[dev.boringcrypto] all: merge master into dev.boringcrypto

Change-Id: I948e086e11e1da571e2be23bb08a7bbd6618dc2f
This commit is contained in:
Dmitri Shuralyov 2020-07-08 23:29:54 -04:00
commit a91ad4250c
544 changed files with 16965 additions and 8695 deletions

20
.gitattributes vendored
View file

@ -1,16 +1,16 @@
# Treat all files in the Go repo as binary, with no git magic updating
# line endings. Windows users contributing to Go will need to use a
# modern version of git and editors capable of LF line endings.
# line endings. This produces predictable results in different environments.
#
# Windows users contributing to Go will need to use a modern version
# of git and editors capable of LF line endings.
#
# Windows .bat files are known to have multiple bugs when run with LF
# endings, and so they are checked in with CRLF endings, with a test
# in test/winbatch.go to catch problems. (See golang.org/issue/37791.)
#
# We'll prevent accidental CRLF line endings from entering the repo
# via the git-review gofmt checks.
# via the git-codereview gofmt checks and tests.
#
# See golang.org/issue/9281
# See golang.org/issue/9281.
* -text
# The only exception is Windows files that must absolutely be CRLF or
# might not work. Batch files are known to have multiple bugs when run
# with LF endings. See golang.org/issue/37791 for more information.
*.bat text eol=crlf

View file

@ -934,7 +934,7 @@ Maya Rashish <maya@netbsd.org>
Mayank Kumar <krmayankk@gmail.com>
MediaMath, Inc
Meir Fischer <meirfischer@gmail.com>
Meng Zhuo <mengzhuo1203@gmail.com>
Meng Zhuo <mengzhuo1203@gmail.com> <mzh@golangcn.org>
Meteor Development Group
Mhd Sulhan <m.shulhan@gmail.com>
Micah Stetson <micah.stetson@gmail.com>
@ -1044,6 +1044,7 @@ Niels Widger <niels.widger@gmail.com>
Nigel Kerr <nigel.kerr@gmail.com>
Nik Nyby <nnyby@columbia.edu>
Nikhil Benesch <nikhil.benesch@gmail.com>
Nikita Gillmann <nikita@n0.is> <ng0@n0.is>
Niklas Schnelle <niklas.schnelle@gmail.com>
Niko Dziemba <niko@dziemba.com>
Nikolay Turpitko <nikolay@turpitko.com>
@ -1142,6 +1143,7 @@ Pietro Gagliardi <pietro10@mac.com>
Piyush Mishra <piyush@codeitout.com>
Platform.sh
Pontus Leitzler <leitzler@gmail.com>
Prasanga Siripala <pj@pjebs.com.au>
Prashant Varanasi <prashant@prashantv.com>
Pravendra Singh <hackpravj@gmail.com>
Preetam Jinka <pj@preet.am>
@ -1396,6 +1398,7 @@ Upthere, Inc.
Uriel Mangado <uriel@berlinblue.org>
Vadim Grek <vadimprog@gmail.com>
Vadim Vygonets <unixdj@gmail.com>
Vee Zhang <veezhang@126.com> <vveezhang@gmail.com>
Vendasta
Veselkov Konstantin <kostozyb@gmail.com>
Victor Vrantchan <vrancean+github@gmail.com>

View file

@ -958,7 +958,7 @@ Irfan Sharif <irfanmahmoudsharif@gmail.com>
Irieda Noboru <irieda@gmail.com>
Isaac Ardis <isaac.ardis@gmail.com>
Isaac Wagner <ibw@isaacwagner.me>
Isfan Azhabil <isfan.azhabil@tokopedia.com>
Isfan Azhabil <isfanazhabil@gmail.com>
Iskander Sharipov <iskander.sharipov@intel.com> <quasilyte@gmail.com>
Issac Trotts <issactrotts@google.com>
Ivan Babrou <ivan@cloudflare.com>
@ -1501,7 +1501,7 @@ Maxwell Krohn <themax@gmail.com>
Maya Rashish <maya@NetBSD.org>
Mayank Kumar <krmayankk@gmail.com>
Meir Fischer <meirfischer@gmail.com>
Meng Zhuo <mengzhuo1203@gmail.com>
Meng Zhuo <mengzhuo1203@gmail.com> <mzh@golangcn.org>
Mhd Sulhan <m.shulhan@gmail.com>
Micah Stetson <micah.stetson@gmail.com>
Michael Anthony Knyszek <mknyszek@google.com>
@ -1654,6 +1654,7 @@ Nigel Kerr <nigel.kerr@gmail.com>
Nigel Tao <nigeltao@golang.org>
Nik Nyby <nnyby@columbia.edu>
Nikhil Benesch <nikhil.benesch@gmail.com>
Nikita Gillmann <nikita@n0.is> <ng0@n0.is>
Nikita Kryuchkov <nkryuchkov10@gmail.com>
Nikita Vanyasin <nikita.vanyasin@gmail.com>
Niklas Schnelle <niklas.schnelle@gmail.com>
@ -1788,6 +1789,7 @@ Pietro Gagliardi <pietro10@mac.com>
Piyush Mishra <piyush@codeitout.com>
Plekhanov Maxim <kishtatix@gmail.com>
Pontus Leitzler <leitzler@gmail.com>
Prasanga Siripala <pj@pjebs.com.au>
Prasanna Swaminathan <prasanna@mediamath.com>
Prashant Agrawal <prashant.a.vjti@gmail.com>
Prashant Varanasi <prashant@prashantv.com>
@ -2194,6 +2196,7 @@ Vadim Grek <vadimprog@gmail.com>
Vadim Vygonets <unixdj@gmail.com>
Val Polouchkine <vpolouch@justin.tv>
Valentin Vidic <vvidic@valentin-vidic.from.hr>
Vee Zhang <veezhang@126.com> <vveezhang@gmail.com>
Vega Garcia Luis Alfonso <vegacom@gmail.com>
Venil Noronha <veniln@vmware.com>
Veselkov Konstantin <kostozyb@gmail.com>

132
api/go1.15.txt Normal file
View file

@ -0,0 +1,132 @@
pkg bufio, var ErrBadReadCount error
pkg crypto, method (Hash) String() string
pkg crypto/ecdsa, func SignASN1(io.Reader, *PrivateKey, []uint8) ([]uint8, error)
pkg crypto/ecdsa, func VerifyASN1(*PublicKey, []uint8, []uint8) bool
pkg crypto/ecdsa, method (*PrivateKey) Equal(crypto.PrivateKey) bool
pkg crypto/ecdsa, method (*PublicKey) Equal(crypto.PublicKey) bool
pkg crypto/ed25519, method (PrivateKey) Equal(crypto.PrivateKey) bool
pkg crypto/ed25519, method (PublicKey) Equal(crypto.PublicKey) bool
pkg crypto/elliptic, func MarshalCompressed(Curve, *big.Int, *big.Int) []uint8
pkg crypto/elliptic, func UnmarshalCompressed(Curve, []uint8) (*big.Int, *big.Int)
pkg crypto/rsa, method (*PrivateKey) Equal(crypto.PrivateKey) bool
pkg crypto/rsa, method (*PublicKey) Equal(crypto.PublicKey) bool
pkg crypto/tls, method (*Dialer) Dial(string, string) (net.Conn, error)
pkg crypto/tls, method (*Dialer) DialContext(context.Context, string, string) (net.Conn, error)
pkg crypto/tls, method (ClientAuthType) String() string
pkg crypto/tls, method (CurveID) String() string
pkg crypto/tls, method (SignatureScheme) String() string
pkg crypto/tls, type Config struct, VerifyConnection func(ConnectionState) error
pkg crypto/tls, type Dialer struct
pkg crypto/tls, type Dialer struct, Config *Config
pkg crypto/tls, type Dialer struct, NetDialer *net.Dialer
pkg crypto/x509, func CreateRevocationList(io.Reader, *RevocationList, *Certificate, crypto.Signer) ([]uint8, error)
pkg crypto/x509, type RevocationList struct
pkg crypto/x509, type RevocationList struct, ExtraExtensions []pkix.Extension
pkg crypto/x509, type RevocationList struct, NextUpdate time.Time
pkg crypto/x509, type RevocationList struct, Number *big.Int
pkg crypto/x509, type RevocationList struct, RevokedCertificates []pkix.RevokedCertificate
pkg crypto/x509, type RevocationList struct, SignatureAlgorithm SignatureAlgorithm
pkg crypto/x509, type RevocationList struct, ThisUpdate time.Time
pkg database/sql, method (*DB) SetConnMaxIdleTime(time.Duration)
pkg database/sql, method (*Row) Err() error
pkg database/sql, type DBStats struct, MaxIdleTimeClosed int64
pkg database/sql/driver, type Validator interface { IsValid }
pkg database/sql/driver, type Validator interface, IsValid() bool
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_APPCONTAINER = 4096
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_APPCONTAINER ideal-int
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 64
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE ideal-int
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY = 128
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY ideal-int
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_GUARD_CF = 16384
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_GUARD_CF ideal-int
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA = 32
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA ideal-int
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NO_BIND = 2048
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NO_BIND ideal-int
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = 512
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NO_ISOLATION ideal-int
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NO_SEH = 1024
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NO_SEH ideal-int
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NX_COMPAT = 256
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NX_COMPAT ideal-int
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 32768
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE ideal-int
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = 8192
pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_WDM_DRIVER ideal-int
pkg debug/pe, const IMAGE_FILE_32BIT_MACHINE = 256
pkg debug/pe, const IMAGE_FILE_32BIT_MACHINE ideal-int
pkg debug/pe, const IMAGE_FILE_AGGRESIVE_WS_TRIM = 16
pkg debug/pe, const IMAGE_FILE_AGGRESIVE_WS_TRIM ideal-int
pkg debug/pe, const IMAGE_FILE_BYTES_REVERSED_HI = 32768
pkg debug/pe, const IMAGE_FILE_BYTES_REVERSED_HI ideal-int
pkg debug/pe, const IMAGE_FILE_BYTES_REVERSED_LO = 128
pkg debug/pe, const IMAGE_FILE_BYTES_REVERSED_LO ideal-int
pkg debug/pe, const IMAGE_FILE_DEBUG_STRIPPED = 512
pkg debug/pe, const IMAGE_FILE_DEBUG_STRIPPED ideal-int
pkg debug/pe, const IMAGE_FILE_DLL = 8192
pkg debug/pe, const IMAGE_FILE_DLL ideal-int
pkg debug/pe, const IMAGE_FILE_EXECUTABLE_IMAGE = 2
pkg debug/pe, const IMAGE_FILE_EXECUTABLE_IMAGE ideal-int
pkg debug/pe, const IMAGE_FILE_LARGE_ADDRESS_AWARE = 32
pkg debug/pe, const IMAGE_FILE_LARGE_ADDRESS_AWARE ideal-int
pkg debug/pe, const IMAGE_FILE_LINE_NUMS_STRIPPED = 4
pkg debug/pe, const IMAGE_FILE_LINE_NUMS_STRIPPED ideal-int
pkg debug/pe, const IMAGE_FILE_LOCAL_SYMS_STRIPPED = 8
pkg debug/pe, const IMAGE_FILE_LOCAL_SYMS_STRIPPED ideal-int
pkg debug/pe, const IMAGE_FILE_NET_RUN_FROM_SWAP = 2048
pkg debug/pe, const IMAGE_FILE_NET_RUN_FROM_SWAP ideal-int
pkg debug/pe, const IMAGE_FILE_RELOCS_STRIPPED = 1
pkg debug/pe, const IMAGE_FILE_RELOCS_STRIPPED ideal-int
pkg debug/pe, const IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = 1024
pkg debug/pe, const IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP ideal-int
pkg debug/pe, const IMAGE_FILE_SYSTEM = 4096
pkg debug/pe, const IMAGE_FILE_SYSTEM ideal-int
pkg debug/pe, const IMAGE_FILE_UP_SYSTEM_ONLY = 16384
pkg debug/pe, const IMAGE_FILE_UP_SYSTEM_ONLY ideal-int
pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_APPLICATION = 10
pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_APPLICATION ideal-int
pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER = 11
pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER ideal-int
pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_ROM = 13
pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_ROM ideal-int
pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER = 12
pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER ideal-int
pkg debug/pe, const IMAGE_SUBSYSTEM_NATIVE = 1
pkg debug/pe, const IMAGE_SUBSYSTEM_NATIVE ideal-int
pkg debug/pe, const IMAGE_SUBSYSTEM_NATIVE_WINDOWS = 8
pkg debug/pe, const IMAGE_SUBSYSTEM_NATIVE_WINDOWS ideal-int
pkg debug/pe, const IMAGE_SUBSYSTEM_OS2_CUI = 5
pkg debug/pe, const IMAGE_SUBSYSTEM_OS2_CUI ideal-int
pkg debug/pe, const IMAGE_SUBSYSTEM_POSIX_CUI = 7
pkg debug/pe, const IMAGE_SUBSYSTEM_POSIX_CUI ideal-int
pkg debug/pe, const IMAGE_SUBSYSTEM_UNKNOWN = 0
pkg debug/pe, const IMAGE_SUBSYSTEM_UNKNOWN ideal-int
pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION = 16
pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION ideal-int
pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_CE_GUI = 9
pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_CE_GUI ideal-int
pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_CUI = 3
pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_CUI ideal-int
pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_GUI = 2
pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_GUI ideal-int
pkg debug/pe, const IMAGE_SUBSYSTEM_XBOX = 14
pkg debug/pe, const IMAGE_SUBSYSTEM_XBOX ideal-int
pkg go/printer, const StdFormat = 16
pkg go/printer, const StdFormat Mode
pkg math/big, method (*Int) FillBytes([]uint8) []uint8
pkg net, method (*Resolver) LookupIP(context.Context, string, string) ([]IP, error)
pkg net/url, method (*URL) EscapedFragment() string
pkg net/url, method (*URL) Redacted() string
pkg net/url, type URL struct, RawFragment string
pkg os, method (*File) ReadFrom(io.Reader) (int64, error)
pkg os, var ErrDeadlineExceeded error
pkg regexp, method (*Regexp) SubexpIndex(string) int
pkg strconv, func FormatComplex(complex128, uint8, int, int) string
pkg strconv, func ParseComplex(string, int) (complex128, error)
pkg sync, method (*Map) LoadAndDelete(interface{}) (interface{}, bool)
pkg testing, method (*B) TempDir() string
pkg testing, method (*T) Deadline() (time.Time, bool)
pkg testing, method (*T) TempDir() string
pkg testing, type TB interface, TempDir() string
pkg time, method (*Ticker) Reset(Duration)

View file

@ -1,3 +0,0 @@
pkg testing, method (*T) Deadline() (time.Time, bool)
pkg time, method (*Ticker) Reset(Duration)
pkg sync, method (*Map) LoadAndDelete(interface{}) (interface{}, bool)

View file

@ -174,7 +174,7 @@ The main Go repository is located at
a Git server hosted by Google.
Authentication on the web server is made through your Google account, but
you also need to configure <code>git</code> on your computer to access it.
Follow this steps:
Follow these steps:
</p>
<ol>
@ -263,6 +263,24 @@ a new issue</a> or by claiming
an <a href="https://golang.org/issues">existing one</a>.
</p>
<h3 id="where">Where to contribute</h3>
<p>
The Go project consists of the main
<a href="https://go.googlesource.com/go">go</a> repository, which contains the
source code for the Go language, as well as many golang.org/x/... repostories.
These contain the various tools and infrastructure that support Go. For
example, <a href="https://go.googlesource.com/pkgsite">golang.org/x/pkgsite</a>
is for <a href="https://pkg.go.dev">pkg.go.dev</a>,
<a href="https://go.googlesource.com/playground">golang.org/x/playground</a>
is for the Go playground, and
<a href="https://go.googlesource.com/tools">golang.org/x/tools</a> contains
a variety of Go tools, including the Go language server,
<a href="https://golang.org/s/gopls">gopls</a>. You can see a
list of all the golang.org/x/... repositories on
<a href="https://go.googlesource.com">go.googlesource.com</a>.
</p>
<h3 id="check_tracker">Check the issue tracker</h3>
<p>
@ -272,6 +290,13 @@ always the first place to go.
Issues are triaged to categorize them and manage the workflow.
</p>
<p>
The majority of the golang.org/x/... repos also use the main Go
issue tracker. However, a few of these repositories manage their issues
separately, so please be sure to check the right tracker for the repository to
which you would like to contribute.
</p>
<p>
Most issues will be marked with one of the following workflow labels:
</p>
@ -285,7 +310,7 @@ Most issues will be marked with one of the following workflow labels:
<b>NeedsDecision</b>: the issue is relatively well understood, but the
Go team hasn't yet decided the best way to address it.
It would be better to wait for a decision before writing code.
If you are interested on working on an issue in this state,
If you are interested in working on an issue in this state,
feel free to "ping" maintainers in the issue's comments
if some time has passed without a decision.
</li>
@ -329,11 +354,16 @@ the code review tool is not the place for high-level discussions.
<p>
When planning work, please note that the Go project follows a <a
href="https://golang.org/wiki/Go-Release-Cycle">six-month development cycle</a>.
The latter half of each cycle is a three-month feature freeze during
which only bug fixes and documentation updates are accepted.
New contributions can be sent during a feature freeze, but they will
not be merged until the freeze is over.
href="https://golang.org/wiki/Go-Release-Cycle">six-month development cycle</a>
for the main Go repository. The latter half of each cycle is a three-month
feature freeze during which only bug fixes and documentation updates are
accepted. New contributions can be sent during a feature freeze, but they will
not be merged until the freeze is over. The freeze applies to the entire main
repository as well as to the code in golang.org/x/... repositories that is
needed to build the binaries included in the release. See the lists of packages
vendored into
<a href="https://github.com/golang/go/blob/master/src/vendor/modules.txt">the standard library</a>
and the <a href="https://github.com/golang/go/blob/master/src/cmd/vendor/modules.txt"><code>go</code> command</a>.
</p>
<p>
@ -408,13 +438,29 @@ This is an overview of the overall process:
<ul>
<li>
<b>Step 1:</b> Clone the Go source code from <code>go.googlesource.com</code>
and make sure it's stable by compiling and testing it once:
<b>Step 1:</b> Clone the source code from <code>go.googlesource.com</code> and
make sure it's stable by compiling and testing it once.
<p>If you're making a change to the
<a href="https://go.googlesource.com/go">main Go repository</a>:</p>
<pre>
$ git clone https://go.googlesource.com/go
$ cd go/src
$ ./all.bash # compile and test
</pre>
<p>
If you're making a change to one of the golang.org/x/... repositories
(<a href="https://go.googlesource.com/tools">golang.org/x/tools</a>,
in this example):
</p>
<pre>
$ git clone https://go.googlesource.com/tools
$ cd tools
$ go test ./... # compile and test
</pre>
</li>
<li>
@ -434,10 +480,18 @@ $ [etc.]
</li>
<li>
<b>Step 3:</b> Test your changes, re-running <code>all.bash</code>.
<b>Step 3:</b> Test your changes, either by running the tests in the package
you edited or by re-running <code>all.bash</code>.
<p>In the main Go repository:</p>
<pre>
$ ./all.bash # recompile and test
</pre>
<p>In a golang.org/x/... repository:</p>
<pre>
$ go test ./... # recompile and test
</pre>
</li>
<li>
@ -465,7 +519,7 @@ The rest of this section describes these steps in more detail.
</p>
<h3 id="checkout_go">Step 1: Clone the Go source code</h3>
<h3 id="checkout_go">Step 1: Clone the source code</h3>
<p>
In addition to a recent Go installation, you need to have a local copy of the source
@ -475,11 +529,19 @@ you want as long as it's outside your <code>GOPATH</code>.
Clone from <code>go.googlesource.com</code> (not GitHub):
</p>
<p>Main Go repository:</p>
<pre>
$ git clone https://go.googlesource.com/go
$ cd go
</pre>
<p>golang.org/x/... repository</p>
(<a href="https://go.googlesource.com/tools">golang.org/x/tools</a> in this example):
<pre>
$ git clone https://go.googlesource.com/tools
$ cd tools
</pre>
<h3 id="make_branch">Step 2: Prepare changes in a new branch</h3>
<p>
@ -543,9 +605,13 @@ into a single one.
<p>
You've <a href="code.html">written and tested your code</a>, but
before sending code out for review, run <i>all the tests for the whole
tree</i> to make sure the changes don't break other packages or programs:
tree</i> to make sure the changes don't break other packages or programs.
</p>
<h4 id="test-gorepo">In the main Go repository</h4>
<p>This can be done by running <code>all.bash</code>:</p>
<pre>
$ cd go/src
$ ./all.bash
@ -574,6 +640,33 @@ See also
the section on how to <a href="#quick_test">test your changes quickly</a>.
</p>
<h4 id="test-xrepo">In the golang.org/x/... repositories</h4>
<p>
Run the tests for the entire repository
(<a href="https://go.googlesource.com/tools">golang.org/x/tools</a>,
in this example):
</p>
<pre>
$ cd tools
$ go test ./...
</pre>
<p>
If you're concerned about the build status,
you can check the <a href="https://build.golang.org">Build Dashboard</a>.
Test failures may also be caught by the TryBots in code review.
</p>
<p>
Some repositories, like
<a href="https://go.googlesource.com/vscode-go">golang.org/x/vscode-go</a> will
have different testing infrastructures, so always check the documentation
for the repository in which you are working. The README file in the root of the
repository will usually have this information.
</p>
<h3 id="mail">Step 4: Send changes for review</h3>
<p>
@ -720,10 +813,10 @@ when the change is applied.
</p>
<p>
If you are sending a change against a subrepository, you must use
If you are sending a change against a golang.org/x/... repository, you must use
the fully-qualified syntax supported by GitHub to make sure the change is
linked to the issue in the main repository, not the subrepository.
All issues are tracked in the main repository's issue tracker.
linked to the issue in the main repository, not the x/ repository.
Most issues are tracked in the main repository's issue tracker.
The correct form is "Fixes golang/go#159".
</p>
@ -1070,25 +1163,6 @@ $ $GODIR/bin/go run run.go
</pre>
</ul>
<h3 id="subrepos">Contributing to subrepositories (golang.org/x/...)</h3>
<p>
If you are contributing a change to a subrepository, obtain the
Go package using <code>go get</code>.
For example, to contribute
to <code>golang.org/x/oauth2</code>, check out the code by running:
</p>
<pre>
$ go get -d golang.org/x/oauth2/...
</pre>
<p>
Then, change your directory to the package's source directory
(<code>$GOPATH/src/golang.org/x/oauth2</code>), and follow the
normal contribution flow.
</p>
<h3 id="cc">Specifying a reviewer / CCing others</h3>
@ -1209,5 +1283,5 @@ $ git codereview mail HEAD
<p>
Make sure to explicitly specify <code>HEAD</code>, which is usually not required when sending
single changes.
single changes. More details can be found in the <a href="https://pkg.go.dev/golang.org/x/review/git-codereview?tab=doc#hdr-Multiple_Commit_Work_Branches">git-codereview documentation</a>.
</p>

View file

@ -20,7 +20,7 @@ editing, navigation, testing, and debugging experience.
<ul>
<li><a href="https://github.com/fatih/vim-go">vim</a>: vim-go plugin provides Go programming language support</li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=lukehoban.Go">Visual Studio Code</a>:
<li><a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode.Go">Visual Studio Code</a>:
Go extension provides support for the Go programming language</li>
<li><a href="https://www.jetbrains.com/go">GoLand</a>: GoLand is distributed either as a standalone IDE
or as a plugin for IntelliJ IDEA Ultimate</li>

View file

@ -2336,10 +2336,9 @@ of the request from the client.
</p>
<p>
For brevity, let's ignore POSTs and assume HTTP requests are always
GETs; that simplification does not affect the way the handlers are
set up. Here's a trivial but complete implementation of a handler to
count the number of times the
page is visited.
GETs; that simplification does not affect the way the handlers are set up.
Here's a trivial implementation of a handler to count the number of times
the page is visited.
</p>
<pre>
// Simple counter server.
@ -2355,6 +2354,11 @@ func (ctr *Counter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
<p>
(Keeping with our theme, note how <code>Fprintf</code> can print to an
<code>http.ResponseWriter</code>.)
In a real server, access to <code>ctr.n</code> would need protection from
concurrent access.
See the <code>sync</code> and <code>atomic</code> packages for suggestions.
</p>
<p>
For reference, here's how to attach such a server to a node on the URL tree.
</p>
<pre>

View file

@ -79,15 +79,13 @@ release.
<h2 id="Source_code">Source code</h2>
<p>
If you cannot use a release, or prefer to build gccgo for
yourself,
the gccgo source code is accessible via Subversion. The
GCC web site
has <a href="https://gcc.gnu.org/svn.html">instructions for getting the
GCC source code</a>. The gccgo source code is included. As a
convenience, a stable version of the Go support is available in
a branch of the main GCC code
repository: <code>svn://gcc.gnu.org/svn/gcc/branches/gccgo</code>.
If you cannot use a release, or prefer to build gccgo for yourself, the
gccgo source code is accessible via Git. The GCC web site has
<a href="https://gcc.gnu.org/git.html">instructions for getting the GCC
source code</a>. The gccgo source code is included. As a convenience, a
stable version of the Go support is available in the
<code>devel/gccgo</code> branch of the main GCC code repository:
<code>git://gcc.gnu.org/git/gcc.git</code>.
This branch is periodically updated with stable Go compiler sources.
</p>
@ -139,13 +137,10 @@ which you have write access):
</p>
<pre>
cvs -z 9 -d :pserver:anoncvs@sourceware.org:/cvs/src login
[password is "anoncvs"]
[The next command will create a directory named src, not binutils]
cvs -z 9 -d :pserver:anoncvs@sourceware.org:/cvs/src co binutils
git clone git://sourceware.org/git/binutils-gdb.git
mkdir binutils-objdir
cd binutils-objdir
../src/configure --enable-gold=default --prefix=/opt/gold
../binutils-gdb/configure --enable-gold=default --prefix=/opt/gold
make
make install
</pre>
@ -176,7 +171,7 @@ described above):
</p>
<pre>
svn checkout svn://gcc.gnu.org/svn/gcc/branches/gccgo gccgo
git clone --branch devel/gccgo git://gcc.gnu.org/git/gcc.git gccgo
mkdir objdir
cd objdir
../gccgo/configure --prefix=/opt/gccgo --enable-languages=c,c++,go --with-ld=/opt/gold/bin/ld

View file

@ -30,7 +30,7 @@ adds <a href="#test">caching of successful test results</a>,
runs <a href="#test-vet">vet automatically during tests</a>,
and
permits <a href="#cgo">passing string values directly between Go and C using cgo</a>.
A new <a href="#cgo">compiler option whitelist</a> may cause
A new <a href="#cgo">hard-coded set of safe compiler options</a> may cause
unexpected <a href="https://golang.org/s/invalidflag"><code>invalid
flag</code></a> errors in code that built successfully with older
releases.
@ -267,7 +267,7 @@ and the <a href="/cmd/test2json/">test2json documentation</a>.
<p>
Options specified by cgo using <code>#cgo CFLAGS</code> and the like
are now checked against a whitelist of permitted options.
are now checked against a list of permitted options.
This closes a security hole in which a downloaded package uses
compiler options like
<span style="white-space: nowrap"><code>-fplugin</code></span>

View file

@ -466,7 +466,15 @@ Do not send CLs removing the interior tags from such phrases.
certificate, and letting the package automatically select the best one.
Note that the performance of this selection is going to be poor unless the
<a href="/pkg/crypto/tls/#Certificate.Leaf"><code>Certificate.Leaf</code></a>
field is set.
field is set. The
<a href="/pkg/crypto/tls/#Config.NameToCertificate"><code>Config.NameToCertificate</code></a>
field, which only supports associating a single certificate with
a give name, is now deprecated and should be left as <code>nil</code>.
Similarly the
<a href="/pkg/crypto/tls/#Config.BuildNameToCertificate"><code>Config.BuildNameToCertificate</code></a>
method, which builds the <code>NameToCertificate</code> field
from the leaf certificates, is now deprecated and should not be
called.
</p>
<p><!-- CL 175517 -->

View file

@ -26,14 +26,20 @@ Do not send CLs removing the interior tags from such phrases.
<h2 id="language">Changes to the language</h2>
<p>
TODO
There are no changes to the language.
</p>
<h2 id="ports">Ports</h2>
<h3 id="darwin">Darwin</h3>
<p> <!-- golang.org/issue/37610, golang.org/issue/37611 -->
<p>
As <a href="go1.14#darwin">announced</a> in the Go 1.14 release
notes, Go 1.15 requires macOS 10.12 Sierra or later; support for
previous versions has been discontinued.
</p>
<p> <!-- golang.org/issue/37610, golang.org/issue/37611, CL 227582, and CL 227198 -->
As <a href="/doc/go1.14#darwin">announced</a> in the Go 1.14 release
notes, Go 1.15 drops support for 32-bit binaries on macOS, iOS,
iPadOS, watchOS, and tvOS (the <code>darwin/386</code>
@ -44,21 +50,52 @@ TODO
<h3 id="windows">Windows</h3>
<p> <!-- CL 214397 and CL 230217 -->
Go 1.15 now generates Windows ASLR executables when -buildmode=pie
cmd/link flag is provided. Go command uses -buildmode=pie by default
on Windows.
Go now generates Windows ASLR executables when <code>-buildmode=pie</code>
cmd/link flag is provided. Go command uses <code>-buildmode=pie</code>
by default on Windows.
</p>
<p>
TODO
<p><!-- CL 227003 -->
The <code>-race</code> and <code>-msan</code> flags now always
enable <code>-d=checkptr</code>, which checks uses
of <code>unsafe.Pointer</code>. This was previously the case on all
OSes except Windows.
</p>
<p><!-- CL 211139 -->
Go-built DLLs no longer cause the process to exit when it receives a
signal (such as Ctrl-C at a terminal).
</p>
<h3 id="android">Android</h3>
<p> <!-- CL 235017, golang.org/issue/38838 -->
When linking binaries for Android, Go 1.15 explicitly selects
the <code>lld</code> linker available in recent versions of the NDK.
The <code>lld</code> linker avoids crashes on some devices, and is
planned to become the default NDK linker in a future NDK version.
</p>
<h3 id="openbsd">OpenBSD</h3>
<p><!-- CL 234381 -->
Go 1.15 adds support for OpenBSD 6.7 on <code>GOARCH=arm</code>
and <code>GOARCH=arm64</code>. Previous versions of Go already
supported OpenBSD 6.7 on <code>GOARCH=386</code>
and <code>GOARCH=amd64</code>.
</p>
<h3 id="riscv">RISC-V</h3>
<p> <!-- CL 226400, CL 226206, and others -->
There has been progress in improving the stability and performance
of the 64-bit RISC-V port on Linux (<code>GOOS=linux</code>,
<code>GOARCH=riscv64</code>). It also now supports asynchronous
preemption.
</p>
<h2 id="tools">Tools</h2>
<p>
TODO
</p>
<h3 id="go-command">Go command</h3>
<p><!-- golang.org/issue/37367 -->
@ -73,10 +110,6 @@ TODO
back to <code>direct</code> in case of errors.
</p>
<p>
TODO
</p>
<h4 id="go-test"><code>go</code> <code>test</code></h4>
<p><!-- https://golang.org/issue/36134 -->
@ -112,27 +145,207 @@ TODO
<a href="https://golang.org/issue/36568">issue #36568</a>). The workaround is
not enabled by default because it is not safe to use when Go versions lower
than 1.14.2 and 1.13.10 are running concurrently with the same module cache.
It can be enabled by explictly setting the environment variable
It can be enabled by explicitly setting the environment variable
<code>GODEBUG=modcacheunzipinplace=1</code>.
</p>
<h3 id="vet">Vet</h3>
<h4 id="vet-string-int">New warning for string(x)</h4>
<p><!-- CL 212919, 232660 -->
The vet tool now warns about conversions of the
form <code>string(x)</code> where <code>x</code> has an integer type
other than <code>rune</code> or <code>byte</code>.
Experience with Go has shown that many conversions of this form
erroneously assume that <code>string(x)</code> evaluates to the
string representation of the integer <code>x</code>.
It actually evaluates to a string containing the UTF-8 encoding of
the value of <code>x</code>.
For example, <code>string(9786)</code> does not evaluate to the
string <code>"9786"</code>; it evaluates to the
string <code>"\xe2\x98\xba"</code>, or <code>"☺"</code>.
</p>
<p>
Code that is using <code>string(x)</code> correctly can be rewritten
to <code>string(rune(x))</code>.
Or, in some cases, calling <code>utf8.EncodeRune(buf, x)</code> with
a suitable byte slice <code>buf</code> may be the right solution.
Other code should most likely use <code>strconv.Itoa</code>
or <code>fmt.Sprint</code>.
</p>
<p>
This new vet check is enabled by default when
using <code>go</code> <code>test</code>.
</p>
<p>
We are considering prohibiting the conversion in a future release of Go.
That is, the language would change to only
permit <code>string(x)</code> for integer <code>x</code> when the
type of <code>x</code> is <code>rune</code> or <code>byte</code>.
Such a language change would not be backward compatible.
We are using this vet check as a first trial step toward changing
the language.
</p>
<h4 id="vet-impossible-interface">New warning for impossible interface conversions</h4>
<p><!-- CL 218779, 232660 -->
The vet tool now warns about type assertions from one interface type
to another interface type when the type assertion will always fail.
This will happen if both interface types implement a method with the
same name but with a different type signature.
</p>
<p>
There is no reason to write a type assertion that always fails, so
any code that triggers this vet check should be rewritten.
</p>
<p>
This new vet check is enabled by default when
using <code>go</code> <code>test</code>.
</p>
<p>
We are considering prohibiting impossible interface type assertions
in a future release of Go.
Such a language change would not be backward compatible.
We are using this vet check as a first trial step toward changing
the language.
</p>
<h2 id="runtime">Runtime</h2>
<p>
TODO
<p><!-- CL 221779 -->
If <code>panic</code> is invoked with a value whose type is derived from any
of: <code>bool</code>, <code>complex64</code>, <code>complex128</code>, <code>float32</code>, <code>float64</code>,
<code>int</code>, <code>int8</code>, <code>int16</code>, <code>int32</code>, <code>int64</code>, <code>string</code>,
<code>uint</code>, <code>uint8</code>, <code>uint16</code>, <code>uint32</code>, <code>uint64</code>, <code>uintptr</code>,
then the value will be printed, instead of just its address.
Previously, this was only true for values of exactly these types.
</p>
<p><!-- CL 228900 -->
On a Unix system, if the <code>kill</code> command
or <code>kill</code> system call is used to send
a <code>SIGSEGV</code>, <code>SIGBUS</code>,
or <code>SIGFPE</code> signal to a Go program, and if the signal
is not being handled via
<a href="/pkg/os/signal/#Notify"><code>os/signal.Notify</code></a>,
the Go program will now reliably crash with a stack trace.
In earlier releases the behavior was unpredictable.
</p>
<p><!-- CL 221182, CL 229998 -->
Allocation of small objects now performs much better at high core
counts, and has lower worst-case latency.
</p>
<p><!-- CL 216401 -->
Converting a small integer value into an interface value no longer
causes allocation.
</p>
<p><!-- CL 216818 -->
Non-blocking receives on closed channels now perform as well as
non-blocking receives on open channels.
</p>
<h2 id="compiler">Compiler</h2>
<p><!-- https://golang.org/cl/229578 -->
<p><!-- CL 229578 -->
Package <code>unsafe</code>'s <a href="/pkg/unsafe/#Pointer">safety
rules</a> allow converting an <code>unsafe.Pointer</code>
into <code>uintptr</code> when calling certain
functions. Previously, in some cases, the compiler allowed multiple
chained conversions (for example, <code>syscall.Syscall(…,
uintptr(uintptr(ptr)), …)</code>). The compiler now requires exactly
one conversion. Code that used multiple conversions should be
updated to satisfy the safety rules.
chained conversions (for example, <code>syscall.Syscall(…,</code>
<code>uintptr(uintptr(ptr)),</code> <code>…)</code>). The compiler
now requires exactly one conversion. Code that used multiple
conversions should be updated to satisfy the safety rules.
</p>
<p><!-- CL 230544, CL 231397 -->
Go 1.15 reduces typical binary sizes by around 5% compared to Go
1.14 by eliminating certain types of GC metadata and more
aggressively eliminating unused type metadata.
</p>
<p><!-- CL 219357, CL 231600 -->
The toolchain now mitigates
<a href="https://www.intel.com/content/www/us/en/support/articles/000055650/processors.html">Intel
CPU erratum SKX102</a> on <code>GOARCH=amd64</code> by aligning
functions to 32 byte boundaries and padding jump instructions. While
this padding increases binary sizes, this is more than made up for
by the binary size improvements mentioned above.
</p>
<p><!-- CL 222661 -->
Go 1.15 adds a <code>-spectre</code> flag to both the
compiler and the assembler, to allow enabling Spectre mitigations.
These should almost never be needed and are provided mainly as a
“defense in depth” mechanism.
See the <a href="https://github.com/golang/go/wiki/Spectre">Spectre wiki page</a> for details.
</p>
<p><!-- CL 228578 -->
The compiler now rejects <code>//go:</code> compiler directives that
have no meaning for the declaration they are applied to with a
"misplaced compiler directive" error. Such misapplied directives
were broken before, but were silently ignored by the compiler.
</p>
<p><!-- CL 206658, CL 205066 -->
The compiler's <code>-json</code> optimization logging now reports
large (>= 128 byte) copies and includes explanations of escape
analysis decisions.
</p>
<h2 id="linker">Linker</h2>
<p>
This release includes substantial improvements to the Go linker,
which reduce linker resource usage (both time and memory) and
improve code robustness/maintainability.
</p>
<p>
For a representative set of large Go programs, linking is 20% faster
and requires 30% less memory on average, for <code>ELF</code>-based
OSes (Linux, FreeBSD, NetBSD, OpenBSD, Dragonfly, and Solaris)
running on <code>amd64</code> architectures, with more modest
improvements for other architecture/OS combinations.
</p>
<p>
The key contributors to better linker performance are a newly
redesigned object file format, and a revamping of internal
phases to increase concurrency (for example, applying relocations to
symbols in parallel). Object files in Go 1.15 are slightly larger
than their 1.14 equivalents.
</p>
<p>
These changes are part of a multi-release project
to <a href="https://golang.org/s/better-linker">modernize the Go
linker</a>, meaning that there will be additional linker
improvements expected in future releases.
</p>
<p><!-- CL 207877 -->
TODO: <a href="https://golang.org/cl/207877">https://golang.org/cl/207877</a>: Revert -buildmode=pie to internal linking.
The linker defaults to internal linking mode for PIE on linux/amd64 and linux/arm64, which does require a C linker.
</p>
<h2 id="objdump">Objdump</h2>
<p><!-- CL 225459 -->
The <a href="/cmd/objdump/">objdump</a> tool now supports
disassembling in GNU assembler syntax with the <code>-gnu</code>
flag.
</p>
<h2 id="library">Core library</h2>
@ -151,25 +364,15 @@ TODO
Either approach increases the size of the program by about 800 KB.
</p>
<p>
TODO
</p>
<h3 id="cgo">Cgo</h3>
<dl id="testing"><dt><a href="/pkg/testing/">testing</a></dt>
<dd>
<p><!-- golang.org/issue/28135 -->
The <code>testing.T</code> type now has a <code>Deadline</code> method
that reports the time at which the test binary will have exceeded its
timeout.
</p>
<p><!-- golang.org/issue/34129 -->
A <code>TestMain</code> function is no longer required to call
<code>os.Exit</code>. If a <code>TestMain</code> function returns,
the test binary will call <code>os.Exit</code> with the value returned
by <code>m.Run</code>.
</p>
</dd>
</dl><!-- testing -->
<p><!-- CL 235817 -->
Go 1.15 will translate the C type <code>EGLConfig</code> to the
Go type <code>uintptr</code>. This change is similar to how Go
1.12 and newer treats <code>EGLDisplay</code>, Darwin's CoreFoundation and
Java's JNI types. See the <a href="/cmd/cgo/#hdr-Special_cases">cgo
documentation</a> for more information.
</p>
<h3 id="minor_library_changes">Minor changes to the library</h3>
@ -179,27 +382,261 @@ TODO
in mind.
</p>
<p>
TODO
</p>
<dl id="bufio"><dt><a href="/pkg/bufio/">bufio</a></dt>
<dd>
<p><!-- CL 225357, CL 225557 -->
When a <a href="/pkg/bufio/#Scanner"><code>Scanner</code></a> is
used with an invalid
<a href="/pkg/io/#Reader"><code>io.Reader</code></a> that
incorrectly returns a negative number from <code>Read</code>,
the <code>Scanner</code> will no longer panic, but will instead
return the new error
<a href="/pkg/bufio/#ErrBadReadCount"><code>ErrBadReadCount</code></a>.
</p>
</dd>
</dl><!-- bufio -->
<dl id="crypto/tls"><dt><a href="/crypto/tls/">crypto/tls</a></dt>
<dl id="crypto"><dt><a href="/pkg/crypto/">crypto</a></dt>
<dd>
<p><!-- CL 231417, CL 225460 -->
The <code>PrivateKey</code> and <code>PublicKey</code> types in the
<a href="/pkg/crypto/rsa/"><code>crypto/rsa</code></a>,
<a href="/pkg/crypto/ecdsa/"><code>crypto/ecdsa</code></a>, and
<a href="/pkg/crypto/ed25519/"><code>crypto/ed25519</code></a> packages
now have an <code>Equal</code> method to compare keys for equivalence
or to make type-safe interfaces for public keys. The method signature
is compatible with
<a href="https://pkg.go.dev/github.com/google/go-cmp/cmp#Equal"><code>go-cmp</code>'s
definition of equality</a>.
</p>
<p><!-- CL 224937 -->
<a href="/pkg/crypto/#Hash"><code>Hash</code></a> now implements
<a href="/pkg/fmt/#Stringer"><code>fmt.Stringer</code></a>.
</p>
</dd>
</dl><!-- crypto -->
<dl id="crypto/ecdsa"><dt><a href="/pkg/crypto/ecdsa/">crypto/ecdsa</a></dt>
<dd>
<p><!-- CL 217940 -->
The new <a href="/pkg/crypto/ecdsa/#SignASN1"><code>SignASN1</code></a>
and <a href="/pkg/crypto/ecdsa/#VerifyASN1"><code>VerifyASN1</code></a>
functions allow generating and verifying ECDSA signatures in the standard
ASN.1 DER encoding.
</p>
</dd>
</dl><!-- crypto/ecdsa -->
<dl id="crypto/elliptic"><dt><a href="/pkg/crypto/elliptic/">crypto/elliptic</a></dt>
<dd>
<p><!-- CL 202819 -->
The new <a href="/pkg/crypto/elliptic/#MarshalCompressed"><code>MarshalCompressed</code></a>
and <a href="/pkg/crypto/elliptic/#UnmarshalCompressed"><code>UnmarshalCompressed</code></a>
functions allow encoding and decoding NIST elliptic curve points in compressed format.
</p>
</dd>
</dl><!-- crypto/elliptic -->
<dl id="crypto/rsa"><dt><a href="/pkg/crypto/rsa/">crypto/rsa</a></dt>
<dd>
<p><!-- CL 226203 -->
<a href="/pkg/crypto/rsa/#VerifyPKCS1v15"><code>VerifyPKCS1v15</code></a>
now rejects invalid short signatures with missing leading zeroes, according to RFC 8017.
</p>
</dd>
</dl><!-- crypto/rsa -->
<dl id="crypto/tls"><dt><a href="/pkg/crypto/tls/">crypto/tls</a></dt>
<dd>
<p><!-- CL 214977 -->
The new
<a href="/pkg/crypto/tls/#Dialer"><code>Dialer</code></a>
type and its
<a href="/pkg/crypto/tls/#Dialer.DialContext"><code>DialContext</code></a>
method permits using a context to both connect and handshake with a TLS server.
method permit using a context to both connect and handshake with a TLS server.
</p>
<p><!-- CL 229122 -->
The new
<a href="/pkg/crypto/tls/#Config.VerifyConnection"><code>VerifyConnection</code></a>
callback on the <a href="/pkg/crypto/tls/#Config"><code>Config</code></a> type
allows custom verification logic for every connection. It has access to the
<a href="/pkg/crypto/tls/#ConnectionState"><code>ConnectionState</code></a>
which includes peer certificates, SCTs, and stapled OCSP responses.
</p>
<p><!-- CL 230679 -->
Auto-generated session ticket keys are now automatically rotated every 24 hours,
with a lifetime of 7 days, to limit their impact on forward secrecy.
</p>
<p><!-- CL 231317 -->
Session ticket lifetimes in TLS 1.2 and earlier, where the session keys
are reused for resumed connections, are now limited to 7 days, also to
limit their impact on forward secrecy.
</p>
<p><!-- CL 231038 -->
The client-side downgrade protection checks specified in RFC 8446 are now
enforced. This has the potential to cause connection errors for clients
encountering middleboxes that behave like unauthorized downgrade attacks.
</p>
<p><!-- CL 208226 -->
<a href="/pkg/crypto/tls/#SignatureScheme"><code>SignatureScheme</code></a>,
<a href="/pkg/crypto/tls/#CurveID"><code>CurveID</code></a>, and
<a href="/pkg/crypto/tls/#ClientAuthType"><code>ClientAuthType</code></a>
now implement <a href="/pkg/fmt/#Stringer"><code>fmt.Stringer</code></a>.
</p>
<p><!-- CL 236737 -->
The <a href="/pkg/crypto/tls/#ConnectionState"><code>ConnectionState</code></a>
fields <code>OCSPResponse</code> and <code>SignedCertificateTimestamps</code>
are now repopulated on client-side resumed connections.
</p>
</dd>
</dl>
</dl><!-- crypto/tls -->
<dl id="crypto/x509"><dt><a href="/pkg/crypto/x509/">crypto/x509</a></dt>
<dd>
<p><!-- CL 231378, CL 231380, CL 231381 -->
If either the name on the certificate or the name being verified (with
<a href="/pkg/crypto/x509/#VerifyOptions.DNSName"><code>VerifyOptions.DNSName</code></a>
or <a href="/pkg/crypto/x509/#Certificate.VerifyHostname"><code>VerifyHostname</code></a>)
are invalid, they will now be compared case-insensitively without further
processing (without honoring wildcards or stripping trailing dots).
Invalid names include those with any characters other than letters,
digits, hyphens and underscores, those with empty labels, and names on
certificates with trailing dots.
</p>
<p><!-- CL 231379 -->
The deprecated, legacy behavior of treating the <code>CommonName</code>
field as a hostname when no Subject Alternative Names are present is now
disabled by default. It can be temporarily re-enabled by adding the value
<code>x509ignoreCN=0</code> to the <code>GODEBUG</code> environment
variable. If the <code>CommonName</code> is an invalid hostname, it's
always ignored.
</p>
<p><!-- CL 217298 -->
The new <a href="/pkg/crypto/x509/#CreateRevocationList"><code>CreateRevocationList</code></a>
function and <a href="/pkg/crypto/x509/#RevocationList"><code>RevocationList</code></a> type
allow creating RFC 5280-compliant X.509 v2 Certificate Revocation Lists.
</p>
<p><!-- CL 227098 -->
<a href="/pkg/crypto/x509/#CreateCertificate"><code>CreateCertificate</code></a>
now automatically generates the <code>SubjectKeyId</code> if the template
is a CA and doesn't explicitly specify one.
</p>
<p><!-- CL 228777 -->
<a href="/pkg/crypto/x509/#CreateCertificate"><code>CreateCertificate</code></a>
now returns an error if the template specifies <code>MaxPathLen</code> but is not a CA.
</p>
<p><!-- CL 205237 -->
On Unix systems other than macOS, the <code>SSL_CERT_DIR</code>
environment variable can now be a colon-separated list.
</p>
<p><!-- CL 227037 -->
On macOS, binaries are now always linked against
<code>Security.framework</code> to extract the system trust roots,
regardless of whether cgo is available. The resulting behavior should be
more consistent with the OS verifier.
</p>
</dd>
</dl><!-- crypto/x509 -->
<dl id="crypto/x509/pkix"><dt><a href="/pkg/crypto/x509/pkix/">crypto/x509/pkix</a></dt>
<dd>
<p><!-- CL 229864 -->
<a href="/pkg/crypto/x509/pkix/#Name.String"><code>Name.String</code></a>
now prints non-standard attributes from
<a href="/pkg/crypto/x509/pkix/#Name.Names"><code>Names</code></a> if
<a href="/pkg/crypto/x509/pkix/#Name.ExtraNames"><code>ExtraNames</code></a> is empty.
</p>
</dd>
</dl><!-- crypto/x509/pkix -->
<dl id="database/sql"><dt><a href="/pkg/database/sql/">database/sql</a></dt>
<dd>
<p><!-- CL 145758 -->
The new <a href="/pkg/database/sql/#DB.SetConnMaxIdleTime"><code>DB.SetConnMaxIdleTime</code></a>
method allows removing a connection from the connection pool after
it has been idle for a period of time, without regard to the total
lifespan of the connection. The <a href="/pkg/database/sql/#DBStats.MaxIdleTimeClosed"><code>DBStats.MaxIdleTimeClosed</code></a>
field shows the total number of connections closed due to
<code>DB.SetConnMaxIdleTime</code>.
</p>
<p><!-- CL 214317 -->
The new <a href="/pkg/database/sql/#Row.Err"><code>Row.Err</code></a> getter
allows checking for query errors without calling
<code>Row.Scan</code>.
</p>
</dd>
</dl><!-- database/sql -->
<dl id="database/sql/driver"><dt><a href="/pkg/database/sql/driver/">database/sql/driver</a></dt>
<dd>
<p><!-- CL 174122 -->
The new <a href="/pkg/database/sql/driver/#Validator"><code>Validator</code></a>
interface may be implemented by <code>Conn</code> to allow drivers
to signal if a connection is valid or if it should be discarded.
</p>
</dd>
</dl><!-- database/sql/driver -->
<dl id="debug/pe"><dt><a href="/pkg/debug/pe/">debug/pe</a></dt>
<dd>
<p><!-- CL 222637 -->
The package now defines the
<code>IMAGE_FILE</code>, <code>IMAGE_SUBSYSTEM</code>,
and <code>IMAGE_DLLCHARACTERISTICS</code> constants used by the
PE file format.
</p>
</dd>
</dl><!-- debug/pe -->
<dl id="encoding/asn1"><dt><a href="/pkg/encoding/asn1/">encoding/asn1</a></dt>
<dd>
<p><!-- CL 226984 -->
<a href="/pkg/encoding/asn1/#Marshal"><code>Marshal</code></a> now sorts the components
of SET OF according to X.690 DER.
</p>
<p><!-- CL 227320 -->
<a href="/pkg/encoding/asn1/#Unmarshal"><code>Unmarshal</code></a> now rejects tags and
Object Identifiers which are not minimally encoded according to X.690 DER.
</p>
</dd>
</dl><!-- encoding/asn1 -->
<dl id="encoding/json"><dt><a href="/pkg/encoding/json/">encoding/json</a></dt>
<dd>
<p><!-- CL 191783 -->
Decoding a JSON array into a slice no longer reuses any existing slice elements,
following the rules that the package documentation already stated.
</p>
<p><!-- CL 199837 -->
The package now has an internal limit to the maximum depth of
nesting when decoding. This reduces the possibility that a
deeply nested input could use large quantities of stack memory,
or even cause a "goroutine stack exceeds limit" panic.
</p>
</dd>
</dl><!-- encoding/json -->
<dl id="flag"><dt><a href="/pkg/flag/">flag</a></dt>
<dd>
<p><!-- CL 221427 -->
When the flag package sees <code>-h</code> or <code>-help</code>, and
those flags are not defined, the flag package prints a usage message.
those flags are not defined, it now prints a usage message.
If the <a href="/pkg/flag/#FlagSet"><code>FlagSet</code></a> was created with
<a href="/pkg/flag/#ExitOnError"><code>ExitOnError</code></a>,
<a href="/pkg/flag/#FlagSet.Parse"><code>FlagSet.Parse</code></a> would then
@ -210,6 +647,46 @@ TODO
</dd>
</dl>
<dl id="fmt"><dt><a href="/pkg/fmt/">fmt</a></dt>
<dd>
<p><!-- CL 215001 -->
The printing verbs <code>%#g</code> and <code>%#G</code> now preserve
trailing zeros for floating-point values.
</p>
</dd>
</dl><!-- fmt -->
<dl id="go/printer"><dt><a href="/pkg/go/printer/">go/printer</a></dt>
<dd>
<p><!-- CL 231461 -->
The new <a href="/pkg/go/printer/#Mode"><code>Mode</code></a>
value <a href="/pkg/go/printer/#StdFormat"><code>StdFormat</code></a>
directs the printer to apply standard formatting changes while
printing the output.
</dd>
</dl><!-- go/printer -->
<dl id="io/ioutil"><dt><a href="/pkg/io/ioutil/">io/ioutil</a></dt>
<dd>
<p><!-- CL 212597 -->
<a href="/pkg/io/ioutil/#TempDir"><code>TempDir</code></a> and
<a href="/pkg/io/ioutil/#TempFile"><code>TempFile</code></a>
now reject patterns that contain path separators.
That is, calls such as <code>ioutil.TempFile("/tmp",</code> <code>"../base*")</code> will no longer succeed.
This prevents unintended directory traversal.
</p>
</dd>
</dl><!-- io/ioutil -->
<dl id="math/big"><dt><a href="/pkg/math/big/">math/big</a></dt>
<dd>
<p><!-- CL 230397 -->
The new <a href="/pkg/math/big/#Int.FillBytes"><code>Int.FillBytes</code></a>
method allows serializing to fixed-size pre-allocated byte slices.
</p>
</dd>
</dl><!-- math/big -->
<dl id="net"><dt><a href="/pkg/net/">net</a></dt>
<dd>
<p><!-- CL 228645 -->
@ -218,7 +695,7 @@ TODO
<code>Conn.SetReadDeadline</code>,
or <code>Conn.SetWriteDeadline</code> methods, it will now
return an error that is or wraps
<a href="/pkg/os#ErrDeadlineExceeded"><code>os.ErrDeadlineExceeded</code></a>.
<a href="/pkg/os/#ErrDeadlineExceeded"><code>os.ErrDeadlineExceeded</code></a>.
This may be used to reliably detect whether an error is due to
an exceeded deadline.
Earlier releases recommended calling the <code>Timeout</code>
@ -234,6 +711,16 @@ TODO
</dd>
</dl>
<dl id="net/http"><dt><a href="/pkg/net/http/">net/http</a></dt>
<dd>
<p><!-- CL 231418, CL 231419 -->
Parsing is now stricter as a hardening measure against request smuggling attacks:
non-ASCII white space is no longer trimmed like SP and HTAB, and support for the
"<code>identity</code>" <code>Transfer-Encoding</code> was dropped.
</p>
</dd>
</dl><!-- net/http -->
<dl id="net/http/httputil"><dt><a href="/pkg/net/http/httputil/">net/http/httputil</a></dt>
<dd>
<p><!-- CL 230937 -->
@ -242,6 +729,12 @@ TODO
header when the incoming <code>Request.Header</code> map entry
for that field is <code>nil</code>.
</p>
<p><!-- CL 224897 -->
When a Switching Protocol (like WebSocket) request handled by
<a href="/pkg/net/http/httputil/#ReverseProxy"><code>ReverseProxy</code></a>
is canceled, the backend connection is now correctly closed.
</p>
</dd>
</dl>
@ -281,7 +774,7 @@ TODO
<a href="/pkg/os/#File.SetReadDeadline"><code>File.SetReadDeadline</code></a>,
or <a href="/pkg/os/#File.SetWriteDeadline"><code>File.SetWriteDeadline</code></a>
methods, it will now return an error that is or wraps
<a href="/pkg/os#ErrDeadlineExceeded"><code>os.ErrDeadlineExceeded</code></a>.
<a href="/pkg/os/#ErrDeadlineExceeded"><code>os.ErrDeadlineExceeded</code></a>.
This may be used to reliably detect whether an error is due to
an exceeded deadline.
Earlier releases recommended calling the <code>Timeout</code>
@ -289,13 +782,48 @@ TODO
which <code>Timeout</code> returns <code>true</code> although a
deadline has not been exceeded.
</p>
<p><!-- CL 232862 -->
Packages <code>os</code> and <code>net</code> now automatically
retry system calls that fail with <code>EINTR</code>. Previously
this led to spurious failures, which became more common in Go
1.14 with the addition of asynchronous preemption. Now this is
handled transparently.
</p>
<p><!-- CL 229101 -->
The <a href="/pkg/os/#File"><code>os.File</code></a> type now
supports a <a href="/pkg/os/#File.ReadFrom"><code>ReadFrom</code></a>
method. This permits the use of the <code>copy_file_range</code>
system call on some systems when using
<a href="/pkg/io/#Copy"><code>io.Copy</code></a> to copy data
from one <code>os.File</code> to another. A consequence is that
<a href="/pkg/io/#CopyBuffer"><code>io.CopyBuffer</code></a>
will not always use the provided buffer when copying to a
<code>os.File</code>. If a program wants to force the use of
the provided buffer, it can be done by writing
<code>io.CopyBuffer(struct{ io.Writer }{dst}, src, buf)</code>.
</p>
</dd>
</dl>
<dl id="plugin"><dt><a href="/pkg/plugin/">plugin</a></dt>
<dd>
<p><!-- CL 182959 -->
DWARF generation is now supported (and enabled by default) for <code>-buildmode=plugin</code> on macOS.
</p>
</dd>
<dd>
<p><!-- CL 191617 -->
Building with <code>-buildmode=plugin</code> is now supported on <code>freebsd/amd64</code>.
</p>
</dd>
</dl>
<dl id="reflect"><dt><a href="/pkg/reflect/">reflect</a></dt>
<dd>
<p><!-- CL 228902 -->
Package reflect now disallows accessing methods of all
Package <code>reflect</code> now disallows accessing methods of all
non-exported fields, whereas previously it allowed accessing
those of non-exported, embedded fields. Code that relies on the
previous behavior should be updated to instead access the
@ -304,30 +832,29 @@ TODO
</dd>
</dl>
<dl id="regexp"><dt><a href="/pkg/regexp/">regexp</a></dt>
<dd>
<p><!-- CL 187919 -->
The new <a href="/pkg/regexp/#Regexp.SubexpIndex"><code>Regexp.SubexpIndex</code></a>
method returns the index of the first subexpression with the given name
within the regular expression.
</p>
</dd>
</dl><!-- regexp -->
<dl id="pkg-runtime"><dt><a href="/pkg/runtime/">runtime</a></dt>
<dd>
<p><!-- CL 221779 -->
If <code>panic</code> is invoked with a value whose type is derived from any
of: <code>bool</code>, <code>complex64</code>, <code>complex128</code>, <code>float32</code>, <code>float64</code>,
<code>int</code>, <code>int8</code>, <code>int16</code>, <code>int32</code>, <code>int64</code>, <code>string</code>,
<code>uint</code>, <code>uint8</code>, <code>uint16</code>, <code>uint32</code>, <code>uint64</code>, <code>uintptr</code>,
then the value will be printed, instead of just its address.
</p>
<p><!-- CL -->
On a Unix system, if the <code>kill</code> command
or <code>kill</code> system call is used to send
a <code>SIGSEGV</code>, <code>SIGBUS</code>,
or <code>SIGFPE</code> signal to a Go program, and if the signal
is not being handled via
<a href="/pkg/os/signal/#Notify"><code>os/signal.Notify</code></a>,
the Go program will now reliably crash with a stack trace.
In earlier releases the behavior was unpredictable.
<p><!-- CL 216557 -->
Several functions, including
<a href="/pkg/runtime/#ReadMemStats"><code>ReadMemStats</code></a>
and
<a href="/pkg/runtime/#GoroutineProfile"><code>GoroutineProfile</code></a>,
no longer block if a garbage collection is in progress.
</p>
</dd>
</dl>
<dl id="pkg-runtime-pprof"><dt><a href="/pkg/runtime/pprof">runtime/pprof</a></dt>
<dl id="pkg-runtime-pprof"><dt><a href="/pkg/runtime/pprof/">runtime/pprof</a></dt>
<dd>
<p><!-- CL 189318 -->
The goroutine profile includes the profile labels associated with each goroutine
@ -337,6 +864,20 @@ TODO
</dd>
</dl>
<dl id="strconv"><dt><a href="/pkg/strconv/">strconv</a></dt>
<dd>
<p><!-- CL 216617 -->
<a href="/pkg/strconv/#FormatComplex"><code>FormatComplex</code></a> and <a href="/pkg/strconv/#ParseComplex"><code>ParseComplex</code></a> are added for working with complex numbers.
</p>
<p>
<a href="/pkg/strconv/#FormatComplex"><code>FormatComplex</code></a> converts a complex number into a string of the form (a+bi), where a and b are the real and imaginary parts.
</p>
<p>
<a href="/pkg/strconv/#ParseComplex"><code>ParseComplex</code></a> converts a string into a complex number of a specified precision. <code>ParseComplex</code> accepts complex numbers in the format <code>N+Ni</code>.
</p>
</dd>
</dl><!-- strconv -->
<dl id="sync"><dt><a href="/pkg/sync/">sync</a></dt>
<dd>
<p><!-- CL 205899, golang.org/issue/33762 -->
@ -370,18 +911,42 @@ TODO
Some programs that set <code>Setctty</code> will need to change
the value of <code>Ctty</code> to use a child descriptor number.
</p>
<p><!-- CL 220578 -->
It is <a href="/pkg/syscall/#Proc.Call">now possible</a> to call
system calls that return floating point values
on <code>windows/amd64</code>.
</p>
</dd>
</dl>
<dl id="testing"><dt><a href="/pkg/testing/">testing</a></dt>
<dd>
<p><!-- golang.org/issue/28135 -->
The <code>testing.T</code> type now has a
<a href="/pkg/testing/#T.Deadline"><code>Deadline</code></a> method
that reports the time at which the test binary will have exceeded its
timeout.
</p>
<p><!-- golang.org/issue/34129 -->
A <code>TestMain</code> function is no longer required to call
<code>os.Exit</code>. If a <code>TestMain</code> function returns,
the test binary will call <code>os.Exit</code> with the value returned
by <code>m.Run</code>.
</p>
<p><!-- CL 226877, golang.org/issue/35998 -->
The new methods
<a href="/pkg/testing/#T.TempDir"><code>T.TempDir</code></a> and
<a href="/pkg/testing/#B.TempDir"><code>B.TempDir</code></a> and
<a href="/pkg/testing/#B.TempDir"><code>B.TempDir</code></a>
return temporary directories that are automatically cleaned up
at the end of the test.
</p>
<p><!-- CL 229085 -->
TODO: <a href="https://golang.org/cl/229085">https://golang.org/cl/229085</a>: reformat test chatty output
</p>
</dd>
</dl><!-- testing -->
@ -392,5 +957,9 @@ TODO
<a href="/pkg/time/#Ticker.Reset"><code>Ticker.Reset</code></a>
supports changing the duration of a ticker.
</p>
<p><!-- CL 227878 -->
When returning an error, <a href="/pkg/time/#ParseDuration"><code>ParseDuration</code></a> now quotes the original value.
</p>
</dd>
</dl><!-- time -->

View file

@ -515,7 +515,7 @@ when used well, can result in clean error-handling code.
See the <a href="/doc/articles/defer_panic_recover.html">Defer, Panic, and Recover</a> article for details.
Also, the <a href="https://blog.golang.org/errors-are-values">Errors are values</a> blog post
describes one approach to handling errors cleanly in Go by demonstrating that,
since errors are just values, the full power of Go can deployed in error handling.
since errors are just values, the full power of Go can be deployed in error handling.
</p>
<h3 id="assertions">

View file

@ -8,7 +8,7 @@
<h2 id="help">Get help</h2>
<img class="gopher" src="/doc/gopher/help.png"/>
<img class="gopher" src="/doc/gopher/help.png" alt=""/>
{{if not $.GoogleCN}}
<h3 id="mailinglist"><a href="https://groups.google.com/group/golang-nuts">Go Nuts Mailing List</a></h3>

View file

@ -33,7 +33,7 @@ compiler using the GCC back end, see
</p>
<p>
The Go compilers support twelve instruction sets:
The Go compilers support the following instruction sets:
<dl>
<dt>
@ -48,24 +48,30 @@ The Go compilers support twelve instruction sets:
<dd>
The <code>ARM</code> instruction set, 64-bit (<code>AArch64</code>) and 32-bit.
</dd>
<dt>
<code>mips64</code>, <code>mips64le</code>, <code>mips</code>, <code>mipsle</code>
</dt>
<dd>
The <code>MIPS</code> instruction set, big- and little-endian, 64- and 32-bit.
</dd>
<dt>
<code>ppc64</code>, <code>ppc64le</code>
</dt>
<dd>
The 64-bit PowerPC instruction set, big- and little-endian.
</dd>
<dt>
<code>riscv64</code>
</dt>
<dd>
The 64-bit RISC-V instruction set.
</dd>
<dt>
<code>s390x</code>
</dt>
<dd>
The IBM z/Architecture.
</dd>
<dt>
<code>mips64</code>, <code>mips64le</code>, <code>mips</code>, <code>mipsle</code>
</dt>
<dd>
The <code>MIPS</code> instruction set, big- and little-endian, 64- and 32-bit.
</dd>
<dt>
<code>wasm</code>
</dt>
@ -501,7 +507,7 @@ These default to the values of <code>$GOHOSTOS</code> and
<p>
Choices for <code>$GOOS</code> are
<code>android</code>, <code>darwin</code> (macOS 10.11 and above and iOS),
<code>android</code>, <code>darwin</code> (macOS/iOS),
<code>dragonfly</code>, <code>freebsd</code>, <code>illumos</code>, <code>js</code>,
<code>linux</code>, <code>netbsd</code>, <code>openbsd</code>,
<code>plan9</code>, <code>solaris</code> and <code>windows</code>.

View file

@ -2200,3 +2200,7 @@ func test32579(t *testing.T) {
// issue 38649
var issue38649 C.netbsd_gid = 42
// issue 39877
var issue39877 *C.void = nil

View file

@ -5,3 +5,4 @@
// This is the relevant part of EGL/egl.h.
typedef void *EGLDisplay;
typedef void *EGLConfig;

View file

@ -13,5 +13,9 @@ import (
)
func Test27054(t *testing.T) {
var _ C.EGLDisplay = 0 // Note: 0, not nil. That makes sure we use uintptr for this type.
var (
// Note: 0, not nil. That makes sure we use uintptr for these types.
_ C.EGLDisplay = 0
_ C.EGLConfig = 0
)
}

View file

@ -0,0 +1,12 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// +build ignore
package main
// enum { ENUMVAL = 0x1 };
import "C"
const ENUMVAL = C.ENUMVAL

View file

@ -24,6 +24,7 @@ var filePrefixes = []string{
"issue37479",
"issue37621",
"issue38649",
"issue39534",
}
func TestGoDefs(t *testing.T) {

View file

@ -32,7 +32,7 @@ func TestMain(m *testing.M) {
}
func testMain(m *testing.M) int {
// Copy testdata into GOPATH/src/testarchive, along with a go.mod file
// Copy testdata into GOPATH/src/testplugin, along with a go.mod file
// declaring the same path.
GOPATH, err := ioutil.TempDir("", "plugin_test")

View file

@ -38,7 +38,15 @@ var testWork = flag.Bool("testwork", false, "if true, log and do not delete the
// run runs a command and calls t.Errorf if it fails.
func run(t *testing.T, msg string, args ...string) {
runWithEnv(t, msg, nil, args...)
}
// runWithEnv runs a command under the given environment and calls t.Errorf if it fails.
func runWithEnv(t *testing.T, msg string, env []string, args ...string) {
c := exec.Command(args[0], args[1:]...)
if len(env) != 0 {
c.Env = append(os.Environ(), env...)
}
if output, err := c.CombinedOutput(); err != nil {
t.Errorf("executing %s (%s) failed %s:\n%s", strings.Join(args, " "), msg, err, output)
}
@ -1028,3 +1036,17 @@ func TestGeneratedHash(t *testing.T) {
goCmd(nil, "install", "-buildmode=shared", "-linkshared", "./issue30768/issue30768lib")
goCmd(nil, "test", "-linkshared", "./issue30768")
}
// Test that packages can be added not in dependency order (here a depends on b, and a adds
// before b). This could happen with e.g. go build -buildmode=shared std. See issue 39777.
func TestPackageOrder(t *testing.T) {
goCmd(t, "install", "-buildmode=shared", "-linkshared", "./issue39777/a", "./issue39777/b")
}
// Test that GC data are generated correctly by the linker when it needs a type defined in
// a shared library. See issue 39927.
func TestGCData(t *testing.T) {
goCmd(t, "install", "-buildmode=shared", "-linkshared", "./gcdata/p")
goCmd(t, "build", "-linkshared", "./gcdata/main")
runWithEnv(t, "running gcdata/main", []string{"GODEBUG=clobberfree=1"}, "./main")
}

View file

@ -0,0 +1,37 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Test that GC data is generated correctly for global
// variables with types defined in a shared library.
// See issue 39927.
// This test run under GODEBUG=clobberfree=1. The check
// *x[i] == 12345 depends on this debug mode to clobber
// the value if the object is freed prematurely.
package main
import (
"fmt"
"runtime"
"testshared/gcdata/p"
)
var x p.T
func main() {
for i := range x {
x[i] = new(int)
*x[i] = 12345
}
runtime.GC()
runtime.GC()
runtime.GC()
for i := range x {
if *x[i] != 12345 {
fmt.Printf("x[%d] == %d, want 12345\n", i, *x[i])
panic("FAIL")
}
}
}

View file

@ -0,0 +1,7 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package p
type T [10]*int

View file

@ -0,0 +1,9 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package a
import "testshared/issue39777/b"
func F() { b.F() }

View file

@ -0,0 +1,7 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package b
func F() {}

View file

@ -175,37 +175,19 @@
const storeValue = (addr, v) => {
const nanHead = 0x7FF80000;
if (typeof v === "number") {
if (typeof v === "number" && v !== 0) {
if (isNaN(v)) {
this.mem.setUint32(addr + 4, nanHead, true);
this.mem.setUint32(addr, 0, true);
return;
}
if (v === 0) {
this.mem.setUint32(addr + 4, nanHead, true);
this.mem.setUint32(addr, 1, true);
return;
}
this.mem.setFloat64(addr, v, true);
return;
}
switch (v) {
case undefined:
this.mem.setFloat64(addr, 0, true);
return;
case null:
this.mem.setUint32(addr + 4, nanHead, true);
this.mem.setUint32(addr, 2, true);
return;
case true:
this.mem.setUint32(addr + 4, nanHead, true);
this.mem.setUint32(addr, 3, true);
return;
case false:
this.mem.setUint32(addr + 4, nanHead, true);
this.mem.setUint32(addr, 4, true);
return;
if (v === undefined) {
this.mem.setFloat64(addr, 0, true);
return;
}
let id = this._ids.get(v);
@ -219,8 +201,13 @@
this._ids.set(v, id);
}
this._goRefCounts[id]++;
let typeFlag = 1;
let typeFlag = 0;
switch (typeof v) {
case "object":
if (v !== null) {
typeFlag = 1;
}
break;
case "string":
typeFlag = 2;
break;
@ -493,10 +480,17 @@
global,
this,
];
this._goRefCounts = []; // number of references that Go has to a JS value, indexed by reference id
this._ids = new Map(); // mapping from JS values to reference ids
this._idPool = []; // unused ids that have been garbage collected
this.exited = false; // whether the Go program has exited
this._goRefCounts = new Array(this._values.length).fill(Infinity); // number of references that Go has to a JS value, indexed by reference id
this._ids = new Map([ // mapping from JS values to reference ids
[0, 1],
[null, 2],
[true, 3],
[false, 4],
[global, 5],
[this, 6],
]);
this._idPool = []; // unused ids that have been garbage collected
this.exited = false; // whether the Go program has exited
// Pass command line arguments and environment variables to WebAssembly by writing them to the linear memory.
let offset = 4096;

View file

@ -1,27 +1,27 @@
:: 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.
@echo off
setlocal
if exist make.bat goto ok
echo all.bat must be run from go\src
:: cannot exit: would kill parent command interpreter
goto end
:ok
set OLDPATH=%PATH%
call make.bat --no-banner --no-local
if %GOBUILDFAIL%==1 goto end
call run.bat --no-rebuild --no-local
if %GOBUILDFAIL%==1 goto end
:: we must restore %PATH% before running "dist banner" so that the latter
:: can get the original %PATH% and give suggestion to add %GOROOT%/bin
:: to %PATH% if necessary.
set PATH=%OLDPATH%
"%GOTOOLDIR%/dist" banner
:end
if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL%
:: 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.
@echo off
setlocal
if exist make.bat goto ok
echo all.bat must be run from go\src
:: cannot exit: would kill parent command interpreter
goto end
:ok
set OLDPATH=%PATH%
call make.bat --no-banner --no-local
if %GOBUILDFAIL%==1 goto end
call run.bat --no-rebuild --no-local
if %GOBUILDFAIL%==1 goto end
:: we must restore %PATH% before running "dist banner" so that the latter
:: can get the original %PATH% and give suggestion to add %GOROOT%/bin
:: to %PATH% if necessary.
set PATH=%OLDPATH%
"%GOTOOLDIR%/dist" banner
:end
if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL%

View file

@ -558,8 +558,8 @@ func (r *negativeEOFReader) Read(p []byte) (int, error) {
return -1, io.EOF
}
// Test that the scanner doesn't panic on a reader that returns a
// negative count of bytes read (issue 38053).
// Test that the scanner doesn't panic and returns ErrBadReadCount
// on a reader that returns a negative count of bytes read (issue 38053).
func TestNegativeEOFReader(t *testing.T) {
r := negativeEOFReader(10)
scanner := NewScanner(&r)
@ -571,8 +571,8 @@ func TestNegativeEOFReader(t *testing.T) {
break
}
}
if scanner.Err() == nil {
t.Error("scanner.Err returned nil, expected an error")
if got, want := scanner.Err(), ErrBadReadCount; got != want {
t.Errorf("scanner.Err: got %v, want %v", got, want)
}
}
@ -584,11 +584,13 @@ func (largeReader) Read(p []byte) (int, error) {
return len(p) + 1, nil
}
// Test that the scanner doesn't panic and returns ErrBadReadCount
// on a reader that returns an impossibly large count of bytes read (issue 38053).
func TestLargeReader(t *testing.T) {
scanner := NewScanner(largeReader{})
for scanner.Scan() {
}
if scanner.Err() == nil {
t.Error("scanner.Err returned nil, expected an error")
if got, want := scanner.Err(), ErrBadReadCount; got != want {
t.Errorf("scanner.Err: got %v, want %v", got, want)
}
}

View file

@ -1,32 +1,32 @@
:: 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.
@echo off
setlocal
set GOBUILDFAIL=0
go tool dist env -w -p >env.bat
if errorlevel 1 goto fail
call env.bat
del env.bat
echo.
if exist %GOTOOLDIR%\dist.exe goto distok
echo cannot find %GOTOOLDIR%\dist; nothing to clean
goto fail
:distok
"%GOBIN%\go" clean -i std
"%GOBIN%\go" tool dist clean
"%GOBIN%\go" clean -i cmd
goto end
:fail
set GOBUILDFAIL=1
:end
if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL%
:: 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.
@echo off
setlocal
set GOBUILDFAIL=0
go tool dist env -w -p >env.bat
if errorlevel 1 goto fail
call env.bat
del env.bat
echo.
if exist %GOTOOLDIR%\dist.exe goto distok
echo cannot find %GOTOOLDIR%\dist; nothing to clean
goto fail
:distok
"%GOBIN%\go" clean -i std
"%GOBIN%\go" tool dist clean
"%GOBIN%\go" clean -i cmd
goto end
:fail
set GOBUILDFAIL=1
:end
if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL%

View file

@ -73,19 +73,29 @@ func testAddr2Line(t *testing.T, exepath, addr string) {
if err != nil {
t.Fatalf("Stat failed: %v", err)
}
// Debug paths are stored slash-separated, so convert to system-native.
srcPath = filepath.FromSlash(srcPath)
fi2, err := os.Stat(srcPath)
if gorootFinal := os.Getenv("GOROOT_FINAL"); gorootFinal != "" && strings.HasPrefix(srcPath, gorootFinal) {
if os.IsNotExist(err) || (err == nil && !os.SameFile(fi1, fi2)) {
// srcPath has had GOROOT_FINAL substituted for GOROOT, and it doesn't
// match the actual file. GOROOT probably hasn't been moved to its final
// location yet, so try the original location instead.
fi2, err = os.Stat(runtime.GOROOT() + strings.TrimPrefix(srcPath, gorootFinal))
}
}
if err != nil {
t.Fatalf("Stat failed: %v", err)
}
if !os.SameFile(fi1, fi2) {
t.Fatalf("addr2line_test.go and %s are not same file", srcPath)
}
if srcLineNo != "89" {
t.Fatalf("line number = %v; want 89", srcLineNo)
if srcLineNo != "99" {
t.Fatalf("line number = %v; want 99", srcLineNo)
}
}
// This is line 88. The test depends on that.
// This is line 98. The test depends on that.
func TestAddr2Line(t *testing.T) {
testenv.MustHaveGoBuild(t)

View file

@ -33,14 +33,17 @@ Flags:
Dump instructions as they are parsed.
-dynlink
Support references to Go symbols defined in other shared libraries.
-gensymabis
Write symbol ABI information to output file. Don't assemble.
-o file
Write output to file. The default is foo.o for /a/b/c/foo.s.
-shared
Generate code that can be linked into a shared library.
-spectre list
Enable spectre mitigations in list (all, ret).
-trimpath prefix
Remove prefix from recorded source file paths.
-gensymabis
Write symbol ABI information to output file. Don't assemble.
Input language:
The assembler uses mostly the same syntax for all architectures,

View file

@ -274,6 +274,9 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
ADDW $0x60060, R2 // ADDW $393312, R2 // 4280011142804111
CMPW $0x60060, R2 // CMPW $393312, R2 // 1b0c8052db00a0725f001b6b
// TODO: this could have better encoding
ANDW $-1, R10 // 1b0080124a011b0a
AND $8, R0, RSP // 1f007d92
ORR $8, R0, RSP // 1f007db2
EOR $8, R0, RSP // 1f007dd2

View file

@ -420,6 +420,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
UXTBW R2, R6 // 461c0053
UXTHW R7, R20 // f43c0053
VCNT V0.B8, V0.B8 // 0058200e
VCNT V0.B16, V0.B16 // 0058204e
WFE // 5f2003d5
WFI // 7f2003d5
YIELD // 3f2003d5

View file

@ -413,7 +413,7 @@ type in Go are instead represented by a uintptr. Those include:
jobjectArray
jweak
3. The EGLDisplay type from the EGL API.
3. The EGLDisplay and EGLConfig types from the EGL API.
These types are uintptr on the Go side because they would otherwise
confuse the Go garbage collector; they are sometimes not really
@ -429,11 +429,16 @@ from Go 1.9 and earlier, use the cftype or jni rewrites in the Go fix tool:
It will replace nil with 0 in the appropriate places.
The EGLDisplay case were introduced in Go 1.12. Use the egl rewrite
The EGLDisplay case was introduced in Go 1.12. Use the egl rewrite
to auto-update code from Go 1.11 and earlier:
go tool fix -r egl <pkg>
The EGLConfig case was introduced in Go 1.15. Use the eglconf rewrite
to auto-update code from Go 1.14 and earlier:
go tool fix -r eglconf <pkg>
Using cgo directly
Usage:
@ -985,7 +990,7 @@ produces a file named a.out, even if cmd/link does so by invoking the host
linker in external linking mode.
By default, cmd/link will decide the linking mode as follows: if the only
packages using cgo are those on a whitelist of standard library
packages using cgo are those on a list of known standard library
packages (net, os/user, runtime/cgo), cmd/link will use internal linking
mode. Otherwise, there are non-standard cgo packages involved, and cmd/link
will use external linking mode. The first rule means that a build of

View file

@ -1354,7 +1354,7 @@ func (p *Package) rewriteRef(f *File) {
if *godefs {
// Substitute definition for mangled type name.
if r.Name.Type != nil {
if r.Name.Type != nil && r.Name.Kind == "type" {
expr = r.Name.Type.Go
}
if id, ok := expr.(*ast.Ident); ok {
@ -3029,7 +3029,7 @@ func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool {
if c.badJNI(dt) {
return true
}
if c.badEGLDisplay(dt) {
if c.badEGLType(dt) {
return true
}
return false
@ -3168,11 +3168,11 @@ func (c *typeConv) badJNI(dt *dwarf.TypedefType) bool {
return false
}
func (c *typeConv) badEGLDisplay(dt *dwarf.TypedefType) bool {
if dt.Name != "EGLDisplay" {
func (c *typeConv) badEGLType(dt *dwarf.TypedefType) bool {
if dt.Name != "EGLDisplay" && dt.Name != "EGLConfig" {
return false
}
// Check that the typedef is "typedef void *EGLDisplay".
// Check that the typedef is "typedef void *<name>".
if ptr, ok := dt.Type.(*dwarf.PtrType); ok {
if _, ok := ptr.Type.(*dwarf.VoidType); ok {
return true

View file

@ -98,6 +98,11 @@ func (p *Package) writeDefs() {
typedefNames := make([]string, 0, len(typedef))
for name := range typedef {
if name == "_Ctype_void" {
// We provide an appropriate declaration for
// _Ctype_void below (#39877).
continue
}
typedefNames = append(typedefNames, name)
}
sort.Strings(typedefNames)

View file

@ -107,6 +107,8 @@ Flags:
Warn about composite literals that can be simplified.
-shared
Generate code that can be linked into a shared library.
-spectre list
Enable spectre mitigations in list (all, index, ret).
-traceprofile file
Write an execution trace to file.
-trimpath prefix

View file

@ -96,7 +96,7 @@ func TestFormats(t *testing.T) {
}
importPath := filepath.Join("cmd/compile", path)
if blacklistedPackages[filepath.ToSlash(importPath)] {
if ignoredPackages[filepath.ToSlash(importPath)] {
return filepath.SkipDir
}
@ -344,8 +344,7 @@ func collectPkgFormats(t *testing.T, pkg *build.Package) {
for index, file := range files {
ast.Inspect(file, func(n ast.Node) bool {
if call, ok := n.(*ast.CallExpr); ok {
// ignore blacklisted functions
if blacklistedFunctions[nodeString(call.Fun)] {
if ignoredFunctions[nodeString(call.Fun)] {
return true
}
// look for an arguments that might be a format string
@ -354,7 +353,7 @@ func collectPkgFormats(t *testing.T, pkg *build.Package) {
// make sure we have enough arguments
n := numFormatArgs(s)
if i+1+n > len(call.Args) {
t.Errorf("%s: not enough format args (blacklist %s?)", posString(call), nodeString(call.Fun))
t.Errorf("%s: not enough format args (ignore %s?)", posString(call), nodeString(call.Fun))
break // ignore this call
}
// assume last n arguments are to be formatted;
@ -549,14 +548,14 @@ func formatReplace(in string, f func(i int, s string) string) string {
return string(append(buf, in[i0:]...))
}
// blacklistedPackages is the set of packages which can
// ignoredPackages is the set of packages which can
// be ignored.
var blacklistedPackages = map[string]bool{}
var ignoredPackages = map[string]bool{}
// blacklistedFunctions is the set of functions which may have
// ignoredFunctions is the set of functions which may have
// format-like arguments but which don't do any formatting and
// thus may be ignored.
var blacklistedFunctions = map[string]bool{}
var ignoredFunctions = map[string]bool{}
func init() {
// verify that knownFormats entries are correctly formatted

View file

@ -115,6 +115,7 @@ var knownFormats = map[string]string{
"cmd/compile/internal/ssa.Sym %v": "",
"cmd/compile/internal/ssa.ValAndOff %s": "",
"cmd/compile/internal/ssa.domain %v": "",
"cmd/compile/internal/ssa.flagConstant %s": "",
"cmd/compile/internal/ssa.posetNode %v": "",
"cmd/compile/internal/ssa.posetTestOp %v": "",
"cmd/compile/internal/ssa.rbrank %d": "",
@ -140,6 +141,7 @@ var knownFormats = map[string]string{
"float64 %.3f": "",
"float64 %.6g": "",
"float64 %g": "",
"int %#x": "",
"int %-12d": "",
"int %-6d": "",
"int %-8o": "",
@ -151,9 +153,11 @@ var knownFormats = map[string]string{
"int %x": "",
"int16 %d": "",
"int16 %x": "",
"int32 %#x": "",
"int32 %d": "",
"int32 %v": "",
"int32 %x": "",
"int64 %#x": "",
"int64 %+d": "",
"int64 %-10d": "",
"int64 %.5d": "",
@ -201,6 +205,7 @@ var knownFormats = map[string]string{
"uint64 %b": "",
"uint64 %d": "",
"uint64 %x": "",
"uint8 %#x": "",
"uint8 %d": "",
"uint8 %v": "",
"uint8 %x": "",

View file

@ -1252,11 +1252,11 @@ var blockJump = [...]struct {
ssa.BlockAMD64NAN: {x86.AJPS, x86.AJPC},
}
var eqfJumps = [2][2]gc.FloatingEQNEJump{
var eqfJumps = [2][2]gc.IndexJump{
{{Jump: x86.AJNE, Index: 1}, {Jump: x86.AJPS, Index: 1}}, // next == b.Succs[0]
{{Jump: x86.AJNE, Index: 1}, {Jump: x86.AJPC, Index: 0}}, // next == b.Succs[1]
}
var nefJumps = [2][2]gc.FloatingEQNEJump{
var nefJumps = [2][2]gc.IndexJump{
{{Jump: x86.AJNE, Index: 0}, {Jump: x86.AJPC, Index: 1}}, // next == b.Succs[0]
{{Jump: x86.AJNE, Index: 0}, {Jump: x86.AJPS, Index: 0}}, // next == b.Succs[1]
}
@ -1296,10 +1296,10 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
p.To.Sym = b.Aux.(*obj.LSym)
case ssa.BlockAMD64EQF:
s.FPJump(b, next, &eqfJumps)
s.CombJump(b, next, &eqfJumps)
case ssa.BlockAMD64NEF:
s.FPJump(b, next, &nefJumps)
s.CombJump(b, next, &nefJumps)
case ssa.BlockAMD64EQ, ssa.BlockAMD64NE,
ssa.BlockAMD64LT, ssa.BlockAMD64GE,

View file

@ -857,12 +857,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p := s.Prog(obj.AGETCALLERPC)
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
case ssa.OpARMFlagEQ,
ssa.OpARMFlagLT_ULT,
ssa.OpARMFlagLT_UGT,
ssa.OpARMFlagGT_ULT,
ssa.OpARMFlagGT_UGT:
v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString())
case ssa.OpARMFlagConstant:
v.Fatalf("FlagConstant op should never make it to codegen %v", v.LongString())
case ssa.OpARMInvertFlags:
v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
case ssa.OpClobber:
@ -888,16 +884,30 @@ var condBits = map[ssa.Op]uint8{
var blockJump = map[ssa.BlockKind]struct {
asm, invasm obj.As
}{
ssa.BlockARMEQ: {arm.ABEQ, arm.ABNE},
ssa.BlockARMNE: {arm.ABNE, arm.ABEQ},
ssa.BlockARMLT: {arm.ABLT, arm.ABGE},
ssa.BlockARMGE: {arm.ABGE, arm.ABLT},
ssa.BlockARMLE: {arm.ABLE, arm.ABGT},
ssa.BlockARMGT: {arm.ABGT, arm.ABLE},
ssa.BlockARMULT: {arm.ABLO, arm.ABHS},
ssa.BlockARMUGE: {arm.ABHS, arm.ABLO},
ssa.BlockARMUGT: {arm.ABHI, arm.ABLS},
ssa.BlockARMULE: {arm.ABLS, arm.ABHI},
ssa.BlockARMEQ: {arm.ABEQ, arm.ABNE},
ssa.BlockARMNE: {arm.ABNE, arm.ABEQ},
ssa.BlockARMLT: {arm.ABLT, arm.ABGE},
ssa.BlockARMGE: {arm.ABGE, arm.ABLT},
ssa.BlockARMLE: {arm.ABLE, arm.ABGT},
ssa.BlockARMGT: {arm.ABGT, arm.ABLE},
ssa.BlockARMULT: {arm.ABLO, arm.ABHS},
ssa.BlockARMUGE: {arm.ABHS, arm.ABLO},
ssa.BlockARMUGT: {arm.ABHI, arm.ABLS},
ssa.BlockARMULE: {arm.ABLS, arm.ABHI},
ssa.BlockARMLTnoov: {arm.ABMI, arm.ABPL},
ssa.BlockARMGEnoov: {arm.ABPL, arm.ABMI},
}
// To model a 'LEnoov' ('<=' without overflow checking) branching
var leJumps = [2][2]gc.IndexJump{
{{Jump: arm.ABEQ, Index: 0}, {Jump: arm.ABPL, Index: 1}}, // next == b.Succs[0]
{{Jump: arm.ABMI, Index: 0}, {Jump: arm.ABEQ, Index: 0}}, // next == b.Succs[1]
}
// To model a 'GTnoov' ('>' without overflow checking) branching
var gtJumps = [2][2]gc.IndexJump{
{{Jump: arm.ABMI, Index: 1}, {Jump: arm.ABEQ, Index: 1}}, // next == b.Succs[0]
{{Jump: arm.ABEQ, Index: 1}, {Jump: arm.ABPL, Index: 0}}, // next == b.Succs[1]
}
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
@ -941,7 +951,8 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
ssa.BlockARMLT, ssa.BlockARMGE,
ssa.BlockARMLE, ssa.BlockARMGT,
ssa.BlockARMULT, ssa.BlockARMUGT,
ssa.BlockARMULE, ssa.BlockARMUGE:
ssa.BlockARMULE, ssa.BlockARMUGE,
ssa.BlockARMLTnoov, ssa.BlockARMGEnoov:
jmp := blockJump[b.Kind]
switch next {
case b.Succs[0].Block():
@ -958,6 +969,12 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
}
}
case ssa.BlockARMLEnoov:
s.CombJump(b, next, &leJumps)
case ssa.BlockARMGTnoov:
s.CombJump(b, next, &gtJumps)
default:
b.Fatalf("branch not implemented: %s", b.LongString())
}

View file

@ -943,12 +943,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p := s.Prog(obj.AGETCALLERPC)
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
case ssa.OpARM64FlagEQ,
ssa.OpARM64FlagLT_ULT,
ssa.OpARM64FlagLT_UGT,
ssa.OpARM64FlagGT_ULT,
ssa.OpARM64FlagGT_UGT:
v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString())
case ssa.OpARM64FlagConstant:
v.Fatalf("FlagConstant op should never make it to codegen %v", v.LongString())
case ssa.OpARM64InvertFlags:
v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
case ssa.OpClobber:
@ -978,26 +974,40 @@ var condBits = map[ssa.Op]int16{
var blockJump = map[ssa.BlockKind]struct {
asm, invasm obj.As
}{
ssa.BlockARM64EQ: {arm64.ABEQ, arm64.ABNE},
ssa.BlockARM64NE: {arm64.ABNE, arm64.ABEQ},
ssa.BlockARM64LT: {arm64.ABLT, arm64.ABGE},
ssa.BlockARM64GE: {arm64.ABGE, arm64.ABLT},
ssa.BlockARM64LE: {arm64.ABLE, arm64.ABGT},
ssa.BlockARM64GT: {arm64.ABGT, arm64.ABLE},
ssa.BlockARM64ULT: {arm64.ABLO, arm64.ABHS},
ssa.BlockARM64UGE: {arm64.ABHS, arm64.ABLO},
ssa.BlockARM64UGT: {arm64.ABHI, arm64.ABLS},
ssa.BlockARM64ULE: {arm64.ABLS, arm64.ABHI},
ssa.BlockARM64Z: {arm64.ACBZ, arm64.ACBNZ},
ssa.BlockARM64NZ: {arm64.ACBNZ, arm64.ACBZ},
ssa.BlockARM64ZW: {arm64.ACBZW, arm64.ACBNZW},
ssa.BlockARM64NZW: {arm64.ACBNZW, arm64.ACBZW},
ssa.BlockARM64TBZ: {arm64.ATBZ, arm64.ATBNZ},
ssa.BlockARM64TBNZ: {arm64.ATBNZ, arm64.ATBZ},
ssa.BlockARM64FLT: {arm64.ABMI, arm64.ABPL},
ssa.BlockARM64FGE: {arm64.ABGE, arm64.ABLT},
ssa.BlockARM64FLE: {arm64.ABLS, arm64.ABHI},
ssa.BlockARM64FGT: {arm64.ABGT, arm64.ABLE},
ssa.BlockARM64EQ: {arm64.ABEQ, arm64.ABNE},
ssa.BlockARM64NE: {arm64.ABNE, arm64.ABEQ},
ssa.BlockARM64LT: {arm64.ABLT, arm64.ABGE},
ssa.BlockARM64GE: {arm64.ABGE, arm64.ABLT},
ssa.BlockARM64LE: {arm64.ABLE, arm64.ABGT},
ssa.BlockARM64GT: {arm64.ABGT, arm64.ABLE},
ssa.BlockARM64ULT: {arm64.ABLO, arm64.ABHS},
ssa.BlockARM64UGE: {arm64.ABHS, arm64.ABLO},
ssa.BlockARM64UGT: {arm64.ABHI, arm64.ABLS},
ssa.BlockARM64ULE: {arm64.ABLS, arm64.ABHI},
ssa.BlockARM64Z: {arm64.ACBZ, arm64.ACBNZ},
ssa.BlockARM64NZ: {arm64.ACBNZ, arm64.ACBZ},
ssa.BlockARM64ZW: {arm64.ACBZW, arm64.ACBNZW},
ssa.BlockARM64NZW: {arm64.ACBNZW, arm64.ACBZW},
ssa.BlockARM64TBZ: {arm64.ATBZ, arm64.ATBNZ},
ssa.BlockARM64TBNZ: {arm64.ATBNZ, arm64.ATBZ},
ssa.BlockARM64FLT: {arm64.ABMI, arm64.ABPL},
ssa.BlockARM64FGE: {arm64.ABGE, arm64.ABLT},
ssa.BlockARM64FLE: {arm64.ABLS, arm64.ABHI},
ssa.BlockARM64FGT: {arm64.ABGT, arm64.ABLE},
ssa.BlockARM64LTnoov: {arm64.ABMI, arm64.ABPL},
ssa.BlockARM64GEnoov: {arm64.ABPL, arm64.ABMI},
}
// To model a 'LEnoov' ('<=' without overflow checking) branching
var leJumps = [2][2]gc.IndexJump{
{{Jump: arm64.ABEQ, Index: 0}, {Jump: arm64.ABPL, Index: 1}}, // next == b.Succs[0]
{{Jump: arm64.ABMI, Index: 0}, {Jump: arm64.ABEQ, Index: 0}}, // next == b.Succs[1]
}
// To model a 'GTnoov' ('>' without overflow checking) branching
var gtJumps = [2][2]gc.IndexJump{
{{Jump: arm64.ABMI, Index: 1}, {Jump: arm64.ABEQ, Index: 1}}, // next == b.Succs[0]
{{Jump: arm64.ABEQ, Index: 1}, {Jump: arm64.ABPL, Index: 0}}, // next == b.Succs[1]
}
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
@ -1045,7 +1055,8 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
ssa.BlockARM64Z, ssa.BlockARM64NZ,
ssa.BlockARM64ZW, ssa.BlockARM64NZW,
ssa.BlockARM64FLT, ssa.BlockARM64FGE,
ssa.BlockARM64FLE, ssa.BlockARM64FGT:
ssa.BlockARM64FLE, ssa.BlockARM64FGT,
ssa.BlockARM64LTnoov, ssa.BlockARM64GEnoov:
jmp := blockJump[b.Kind]
var p *obj.Prog
switch next {
@ -1087,6 +1098,10 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
p.From.Type = obj.TYPE_CONST
p.Reg = b.Controls[0].Reg()
case ssa.BlockARM64LEnoov:
s.CombJump(b, next, &leJumps)
case ssa.BlockARM64GTnoov:
s.CombJump(b, next, &gtJumps)
default:
b.Fatalf("branch not implemented: %s", b.LongString())
}

View file

@ -63,6 +63,26 @@ func IncomparableField(t *types.Type) *types.Field {
return nil
}
// EqCanPanic reports whether == on type t could panic (has an interface somewhere).
// t must be comparable.
func EqCanPanic(t *types.Type) bool {
switch t.Etype {
default:
return false
case TINTER:
return true
case TARRAY:
return EqCanPanic(t.Elem())
case TSTRUCT:
for _, f := range t.FieldSlice() {
if !f.Sym.IsBlank() && EqCanPanic(f.Type) {
return true
}
}
return false
}
}
// algtype is like algtype1, except it returns the fixed-width AMEMxx variants
// instead of the general AMEM kind when possible.
func algtype(t *types.Type) AlgKind {
@ -591,24 +611,6 @@ func geneq(t *types.Type) *obj.LSym {
}
switch t.Elem().Etype {
case TINTER:
// Do two loops. First, check that all the types match (cheap).
// Second, check that all the data match (expensive).
// TODO: when the array size is small, unroll the tab match checks.
checkAll(3, func(pi, qi *Node) *Node {
// Compare types.
pi = typecheck(pi, ctxExpr)
qi = typecheck(qi, ctxExpr)
eqtab, _ := eqinterface(pi, qi)
return eqtab
})
checkAll(1, func(pi, qi *Node) *Node {
// Compare data.
pi = typecheck(pi, ctxExpr)
qi = typecheck(qi, ctxExpr)
_, eqdata := eqinterface(pi, qi)
return eqdata
})
case TSTRING:
// Do two loops. First, check that all the lengths match (cheap).
// Second, check that all the contents match (expensive).
@ -642,14 +644,19 @@ func geneq(t *types.Type) *obj.LSym {
case TSTRUCT:
// Build a list of conditions to satisfy.
// Track their order so that we can preserve aspects of that order.
// The conditions are a list-of-lists. Conditions are reorderable
// within each inner list. The outer lists must be evaluated in order.
// Even within each inner list, track their order so that we can preserve
// aspects of that order. (TODO: latter part needed?)
type nodeIdx struct {
n *Node
idx int
}
var conds []nodeIdx
var conds [][]nodeIdx
conds = append(conds, []nodeIdx{})
and := func(n *Node) {
conds = append(conds, nodeIdx{n: n, idx: len(conds)})
i := len(conds) - 1
conds[i] = append(conds[i], nodeIdx{n: n, idx: len(conds[i])})
}
// Walk the struct using memequal for runs of AMEM
@ -665,6 +672,10 @@ func geneq(t *types.Type) *obj.LSym {
// Compare non-memory fields with field equality.
if !IsRegularMemory(f.Type) {
if EqCanPanic(f.Type) {
// Enforce ordering by starting a new set of reorderable conditions.
conds = append(conds, []nodeIdx{})
}
p := nodSym(OXDOT, np, f.Sym)
q := nodSym(OXDOT, nq, f.Sym)
switch {
@ -672,17 +683,13 @@ func geneq(t *types.Type) *obj.LSym {
eqlen, eqmem := eqstring(p, q)
and(eqlen)
and(eqmem)
case f.Type.IsInterface():
p.Type = f.Type
p = typecheck(p, ctxExpr)
q.Type = f.Type
q = typecheck(q, ctxExpr)
eqtab, eqdata := eqinterface(p, q)
and(eqtab)
and(eqdata)
default:
and(nod(OEQ, p, q))
}
if EqCanPanic(f.Type) {
// Also enforce ordering after something that can panic.
conds = append(conds, []nodeIdx{})
}
i++
continue
}
@ -706,20 +713,24 @@ func geneq(t *types.Type) *obj.LSym {
// Sort conditions to put runtime calls last.
// Preserve the rest of the ordering.
sort.SliceStable(conds, func(i, j int) bool {
x, y := conds[i], conds[j]
if (x.n.Op != OCALL) == (y.n.Op != OCALL) {
return x.idx < y.idx
}
return x.n.Op != OCALL
})
var flatConds []nodeIdx
for _, c := range conds {
sort.SliceStable(c, func(i, j int) bool {
x, y := c[i], c[j]
if (x.n.Op != OCALL) == (y.n.Op != OCALL) {
return x.idx < y.idx
}
return x.n.Op != OCALL
})
flatConds = append(flatConds, c...)
}
var cond *Node
if len(conds) == 0 {
if len(flatConds) == 0 {
cond = nodbool(true)
} else {
cond = conds[0].n
for _, c := range conds[1:] {
cond = flatConds[0].n
for _, c := range flatConds[1:] {
cond = nod(OANDAND, cond, c.n)
}
}

View file

@ -10,325 +10,329 @@ var runtimeDecls = [...]struct {
typ int
}{
{"newobject", funcTag, 4},
{"panicdivide", funcTag, 5},
{"panicshift", funcTag, 5},
{"panicmakeslicelen", funcTag, 5},
{"panicmakeslicecap", funcTag, 5},
{"throwinit", funcTag, 5},
{"panicwrap", funcTag, 5},
{"gopanic", funcTag, 7},
{"gorecover", funcTag, 10},
{"goschedguarded", funcTag, 5},
{"goPanicIndex", funcTag, 12},
{"goPanicIndexU", funcTag, 14},
{"goPanicSliceAlen", funcTag, 12},
{"goPanicSliceAlenU", funcTag, 14},
{"goPanicSliceAcap", funcTag, 12},
{"goPanicSliceAcapU", funcTag, 14},
{"goPanicSliceB", funcTag, 12},
{"goPanicSliceBU", funcTag, 14},
{"goPanicSlice3Alen", funcTag, 12},
{"goPanicSlice3AlenU", funcTag, 14},
{"goPanicSlice3Acap", funcTag, 12},
{"goPanicSlice3AcapU", funcTag, 14},
{"goPanicSlice3B", funcTag, 12},
{"goPanicSlice3BU", funcTag, 14},
{"goPanicSlice3C", funcTag, 12},
{"goPanicSlice3CU", funcTag, 14},
{"printbool", funcTag, 16},
{"printfloat", funcTag, 18},
{"printint", funcTag, 20},
{"printhex", funcTag, 22},
{"printuint", funcTag, 22},
{"printcomplex", funcTag, 24},
{"printstring", funcTag, 26},
{"printpointer", funcTag, 27},
{"printiface", funcTag, 27},
{"printeface", funcTag, 27},
{"printslice", funcTag, 27},
{"printnl", funcTag, 5},
{"printsp", funcTag, 5},
{"printlock", funcTag, 5},
{"printunlock", funcTag, 5},
{"concatstring2", funcTag, 30},
{"concatstring3", funcTag, 31},
{"concatstring4", funcTag, 32},
{"concatstring5", funcTag, 33},
{"concatstrings", funcTag, 35},
{"cmpstring", funcTag, 36},
{"intstring", funcTag, 39},
{"slicebytetostring", funcTag, 40},
{"slicebytetostringtmp", funcTag, 41},
{"slicerunetostring", funcTag, 44},
{"stringtoslicebyte", funcTag, 46},
{"stringtoslicerune", funcTag, 49},
{"slicecopy", funcTag, 51},
{"slicestringcopy", funcTag, 52},
{"decoderune", funcTag, 53},
{"countrunes", funcTag, 54},
{"convI2I", funcTag, 55},
{"convT16", funcTag, 57},
{"convT32", funcTag, 57},
{"convT64", funcTag, 57},
{"convTstring", funcTag, 57},
{"convTslice", funcTag, 57},
{"convT2E", funcTag, 58},
{"convT2Enoptr", funcTag, 58},
{"convT2I", funcTag, 58},
{"convT2Inoptr", funcTag, 58},
{"assertE2I", funcTag, 55},
{"assertE2I2", funcTag, 59},
{"assertI2I", funcTag, 55},
{"assertI2I2", funcTag, 59},
{"panicdottypeE", funcTag, 60},
{"panicdottypeI", funcTag, 60},
{"panicnildottype", funcTag, 61},
{"ifaceeq", funcTag, 63},
{"efaceeq", funcTag, 63},
{"fastrand", funcTag, 65},
{"makemap64", funcTag, 67},
{"makemap", funcTag, 68},
{"makemap_small", funcTag, 69},
{"mapaccess1", funcTag, 70},
{"mapaccess1_fast32", funcTag, 71},
{"mapaccess1_fast64", funcTag, 71},
{"mapaccess1_faststr", funcTag, 71},
{"mapaccess1_fat", funcTag, 72},
{"mapaccess2", funcTag, 73},
{"mapaccess2_fast32", funcTag, 74},
{"mapaccess2_fast64", funcTag, 74},
{"mapaccess2_faststr", funcTag, 74},
{"mapaccess2_fat", funcTag, 75},
{"mapassign", funcTag, 70},
{"mapassign_fast32", funcTag, 71},
{"mapassign_fast32ptr", funcTag, 71},
{"mapassign_fast64", funcTag, 71},
{"mapassign_fast64ptr", funcTag, 71},
{"mapassign_faststr", funcTag, 71},
{"mapiterinit", funcTag, 76},
{"mapdelete", funcTag, 76},
{"mapdelete_fast32", funcTag, 77},
{"mapdelete_fast64", funcTag, 77},
{"mapdelete_faststr", funcTag, 77},
{"mapiternext", funcTag, 78},
{"mapclear", funcTag, 79},
{"makechan64", funcTag, 81},
{"makechan", funcTag, 82},
{"chanrecv1", funcTag, 84},
{"chanrecv2", funcTag, 85},
{"chansend1", funcTag, 87},
{"closechan", funcTag, 27},
{"writeBarrier", varTag, 89},
{"typedmemmove", funcTag, 90},
{"typedmemclr", funcTag, 91},
{"typedslicecopy", funcTag, 92},
{"selectnbsend", funcTag, 93},
{"selectnbrecv", funcTag, 94},
{"selectnbrecv2", funcTag, 96},
{"selectsetpc", funcTag, 61},
{"selectgo", funcTag, 97},
{"block", funcTag, 5},
{"makeslice", funcTag, 98},
{"makeslice64", funcTag, 99},
{"growslice", funcTag, 101},
{"memmove", funcTag, 102},
{"memclrNoHeapPointers", funcTag, 103},
{"memclrHasPointers", funcTag, 103},
{"memequal", funcTag, 104},
{"memequal0", funcTag, 105},
{"memequal8", funcTag, 105},
{"memequal16", funcTag, 105},
{"memequal32", funcTag, 105},
{"memequal64", funcTag, 105},
{"memequal128", funcTag, 105},
{"f32equal", funcTag, 106},
{"f64equal", funcTag, 106},
{"c64equal", funcTag, 106},
{"c128equal", funcTag, 106},
{"strequal", funcTag, 106},
{"interequal", funcTag, 106},
{"nilinterequal", funcTag, 106},
{"memhash", funcTag, 107},
{"memhash0", funcTag, 108},
{"memhash8", funcTag, 108},
{"memhash16", funcTag, 108},
{"memhash32", funcTag, 108},
{"memhash64", funcTag, 108},
{"memhash128", funcTag, 108},
{"f32hash", funcTag, 108},
{"f64hash", funcTag, 108},
{"c64hash", funcTag, 108},
{"c128hash", funcTag, 108},
{"strhash", funcTag, 108},
{"interhash", funcTag, 108},
{"nilinterhash", funcTag, 108},
{"int64div", funcTag, 109},
{"uint64div", funcTag, 110},
{"int64mod", funcTag, 109},
{"uint64mod", funcTag, 110},
{"float64toint64", funcTag, 111},
{"float64touint64", funcTag, 112},
{"float64touint32", funcTag, 113},
{"int64tofloat64", funcTag, 114},
{"uint64tofloat64", funcTag, 115},
{"uint32tofloat64", funcTag, 116},
{"complex128div", funcTag, 117},
{"racefuncenter", funcTag, 118},
{"racefuncenterfp", funcTag, 5},
{"racefuncexit", funcTag, 5},
{"raceread", funcTag, 118},
{"racewrite", funcTag, 118},
{"racereadrange", funcTag, 119},
{"racewriterange", funcTag, 119},
{"msanread", funcTag, 119},
{"msanwrite", funcTag, 119},
{"checkptrAlignment", funcTag, 120},
{"checkptrArithmetic", funcTag, 122},
{"libfuzzerTraceCmp1", funcTag, 124},
{"libfuzzerTraceCmp2", funcTag, 126},
{"libfuzzerTraceCmp4", funcTag, 127},
{"libfuzzerTraceCmp8", funcTag, 128},
{"libfuzzerTraceConstCmp1", funcTag, 124},
{"libfuzzerTraceConstCmp2", funcTag, 126},
{"libfuzzerTraceConstCmp4", funcTag, 127},
{"libfuzzerTraceConstCmp8", funcTag, 128},
{"x86HasPOPCNT", varTag, 15},
{"x86HasSSE41", varTag, 15},
{"x86HasFMA", varTag, 15},
{"armHasVFPv4", varTag, 15},
{"arm64HasATOMICS", varTag, 15},
{"mallocgc", funcTag, 8},
{"panicdivide", funcTag, 9},
{"panicshift", funcTag, 9},
{"panicmakeslicelen", funcTag, 9},
{"panicmakeslicecap", funcTag, 9},
{"throwinit", funcTag, 9},
{"panicwrap", funcTag, 9},
{"gopanic", funcTag, 11},
{"gorecover", funcTag, 14},
{"goschedguarded", funcTag, 9},
{"goPanicIndex", funcTag, 16},
{"goPanicIndexU", funcTag, 18},
{"goPanicSliceAlen", funcTag, 16},
{"goPanicSliceAlenU", funcTag, 18},
{"goPanicSliceAcap", funcTag, 16},
{"goPanicSliceAcapU", funcTag, 18},
{"goPanicSliceB", funcTag, 16},
{"goPanicSliceBU", funcTag, 18},
{"goPanicSlice3Alen", funcTag, 16},
{"goPanicSlice3AlenU", funcTag, 18},
{"goPanicSlice3Acap", funcTag, 16},
{"goPanicSlice3AcapU", funcTag, 18},
{"goPanicSlice3B", funcTag, 16},
{"goPanicSlice3BU", funcTag, 18},
{"goPanicSlice3C", funcTag, 16},
{"goPanicSlice3CU", funcTag, 18},
{"printbool", funcTag, 19},
{"printfloat", funcTag, 21},
{"printint", funcTag, 23},
{"printhex", funcTag, 25},
{"printuint", funcTag, 25},
{"printcomplex", funcTag, 27},
{"printstring", funcTag, 29},
{"printpointer", funcTag, 30},
{"printiface", funcTag, 30},
{"printeface", funcTag, 30},
{"printslice", funcTag, 30},
{"printnl", funcTag, 9},
{"printsp", funcTag, 9},
{"printlock", funcTag, 9},
{"printunlock", funcTag, 9},
{"concatstring2", funcTag, 33},
{"concatstring3", funcTag, 34},
{"concatstring4", funcTag, 35},
{"concatstring5", funcTag, 36},
{"concatstrings", funcTag, 38},
{"cmpstring", funcTag, 39},
{"intstring", funcTag, 42},
{"slicebytetostring", funcTag, 43},
{"slicebytetostringtmp", funcTag, 44},
{"slicerunetostring", funcTag, 47},
{"stringtoslicebyte", funcTag, 49},
{"stringtoslicerune", funcTag, 52},
{"slicecopy", funcTag, 53},
{"slicestringcopy", funcTag, 54},
{"decoderune", funcTag, 55},
{"countrunes", funcTag, 56},
{"convI2I", funcTag, 57},
{"convT16", funcTag, 58},
{"convT32", funcTag, 58},
{"convT64", funcTag, 58},
{"convTstring", funcTag, 58},
{"convTslice", funcTag, 58},
{"convT2E", funcTag, 59},
{"convT2Enoptr", funcTag, 59},
{"convT2I", funcTag, 59},
{"convT2Inoptr", funcTag, 59},
{"assertE2I", funcTag, 57},
{"assertE2I2", funcTag, 60},
{"assertI2I", funcTag, 57},
{"assertI2I2", funcTag, 60},
{"panicdottypeE", funcTag, 61},
{"panicdottypeI", funcTag, 61},
{"panicnildottype", funcTag, 62},
{"ifaceeq", funcTag, 64},
{"efaceeq", funcTag, 64},
{"fastrand", funcTag, 66},
{"makemap64", funcTag, 68},
{"makemap", funcTag, 69},
{"makemap_small", funcTag, 70},
{"mapaccess1", funcTag, 71},
{"mapaccess1_fast32", funcTag, 72},
{"mapaccess1_fast64", funcTag, 72},
{"mapaccess1_faststr", funcTag, 72},
{"mapaccess1_fat", funcTag, 73},
{"mapaccess2", funcTag, 74},
{"mapaccess2_fast32", funcTag, 75},
{"mapaccess2_fast64", funcTag, 75},
{"mapaccess2_faststr", funcTag, 75},
{"mapaccess2_fat", funcTag, 76},
{"mapassign", funcTag, 71},
{"mapassign_fast32", funcTag, 72},
{"mapassign_fast32ptr", funcTag, 72},
{"mapassign_fast64", funcTag, 72},
{"mapassign_fast64ptr", funcTag, 72},
{"mapassign_faststr", funcTag, 72},
{"mapiterinit", funcTag, 77},
{"mapdelete", funcTag, 77},
{"mapdelete_fast32", funcTag, 78},
{"mapdelete_fast64", funcTag, 78},
{"mapdelete_faststr", funcTag, 78},
{"mapiternext", funcTag, 79},
{"mapclear", funcTag, 80},
{"makechan64", funcTag, 82},
{"makechan", funcTag, 83},
{"chanrecv1", funcTag, 85},
{"chanrecv2", funcTag, 86},
{"chansend1", funcTag, 88},
{"closechan", funcTag, 30},
{"writeBarrier", varTag, 90},
{"typedmemmove", funcTag, 91},
{"typedmemclr", funcTag, 92},
{"typedslicecopy", funcTag, 93},
{"selectnbsend", funcTag, 94},
{"selectnbrecv", funcTag, 95},
{"selectnbrecv2", funcTag, 97},
{"selectsetpc", funcTag, 62},
{"selectgo", funcTag, 98},
{"block", funcTag, 9},
{"makeslice", funcTag, 99},
{"makeslice64", funcTag, 100},
{"makeslicecopy", funcTag, 101},
{"growslice", funcTag, 103},
{"memmove", funcTag, 104},
{"memclrNoHeapPointers", funcTag, 105},
{"memclrHasPointers", funcTag, 105},
{"memequal", funcTag, 106},
{"memequal0", funcTag, 107},
{"memequal8", funcTag, 107},
{"memequal16", funcTag, 107},
{"memequal32", funcTag, 107},
{"memequal64", funcTag, 107},
{"memequal128", funcTag, 107},
{"f32equal", funcTag, 108},
{"f64equal", funcTag, 108},
{"c64equal", funcTag, 108},
{"c128equal", funcTag, 108},
{"strequal", funcTag, 108},
{"interequal", funcTag, 108},
{"nilinterequal", funcTag, 108},
{"memhash", funcTag, 109},
{"memhash0", funcTag, 110},
{"memhash8", funcTag, 110},
{"memhash16", funcTag, 110},
{"memhash32", funcTag, 110},
{"memhash64", funcTag, 110},
{"memhash128", funcTag, 110},
{"f32hash", funcTag, 110},
{"f64hash", funcTag, 110},
{"c64hash", funcTag, 110},
{"c128hash", funcTag, 110},
{"strhash", funcTag, 110},
{"interhash", funcTag, 110},
{"nilinterhash", funcTag, 110},
{"int64div", funcTag, 111},
{"uint64div", funcTag, 112},
{"int64mod", funcTag, 111},
{"uint64mod", funcTag, 112},
{"float64toint64", funcTag, 113},
{"float64touint64", funcTag, 114},
{"float64touint32", funcTag, 115},
{"int64tofloat64", funcTag, 116},
{"uint64tofloat64", funcTag, 117},
{"uint32tofloat64", funcTag, 118},
{"complex128div", funcTag, 119},
{"racefuncenter", funcTag, 120},
{"racefuncenterfp", funcTag, 9},
{"racefuncexit", funcTag, 9},
{"raceread", funcTag, 120},
{"racewrite", funcTag, 120},
{"racereadrange", funcTag, 121},
{"racewriterange", funcTag, 121},
{"msanread", funcTag, 121},
{"msanwrite", funcTag, 121},
{"checkptrAlignment", funcTag, 122},
{"checkptrArithmetic", funcTag, 124},
{"libfuzzerTraceCmp1", funcTag, 126},
{"libfuzzerTraceCmp2", funcTag, 128},
{"libfuzzerTraceCmp4", funcTag, 129},
{"libfuzzerTraceCmp8", funcTag, 130},
{"libfuzzerTraceConstCmp1", funcTag, 126},
{"libfuzzerTraceConstCmp2", funcTag, 128},
{"libfuzzerTraceConstCmp4", funcTag, 129},
{"libfuzzerTraceConstCmp8", funcTag, 130},
{"x86HasPOPCNT", varTag, 6},
{"x86HasSSE41", varTag, 6},
{"x86HasFMA", varTag, 6},
{"armHasVFPv4", varTag, 6},
{"arm64HasATOMICS", varTag, 6},
}
func runtimeTypes() []*types.Type {
var typs [129]*types.Type
var typs [131]*types.Type
typs[0] = types.Bytetype
typs[1] = types.NewPtr(typs[0])
typs[2] = types.Types[TANY]
typs[3] = types.NewPtr(typs[2])
typs[4] = functype(nil, []*Node{anonfield(typs[1])}, []*Node{anonfield(typs[3])})
typs[5] = functype(nil, nil, nil)
typs[6] = types.Types[TINTER]
typs[7] = functype(nil, []*Node{anonfield(typs[6])}, nil)
typs[8] = types.Types[TINT32]
typs[9] = types.NewPtr(typs[8])
typs[10] = functype(nil, []*Node{anonfield(typs[9])}, []*Node{anonfield(typs[6])})
typs[11] = types.Types[TINT]
typs[12] = functype(nil, []*Node{anonfield(typs[11]), anonfield(typs[11])}, nil)
typs[13] = types.Types[TUINT]
typs[14] = functype(nil, []*Node{anonfield(typs[13]), anonfield(typs[11])}, nil)
typs[15] = types.Types[TBOOL]
typs[16] = functype(nil, []*Node{anonfield(typs[15])}, nil)
typs[17] = types.Types[TFLOAT64]
typs[18] = functype(nil, []*Node{anonfield(typs[17])}, nil)
typs[19] = types.Types[TINT64]
typs[20] = functype(nil, []*Node{anonfield(typs[19])}, nil)
typs[21] = types.Types[TUINT64]
typs[22] = functype(nil, []*Node{anonfield(typs[21])}, nil)
typs[23] = types.Types[TCOMPLEX128]
typs[24] = functype(nil, []*Node{anonfield(typs[23])}, nil)
typs[25] = types.Types[TSTRING]
typs[26] = functype(nil, []*Node{anonfield(typs[25])}, nil)
typs[27] = functype(nil, []*Node{anonfield(typs[2])}, nil)
typs[28] = types.NewArray(typs[0], 32)
typs[29] = types.NewPtr(typs[28])
typs[30] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[25]), anonfield(typs[25])}, []*Node{anonfield(typs[25])})
typs[31] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[25]), anonfield(typs[25]), anonfield(typs[25])}, []*Node{anonfield(typs[25])})
typs[32] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[25]), anonfield(typs[25]), anonfield(typs[25]), anonfield(typs[25])}, []*Node{anonfield(typs[25])})
typs[33] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[25]), anonfield(typs[25]), anonfield(typs[25]), anonfield(typs[25]), anonfield(typs[25])}, []*Node{anonfield(typs[25])})
typs[34] = types.NewSlice(typs[25])
typs[35] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[34])}, []*Node{anonfield(typs[25])})
typs[36] = functype(nil, []*Node{anonfield(typs[25]), anonfield(typs[25])}, []*Node{anonfield(typs[11])})
typs[37] = types.NewArray(typs[0], 4)
typs[38] = types.NewPtr(typs[37])
typs[39] = functype(nil, []*Node{anonfield(typs[38]), anonfield(typs[19])}, []*Node{anonfield(typs[25])})
typs[40] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[1]), anonfield(typs[11])}, []*Node{anonfield(typs[25])})
typs[41] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[11])}, []*Node{anonfield(typs[25])})
typs[42] = types.Runetype
typs[43] = types.NewSlice(typs[42])
typs[44] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[43])}, []*Node{anonfield(typs[25])})
typs[45] = types.NewSlice(typs[0])
typs[46] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[25])}, []*Node{anonfield(typs[45])})
typs[47] = types.NewArray(typs[42], 32)
typs[48] = types.NewPtr(typs[47])
typs[49] = functype(nil, []*Node{anonfield(typs[48]), anonfield(typs[25])}, []*Node{anonfield(typs[43])})
typs[50] = types.Types[TUINTPTR]
typs[51] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[11]), anonfield(typs[3]), anonfield(typs[11]), anonfield(typs[50])}, []*Node{anonfield(typs[11])})
typs[52] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[11]), anonfield(typs[25])}, []*Node{anonfield(typs[11])})
typs[53] = functype(nil, []*Node{anonfield(typs[25]), anonfield(typs[11])}, []*Node{anonfield(typs[42]), anonfield(typs[11])})
typs[54] = functype(nil, []*Node{anonfield(typs[25])}, []*Node{anonfield(typs[11])})
typs[55] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2])})
typs[56] = types.Types[TUNSAFEPTR]
typs[57] = functype(nil, []*Node{anonfield(typs[2])}, []*Node{anonfield(typs[56])})
typs[58] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, []*Node{anonfield(typs[2])})
typs[59] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2]), anonfield(typs[15])})
typs[60] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil)
typs[61] = functype(nil, []*Node{anonfield(typs[1])}, nil)
typs[62] = types.NewPtr(typs[50])
typs[63] = functype(nil, []*Node{anonfield(typs[62]), anonfield(typs[56]), anonfield(typs[56])}, []*Node{anonfield(typs[15])})
typs[64] = types.Types[TUINT32]
typs[65] = functype(nil, nil, []*Node{anonfield(typs[64])})
typs[66] = types.NewMap(typs[2], typs[2])
typs[67] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[19]), anonfield(typs[3])}, []*Node{anonfield(typs[66])})
typs[68] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[11]), anonfield(typs[3])}, []*Node{anonfield(typs[66])})
typs[69] = functype(nil, nil, []*Node{anonfield(typs[66])})
typs[70] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3])}, []*Node{anonfield(typs[3])})
typs[71] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[2])}, []*Node{anonfield(typs[3])})
typs[72] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3])})
typs[73] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3])}, []*Node{anonfield(typs[3]), anonfield(typs[15])})
typs[74] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[2])}, []*Node{anonfield(typs[3]), anonfield(typs[15])})
typs[75] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3]), anonfield(typs[15])})
typs[76] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3])}, nil)
typs[77] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[2])}, nil)
typs[78] = functype(nil, []*Node{anonfield(typs[3])}, nil)
typs[79] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66])}, nil)
typs[80] = types.NewChan(typs[2], types.Cboth)
typs[81] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[19])}, []*Node{anonfield(typs[80])})
typs[82] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[11])}, []*Node{anonfield(typs[80])})
typs[83] = types.NewChan(typs[2], types.Crecv)
typs[84] = functype(nil, []*Node{anonfield(typs[83]), anonfield(typs[3])}, nil)
typs[85] = functype(nil, []*Node{anonfield(typs[83]), anonfield(typs[3])}, []*Node{anonfield(typs[15])})
typs[86] = types.NewChan(typs[2], types.Csend)
typs[87] = functype(nil, []*Node{anonfield(typs[86]), anonfield(typs[3])}, nil)
typs[88] = types.NewArray(typs[0], 3)
typs[89] = tostruct([]*Node{namedfield("enabled", typs[15]), namedfield("pad", typs[88]), namedfield("needed", typs[15]), namedfield("cgo", typs[15]), namedfield("alignme", typs[21])})
typs[90] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil)
typs[91] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, nil)
typs[92] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[11]), anonfield(typs[3]), anonfield(typs[11])}, []*Node{anonfield(typs[11])})
typs[93] = functype(nil, []*Node{anonfield(typs[86]), anonfield(typs[3])}, []*Node{anonfield(typs[15])})
typs[94] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[83])}, []*Node{anonfield(typs[15])})
typs[95] = types.NewPtr(typs[15])
typs[96] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[95]), anonfield(typs[83])}, []*Node{anonfield(typs[15])})
typs[97] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[11])}, []*Node{anonfield(typs[11]), anonfield(typs[15])})
typs[98] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[11]), anonfield(typs[11])}, []*Node{anonfield(typs[56])})
typs[99] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[19]), anonfield(typs[19])}, []*Node{anonfield(typs[56])})
typs[100] = types.NewSlice(typs[2])
typs[101] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[100]), anonfield(typs[11])}, []*Node{anonfield(typs[100])})
typs[102] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[50])}, nil)
typs[103] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[50])}, nil)
typs[104] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[50])}, []*Node{anonfield(typs[15])})
typs[105] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[15])})
typs[106] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[56])}, []*Node{anonfield(typs[15])})
typs[107] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[50]), anonfield(typs[50])}, []*Node{anonfield(typs[50])})
typs[108] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[50])}, []*Node{anonfield(typs[50])})
typs[109] = functype(nil, []*Node{anonfield(typs[19]), anonfield(typs[19])}, []*Node{anonfield(typs[19])})
typs[110] = functype(nil, []*Node{anonfield(typs[21]), anonfield(typs[21])}, []*Node{anonfield(typs[21])})
typs[111] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[19])})
typs[112] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[21])})
typs[113] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[64])})
typs[114] = functype(nil, []*Node{anonfield(typs[19])}, []*Node{anonfield(typs[17])})
typs[115] = functype(nil, []*Node{anonfield(typs[21])}, []*Node{anonfield(typs[17])})
typs[116] = functype(nil, []*Node{anonfield(typs[64])}, []*Node{anonfield(typs[17])})
typs[117] = functype(nil, []*Node{anonfield(typs[23]), anonfield(typs[23])}, []*Node{anonfield(typs[23])})
typs[118] = functype(nil, []*Node{anonfield(typs[50])}, nil)
typs[119] = functype(nil, []*Node{anonfield(typs[50]), anonfield(typs[50])}, nil)
typs[120] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[1]), anonfield(typs[50])}, nil)
typs[121] = types.NewSlice(typs[56])
typs[122] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[121])}, nil)
typs[123] = types.Types[TUINT8]
typs[124] = functype(nil, []*Node{anonfield(typs[123]), anonfield(typs[123])}, nil)
typs[125] = types.Types[TUINT16]
typs[5] = types.Types[TUINTPTR]
typs[6] = types.Types[TBOOL]
typs[7] = types.Types[TUNSAFEPTR]
typs[8] = functype(nil, []*Node{anonfield(typs[5]), anonfield(typs[1]), anonfield(typs[6])}, []*Node{anonfield(typs[7])})
typs[9] = functype(nil, nil, nil)
typs[10] = types.Types[TINTER]
typs[11] = functype(nil, []*Node{anonfield(typs[10])}, nil)
typs[12] = types.Types[TINT32]
typs[13] = types.NewPtr(typs[12])
typs[14] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[10])})
typs[15] = types.Types[TINT]
typs[16] = functype(nil, []*Node{anonfield(typs[15]), anonfield(typs[15])}, nil)
typs[17] = types.Types[TUINT]
typs[18] = functype(nil, []*Node{anonfield(typs[17]), anonfield(typs[15])}, nil)
typs[19] = functype(nil, []*Node{anonfield(typs[6])}, nil)
typs[20] = types.Types[TFLOAT64]
typs[21] = functype(nil, []*Node{anonfield(typs[20])}, nil)
typs[22] = types.Types[TINT64]
typs[23] = functype(nil, []*Node{anonfield(typs[22])}, nil)
typs[24] = types.Types[TUINT64]
typs[25] = functype(nil, []*Node{anonfield(typs[24])}, nil)
typs[26] = types.Types[TCOMPLEX128]
typs[27] = functype(nil, []*Node{anonfield(typs[26])}, nil)
typs[28] = types.Types[TSTRING]
typs[29] = functype(nil, []*Node{anonfield(typs[28])}, nil)
typs[30] = functype(nil, []*Node{anonfield(typs[2])}, nil)
typs[31] = types.NewArray(typs[0], 32)
typs[32] = types.NewPtr(typs[31])
typs[33] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
typs[34] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
typs[35] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
typs[36] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
typs[37] = types.NewSlice(typs[28])
typs[38] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[37])}, []*Node{anonfield(typs[28])})
typs[39] = functype(nil, []*Node{anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[15])})
typs[40] = types.NewArray(typs[0], 4)
typs[41] = types.NewPtr(typs[40])
typs[42] = functype(nil, []*Node{anonfield(typs[41]), anonfield(typs[22])}, []*Node{anonfield(typs[28])})
typs[43] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[28])})
typs[44] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[28])})
typs[45] = types.Runetype
typs[46] = types.NewSlice(typs[45])
typs[47] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[46])}, []*Node{anonfield(typs[28])})
typs[48] = types.NewSlice(typs[0])
typs[49] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28])}, []*Node{anonfield(typs[48])})
typs[50] = types.NewArray(typs[45], 32)
typs[51] = types.NewPtr(typs[50])
typs[52] = functype(nil, []*Node{anonfield(typs[51]), anonfield(typs[28])}, []*Node{anonfield(typs[46])})
typs[53] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[5])}, []*Node{anonfield(typs[15])})
typs[54] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[28])}, []*Node{anonfield(typs[15])})
typs[55] = functype(nil, []*Node{anonfield(typs[28]), anonfield(typs[15])}, []*Node{anonfield(typs[45]), anonfield(typs[15])})
typs[56] = functype(nil, []*Node{anonfield(typs[28])}, []*Node{anonfield(typs[15])})
typs[57] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2])})
typs[58] = functype(nil, []*Node{anonfield(typs[2])}, []*Node{anonfield(typs[7])})
typs[59] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, []*Node{anonfield(typs[2])})
typs[60] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2]), anonfield(typs[6])})
typs[61] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil)
typs[62] = functype(nil, []*Node{anonfield(typs[1])}, nil)
typs[63] = types.NewPtr(typs[5])
typs[64] = functype(nil, []*Node{anonfield(typs[63]), anonfield(typs[7]), anonfield(typs[7])}, []*Node{anonfield(typs[6])})
typs[65] = types.Types[TUINT32]
typs[66] = functype(nil, nil, []*Node{anonfield(typs[65])})
typs[67] = types.NewMap(typs[2], typs[2])
typs[68] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[3])}, []*Node{anonfield(typs[67])})
typs[69] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[3])}, []*Node{anonfield(typs[67])})
typs[70] = functype(nil, nil, []*Node{anonfield(typs[67])})
typs[71] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, []*Node{anonfield(typs[3])})
typs[72] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, []*Node{anonfield(typs[3])})
typs[73] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3])})
typs[74] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
typs[75] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
typs[76] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
typs[77] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, nil)
typs[78] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, nil)
typs[79] = functype(nil, []*Node{anonfield(typs[3])}, nil)
typs[80] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67])}, nil)
typs[81] = types.NewChan(typs[2], types.Cboth)
typs[82] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22])}, []*Node{anonfield(typs[81])})
typs[83] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[81])})
typs[84] = types.NewChan(typs[2], types.Crecv)
typs[85] = functype(nil, []*Node{anonfield(typs[84]), anonfield(typs[3])}, nil)
typs[86] = functype(nil, []*Node{anonfield(typs[84]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
typs[87] = types.NewChan(typs[2], types.Csend)
typs[88] = functype(nil, []*Node{anonfield(typs[87]), anonfield(typs[3])}, nil)
typs[89] = types.NewArray(typs[0], 3)
typs[90] = tostruct([]*Node{namedfield("enabled", typs[6]), namedfield("pad", typs[89]), namedfield("needed", typs[6]), namedfield("cgo", typs[6]), namedfield("alignme", typs[24])})
typs[91] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil)
typs[92] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, nil)
typs[93] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[3]), anonfield(typs[15])}, []*Node{anonfield(typs[15])})
typs[94] = functype(nil, []*Node{anonfield(typs[87]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
typs[95] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[84])}, []*Node{anonfield(typs[6])})
typs[96] = types.NewPtr(typs[6])
typs[97] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[96]), anonfield(typs[84])}, []*Node{anonfield(typs[6])})
typs[98] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[15]), anonfield(typs[6])})
typs[99] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[7])})
typs[100] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[22])}, []*Node{anonfield(typs[7])})
typs[101] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15]), anonfield(typs[7])}, []*Node{anonfield(typs[7])})
typs[102] = types.NewSlice(typs[2])
typs[103] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[102]), anonfield(typs[15])}, []*Node{anonfield(typs[102])})
typs[104] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, nil)
typs[105] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5])}, nil)
typs[106] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, []*Node{anonfield(typs[6])})
typs[107] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
typs[108] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[7])}, []*Node{anonfield(typs[6])})
typs[109] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5]), anonfield(typs[5])}, []*Node{anonfield(typs[5])})
typs[110] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5])}, []*Node{anonfield(typs[5])})
typs[111] = functype(nil, []*Node{anonfield(typs[22]), anonfield(typs[22])}, []*Node{anonfield(typs[22])})
typs[112] = functype(nil, []*Node{anonfield(typs[24]), anonfield(typs[24])}, []*Node{anonfield(typs[24])})
typs[113] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[22])})
typs[114] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[24])})
typs[115] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[65])})
typs[116] = functype(nil, []*Node{anonfield(typs[22])}, []*Node{anonfield(typs[20])})
typs[117] = functype(nil, []*Node{anonfield(typs[24])}, []*Node{anonfield(typs[20])})
typs[118] = functype(nil, []*Node{anonfield(typs[65])}, []*Node{anonfield(typs[20])})
typs[119] = functype(nil, []*Node{anonfield(typs[26]), anonfield(typs[26])}, []*Node{anonfield(typs[26])})
typs[120] = functype(nil, []*Node{anonfield(typs[5])}, nil)
typs[121] = functype(nil, []*Node{anonfield(typs[5]), anonfield(typs[5])}, nil)
typs[122] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[1]), anonfield(typs[5])}, nil)
typs[123] = types.NewSlice(typs[7])
typs[124] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[123])}, nil)
typs[125] = types.Types[TUINT8]
typs[126] = functype(nil, []*Node{anonfield(typs[125]), anonfield(typs[125])}, nil)
typs[127] = functype(nil, []*Node{anonfield(typs[64]), anonfield(typs[64])}, nil)
typs[128] = functype(nil, []*Node{anonfield(typs[21]), anonfield(typs[21])}, nil)
typs[127] = types.Types[TUINT16]
typs[128] = functype(nil, []*Node{anonfield(typs[127]), anonfield(typs[127])}, nil)
typs[129] = functype(nil, []*Node{anonfield(typs[65]), anonfield(typs[65])}, nil)
typs[130] = functype(nil, []*Node{anonfield(typs[24]), anonfield(typs[24])}, nil)
return typs[:]
}

View file

@ -15,6 +15,7 @@ package runtime
import "unsafe"
func newobject(typ *byte) *any
func mallocgc(size uintptr, typ *byte, needszero bool) unsafe.Pointer
func panicdivide()
func panicshift()
func panicmakeslicelen()
@ -174,6 +175,7 @@ func block()
func makeslice(typ *byte, len int, cap int) unsafe.Pointer
func makeslice64(typ *byte, len int64, cap int64) unsafe.Pointer
func makeslicecopy(typ *byte, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer
func growslice(typ *byte, old []any, cap int) (ary []any)
func memmove(to *any, frm *any, length uintptr)
func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)

View file

@ -141,13 +141,13 @@ func isSelfAssign(dst, src *Node) bool {
return samesafeexpr(dst.Left, src.Left)
}
// mayAffectMemory reports whether n evaluation may affect program memory state.
// If expression can't affect it, then it can be safely ignored by the escape analysis.
// mayAffectMemory reports whether evaluation of n may affect the program's
// memory state. If the expression can't affect memory state, then it can be
// safely ignored by the escape analysis.
func mayAffectMemory(n *Node) bool {
// We may want to use "memory safe" black list instead of general
// "side-effect free", which can include all calls and other ops
// that can affect allocate or change global state.
// It's safer to start from a whitelist for now.
// We may want to use a list of "memory safe" ops instead of generally
// "side-effect free", which would include all calls and other ops that can
// allocate or change global state. For now, it's safer to start with the latter.
//
// We're ignoring things like division by zero, index out of range,
// and nil pointer dereference here.

View file

@ -1165,92 +1165,93 @@ func (n *Node) stmtfmt(s fmt.State, mode fmtMode) {
}
var opprec = []int{
OALIGNOF: 8,
OAPPEND: 8,
OBYTES2STR: 8,
OARRAYLIT: 8,
OSLICELIT: 8,
ORUNES2STR: 8,
OCALLFUNC: 8,
OCALLINTER: 8,
OCALLMETH: 8,
OCALL: 8,
OCAP: 8,
OCLOSE: 8,
OCONVIFACE: 8,
OCONVNOP: 8,
OCONV: 8,
OCOPY: 8,
ODELETE: 8,
OGETG: 8,
OLEN: 8,
OLITERAL: 8,
OMAKESLICE: 8,
OMAKE: 8,
OMAPLIT: 8,
ONAME: 8,
ONEW: 8,
ONONAME: 8,
OOFFSETOF: 8,
OPACK: 8,
OPANIC: 8,
OPAREN: 8,
OPRINTN: 8,
OPRINT: 8,
ORUNESTR: 8,
OSIZEOF: 8,
OSTR2BYTES: 8,
OSTR2RUNES: 8,
OSTRUCTLIT: 8,
OTARRAY: 8,
OTCHAN: 8,
OTFUNC: 8,
OTINTER: 8,
OTMAP: 8,
OTSTRUCT: 8,
OINDEXMAP: 8,
OINDEX: 8,
OSLICE: 8,
OSLICESTR: 8,
OSLICEARR: 8,
OSLICE3: 8,
OSLICE3ARR: 8,
OSLICEHEADER: 8,
ODOTINTER: 8,
ODOTMETH: 8,
ODOTPTR: 8,
ODOTTYPE2: 8,
ODOTTYPE: 8,
ODOT: 8,
OXDOT: 8,
OCALLPART: 8,
OPLUS: 7,
ONOT: 7,
OBITNOT: 7,
ONEG: 7,
OADDR: 7,
ODEREF: 7,
ORECV: 7,
OMUL: 6,
ODIV: 6,
OMOD: 6,
OLSH: 6,
ORSH: 6,
OAND: 6,
OANDNOT: 6,
OADD: 5,
OSUB: 5,
OOR: 5,
OXOR: 5,
OEQ: 4,
OLT: 4,
OLE: 4,
OGE: 4,
OGT: 4,
ONE: 4,
OSEND: 3,
OANDAND: 2,
OOROR: 1,
OALIGNOF: 8,
OAPPEND: 8,
OBYTES2STR: 8,
OARRAYLIT: 8,
OSLICELIT: 8,
ORUNES2STR: 8,
OCALLFUNC: 8,
OCALLINTER: 8,
OCALLMETH: 8,
OCALL: 8,
OCAP: 8,
OCLOSE: 8,
OCONVIFACE: 8,
OCONVNOP: 8,
OCONV: 8,
OCOPY: 8,
ODELETE: 8,
OGETG: 8,
OLEN: 8,
OLITERAL: 8,
OMAKESLICE: 8,
OMAKESLICECOPY: 8,
OMAKE: 8,
OMAPLIT: 8,
ONAME: 8,
ONEW: 8,
ONONAME: 8,
OOFFSETOF: 8,
OPACK: 8,
OPANIC: 8,
OPAREN: 8,
OPRINTN: 8,
OPRINT: 8,
ORUNESTR: 8,
OSIZEOF: 8,
OSTR2BYTES: 8,
OSTR2RUNES: 8,
OSTRUCTLIT: 8,
OTARRAY: 8,
OTCHAN: 8,
OTFUNC: 8,
OTINTER: 8,
OTMAP: 8,
OTSTRUCT: 8,
OINDEXMAP: 8,
OINDEX: 8,
OSLICE: 8,
OSLICESTR: 8,
OSLICEARR: 8,
OSLICE3: 8,
OSLICE3ARR: 8,
OSLICEHEADER: 8,
ODOTINTER: 8,
ODOTMETH: 8,
ODOTPTR: 8,
ODOTTYPE2: 8,
ODOTTYPE: 8,
ODOT: 8,
OXDOT: 8,
OCALLPART: 8,
OPLUS: 7,
ONOT: 7,
OBITNOT: 7,
ONEG: 7,
OADDR: 7,
ODEREF: 7,
ORECV: 7,
OMUL: 6,
ODIV: 6,
OMOD: 6,
OLSH: 6,
ORSH: 6,
OAND: 6,
OANDNOT: 6,
OADD: 5,
OSUB: 5,
OOR: 5,
OXOR: 5,
OEQ: 4,
OLT: 4,
OLE: 4,
OGE: 4,
OGT: 4,
ONE: 4,
OSEND: 3,
OANDAND: 2,
OOROR: 1,
// Statements handled by stmtfmt
OAS: -1,
@ -1572,6 +1573,9 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
}
mode.Fprintf(s, "make(%v)", n.Type)
case OMAKESLICECOPY:
mode.Fprintf(s, "makeslicecopy(%v, %v, %v)", n.Type, n.Left, n.Right)
case OPLUS, ONEG, OADDR, OBITNOT, ODEREF, ONOT, ORECV:
// Unary
mode.Fprintf(s, "%#v", n.Op)

View file

@ -1,5 +1,5 @@
// Derived from Inferno utils/6c/txt.c
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6c/txt.c
// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6c/txt.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)

View file

@ -44,7 +44,7 @@ func parseFiles(filenames []string) uint {
f, err := os.Open(filename)
if err != nil {
p.error(syntax.Error{Pos: syntax.MakePos(base, 0, 0), Msg: err.Error()})
p.error(syntax.Error{Msg: err.Error()})
return
}
defer f.Close()

View file

@ -82,89 +82,90 @@ func _() {
_ = x[OMAKECHAN-71]
_ = x[OMAKEMAP-72]
_ = x[OMAKESLICE-73]
_ = x[OMUL-74]
_ = x[ODIV-75]
_ = x[OMOD-76]
_ = x[OLSH-77]
_ = x[ORSH-78]
_ = x[OAND-79]
_ = x[OANDNOT-80]
_ = x[ONEW-81]
_ = x[ONEWOBJ-82]
_ = x[ONOT-83]
_ = x[OBITNOT-84]
_ = x[OPLUS-85]
_ = x[ONEG-86]
_ = x[OOROR-87]
_ = x[OPANIC-88]
_ = x[OPRINT-89]
_ = x[OPRINTN-90]
_ = x[OPAREN-91]
_ = x[OSEND-92]
_ = x[OSLICE-93]
_ = x[OSLICEARR-94]
_ = x[OSLICESTR-95]
_ = x[OSLICE3-96]
_ = x[OSLICE3ARR-97]
_ = x[OSLICEHEADER-98]
_ = x[ORECOVER-99]
_ = x[ORECV-100]
_ = x[ORUNESTR-101]
_ = x[OSELRECV-102]
_ = x[OSELRECV2-103]
_ = x[OIOTA-104]
_ = x[OREAL-105]
_ = x[OIMAG-106]
_ = x[OCOMPLEX-107]
_ = x[OALIGNOF-108]
_ = x[OOFFSETOF-109]
_ = x[OSIZEOF-110]
_ = x[OBLOCK-111]
_ = x[OBREAK-112]
_ = x[OCASE-113]
_ = x[OCONTINUE-114]
_ = x[ODEFER-115]
_ = x[OEMPTY-116]
_ = x[OFALL-117]
_ = x[OFOR-118]
_ = x[OFORUNTIL-119]
_ = x[OGOTO-120]
_ = x[OIF-121]
_ = x[OLABEL-122]
_ = x[OGO-123]
_ = x[ORANGE-124]
_ = x[ORETURN-125]
_ = x[OSELECT-126]
_ = x[OSWITCH-127]
_ = x[OTYPESW-128]
_ = x[OTCHAN-129]
_ = x[OTMAP-130]
_ = x[OTSTRUCT-131]
_ = x[OTINTER-132]
_ = x[OTFUNC-133]
_ = x[OTARRAY-134]
_ = x[ODDD-135]
_ = x[OINLCALL-136]
_ = x[OEFACE-137]
_ = x[OITAB-138]
_ = x[OIDATA-139]
_ = x[OSPTR-140]
_ = x[OCLOSUREVAR-141]
_ = x[OCFUNC-142]
_ = x[OCHECKNIL-143]
_ = x[OVARDEF-144]
_ = x[OVARKILL-145]
_ = x[OVARLIVE-146]
_ = x[ORESULT-147]
_ = x[OINLMARK-148]
_ = x[ORETJMP-149]
_ = x[OGETG-150]
_ = x[OEND-151]
_ = x[OMAKESLICECOPY-74]
_ = x[OMUL-75]
_ = x[ODIV-76]
_ = x[OMOD-77]
_ = x[OLSH-78]
_ = x[ORSH-79]
_ = x[OAND-80]
_ = x[OANDNOT-81]
_ = x[ONEW-82]
_ = x[ONEWOBJ-83]
_ = x[ONOT-84]
_ = x[OBITNOT-85]
_ = x[OPLUS-86]
_ = x[ONEG-87]
_ = x[OOROR-88]
_ = x[OPANIC-89]
_ = x[OPRINT-90]
_ = x[OPRINTN-91]
_ = x[OPAREN-92]
_ = x[OSEND-93]
_ = x[OSLICE-94]
_ = x[OSLICEARR-95]
_ = x[OSLICESTR-96]
_ = x[OSLICE3-97]
_ = x[OSLICE3ARR-98]
_ = x[OSLICEHEADER-99]
_ = x[ORECOVER-100]
_ = x[ORECV-101]
_ = x[ORUNESTR-102]
_ = x[OSELRECV-103]
_ = x[OSELRECV2-104]
_ = x[OIOTA-105]
_ = x[OREAL-106]
_ = x[OIMAG-107]
_ = x[OCOMPLEX-108]
_ = x[OALIGNOF-109]
_ = x[OOFFSETOF-110]
_ = x[OSIZEOF-111]
_ = x[OBLOCK-112]
_ = x[OBREAK-113]
_ = x[OCASE-114]
_ = x[OCONTINUE-115]
_ = x[ODEFER-116]
_ = x[OEMPTY-117]
_ = x[OFALL-118]
_ = x[OFOR-119]
_ = x[OFORUNTIL-120]
_ = x[OGOTO-121]
_ = x[OIF-122]
_ = x[OLABEL-123]
_ = x[OGO-124]
_ = x[ORANGE-125]
_ = x[ORETURN-126]
_ = x[OSELECT-127]
_ = x[OSWITCH-128]
_ = x[OTYPESW-129]
_ = x[OTCHAN-130]
_ = x[OTMAP-131]
_ = x[OTSTRUCT-132]
_ = x[OTINTER-133]
_ = x[OTFUNC-134]
_ = x[OTARRAY-135]
_ = x[ODDD-136]
_ = x[OINLCALL-137]
_ = x[OEFACE-138]
_ = x[OITAB-139]
_ = x[OIDATA-140]
_ = x[OSPTR-141]
_ = x[OCLOSUREVAR-142]
_ = x[OCFUNC-143]
_ = x[OCHECKNIL-144]
_ = x[OVARDEF-145]
_ = x[OVARKILL-146]
_ = x[OVARLIVE-147]
_ = x[ORESULT-148]
_ = x[OINLMARK-149]
_ = x[ORETJMP-150]
_ = x[OGETG-151]
_ = x[OEND-152]
}
const _Op_name = "XXXNAMENONAMETYPEPACKLITERALADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCALLPARTCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDCLFIELDDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMULDIVMODLSHRSHANDANDNOTNEWNEWOBJNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECVRUNESTRSELRECVSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFBLOCKBREAKCASECONTINUEDEFEREMPTYFALLFORFORUNTILGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWTCHANTMAPTSTRUCTTINTERTFUNCTARRAYDDDINLCALLEFACEITABIDATASPTRCLOSUREVARCFUNCCHECKNILVARDEFVARKILLVARLIVERESULTINLMARKRETJMPGETGEND"
const _Op_name = "XXXNAMENONAMETYPEPACKLITERALADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCALLPARTCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDCLFIELDDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNEWOBJNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECVRUNESTRSELRECVSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFBLOCKBREAKCASECONTINUEDEFEREMPTYFALLFORFORUNTILGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWTCHANTMAPTSTRUCTTINTERTFUNCTARRAYDDDINLCALLEFACEITABIDATASPTRCLOSUREVARCFUNCCHECKNILVARDEFVARKILLVARLIVERESULTINLMARKRETJMPGETGEND"
var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 36, 39, 45, 49, 55, 61, 70, 82, 91, 100, 112, 121, 123, 126, 136, 143, 150, 157, 161, 165, 173, 181, 190, 198, 201, 206, 213, 220, 226, 235, 243, 251, 257, 261, 270, 277, 281, 284, 291, 299, 307, 314, 320, 323, 329, 336, 344, 348, 355, 363, 365, 367, 369, 371, 373, 375, 380, 385, 393, 396, 405, 408, 412, 420, 427, 436, 439, 442, 445, 448, 451, 454, 460, 463, 469, 472, 478, 482, 485, 489, 494, 499, 505, 510, 514, 519, 527, 535, 541, 550, 561, 568, 572, 579, 586, 594, 598, 602, 606, 613, 620, 628, 634, 639, 644, 648, 656, 661, 666, 670, 673, 681, 685, 687, 692, 694, 699, 705, 711, 717, 723, 728, 732, 739, 745, 750, 756, 759, 766, 771, 775, 780, 784, 794, 799, 807, 813, 820, 827, 833, 840, 846, 850, 853}
var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 36, 39, 45, 49, 55, 61, 70, 82, 91, 100, 112, 121, 123, 126, 136, 143, 150, 157, 161, 165, 173, 181, 190, 198, 201, 206, 213, 220, 226, 235, 243, 251, 257, 261, 270, 277, 281, 284, 291, 299, 307, 314, 320, 323, 329, 336, 344, 348, 355, 363, 365, 367, 369, 371, 373, 375, 380, 385, 393, 396, 405, 408, 412, 420, 427, 436, 449, 452, 455, 458, 461, 464, 467, 473, 476, 482, 485, 491, 495, 498, 502, 507, 512, 518, 523, 527, 532, 540, 548, 554, 563, 574, 581, 585, 592, 599, 607, 611, 615, 619, 626, 633, 641, 647, 652, 657, 661, 669, 674, 679, 683, 686, 694, 698, 700, 705, 707, 712, 718, 724, 730, 736, 741, 745, 752, 758, 763, 769, 772, 779, 784, 788, 793, 797, 807, 812, 820, 826, 833, 840, 846, 853, 859, 863, 866}
func (i Op) String() string {
if i >= Op(len(_Op_index)-1) {

View file

@ -319,11 +319,82 @@ func (o *Order) cleanTemp(top ordermarker) {
// stmtList orders each of the statements in the list.
func (o *Order) stmtList(l Nodes) {
for _, n := range l.Slice() {
o.stmt(n)
s := l.Slice()
for i := range s {
orderMakeSliceCopy(s[i:])
o.stmt(s[i])
}
}
// orderMakeSliceCopy matches the pattern:
// m = OMAKESLICE([]T, x); OCOPY(m, s)
// and rewrites it to:
// m = OMAKESLICECOPY([]T, x, s); nil
func orderMakeSliceCopy(s []*Node) {
const go115makeslicecopy = true
if !go115makeslicecopy {
return
}
if Debug['N'] != 0 || instrumenting {
return
}
if len(s) < 2 {
return
}
asn := s[0]
copyn := s[1]
if asn == nil || asn.Op != OAS {
return
}
if asn.Left.Op != ONAME {
return
}
if asn.Left.isBlank() {
return
}
maken := asn.Right
if maken == nil || maken.Op != OMAKESLICE {
return
}
if maken.Esc == EscNone {
return
}
if maken.Left == nil || maken.Right != nil {
return
}
if copyn.Op != OCOPY {
return
}
if copyn.Left.Op != ONAME {
return
}
if asn.Left.Sym != copyn.Left.Sym {
return
}
if copyn.Right.Op != ONAME {
return
}
if copyn.Left.Sym == copyn.Right.Sym {
return
}
maken.Op = OMAKESLICECOPY
maken.Right = copyn.Right
// Set bounded when m = OMAKESLICE([]T, len(s)); OCOPY(m, s)
maken.SetBounded(maken.Left.Op == OLEN && samesafeexpr(maken.Left.Left, copyn.Right))
maken = typecheck(maken, ctxExpr)
s[1] = nil // remove separate copy call
return
}
// edge inserts coverage instrumentation for libfuzzer.
func (o *Order) edge() {
if Debug_libfuzzer == 0 {
@ -1150,6 +1221,7 @@ func (o *Order) expr(n, lhs *Node) *Node {
OMAKECHAN,
OMAKEMAP,
OMAKESLICE,
OMAKESLICECOPY,
ONEW,
OREAL,
ORECOVER,

View file

@ -271,7 +271,7 @@ func compile(fn *Node) {
}
}
if compilenow() {
if compilenow(fn) {
compileSSA(fn, 0)
} else {
compilequeue = append(compilequeue, fn)
@ -282,10 +282,31 @@ func compile(fn *Node) {
// If functions are not compiled immediately,
// they are enqueued in compilequeue,
// which is drained by compileFunctions.
func compilenow() bool {
func compilenow(fn *Node) bool {
// Issue 38068: if this function is a method AND an inline
// candidate AND was not inlined (yet), put it onto the compile
// queue instead of compiling it immediately. This is in case we
// wind up inlining it into a method wrapper that is generated by
// compiling a function later on in the xtop list.
if fn.IsMethod() && isInlinableButNotInlined(fn) {
return false
}
return nBackendWorkers == 1 && Debug_compilelater == 0
}
// isInlinableButNotInlined returns true if 'fn' was marked as an
// inline candidate but then never inlined (presumably because we
// found no call sites).
func isInlinableButNotInlined(fn *Node) bool {
if fn.Func.Nname.Func.Inl == nil {
return false
}
if fn.Sym == nil {
return true
}
return !fn.Sym.Linksym().WasInlined()
}
const maxStackSize = 1 << 30
// compileSSA builds an SSA backend function,

View file

@ -680,8 +680,9 @@ func (lv *Liveness) pointerMap(liveout bvec, vars []*Node, args, locals bvec) {
}
}
// markUnsafePoints finds unsafe points and computes lv.unsafePoints.
func (lv *Liveness) markUnsafePoints() {
// allUnsafe indicates that all points in this function are
// unsafe-points.
func allUnsafe(f *ssa.Func) bool {
// The runtime assumes the only safe-points are function
// prologues (because that's how it used to be). We could and
// should improve that, but for now keep consider all points
@ -691,7 +692,12 @@ func (lv *Liveness) markUnsafePoints() {
// go:nosplit functions are similar. Since safe points used to
// be coupled with stack checks, go:nosplit often actually
// means "no safe points in this function".
if compiling_runtime || lv.f.NoSplit {
return compiling_runtime || f.NoSplit
}
// markUnsafePoints finds unsafe points and computes lv.unsafePoints.
func (lv *Liveness) markUnsafePoints() {
if allUnsafe(lv.f) {
// No complex analysis necessary.
lv.allUnsafe = true
return
@ -1249,7 +1255,7 @@ func (lv *Liveness) compact(b *ssa.Block) {
if go115ReduceLiveness {
hasStackMap := lv.hasStackMap(v)
isUnsafePoint := lv.allUnsafe || lv.unsafePoints.Get(int32(v.ID))
idx := LivenessIndex{StackMapDontCare, 0, isUnsafePoint}
idx := LivenessIndex{StackMapDontCare, StackMapDontCare, isUnsafePoint}
if hasStackMap {
idx.stackMapIndex = lv.stackMapSet.add(lv.livevars[pos].vars)
pos++

View file

@ -60,3 +60,53 @@ func TestReproducibleBuilds(t *testing.T) {
})
}
}
func TestIssue38068(t *testing.T) {
testenv.MustHaveGoBuild(t)
t.Parallel()
// Compile a small package with and without the concurrent
// backend, then check to make sure that the resulting archives
// are identical. Note: this uses "go tool compile" instead of
// "go build" since the latter will generate differnent build IDs
// if it sees different command line flags.
scenarios := []struct {
tag string
args string
libpath string
}{
{tag: "serial", args: "-c=1"},
{tag: "concurrent", args: "-c=2"}}
tmpdir, err := ioutil.TempDir("", "TestIssue38068")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
src := filepath.Join("testdata", "reproducible", "issue38068.go")
for i := range scenarios {
s := &scenarios[i]
s.libpath = filepath.Join(tmpdir, s.tag+".a")
// Note: use of "-p" required in order for DWARF to be generated.
cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-trimpath", "-p=issue38068", "-buildid=", s.args, "-o", s.libpath, src)
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("%v: %v:\n%s", cmd.Args, err, out)
}
}
readBytes := func(fn string) []byte {
payload, err := ioutil.ReadFile(fn)
if err != nil {
t.Fatalf("failed to read executable '%s': %v", fn, err)
}
return payload
}
b1 := readBytes(scenarios[0].libpath)
b2 := readBytes(scenarios[1].libpath)
if !bytes.Equal(b1, b2) {
t.Fatalf("concurrent and serial builds produced different output")
}
}

View file

@ -6010,8 +6010,8 @@ func genssa(f *ssa.Func, pp *Progs) {
// for an empty block this will be used for its control
// instruction. We won't use the actual liveness map on a
// control instruction. Just mark it something that is
// preemptible.
s.pp.nextLive = LivenessIndex{-1, -1, false}
// preemptible, unless this function is "all unsafe".
s.pp.nextLive = LivenessIndex{-1, -1, allUnsafe(f)}
// Emit values in block
thearch.SSAMarkMoves(&s, b)
@ -6313,34 +6313,39 @@ func defframe(s *SSAGenState, e *ssafn) {
thearch.ZeroRange(pp, p, frame+lo, hi-lo, &state)
}
type FloatingEQNEJump struct {
// For generating consecutive jump instructions to model a specific branching
type IndexJump struct {
Jump obj.As
Index int
}
func (s *SSAGenState) oneFPJump(b *ssa.Block, jumps *FloatingEQNEJump) {
p := s.Prog(jumps.Jump)
p.To.Type = obj.TYPE_BRANCH
func (s *SSAGenState) oneJump(b *ssa.Block, jump *IndexJump) {
p := s.Br(jump.Jump, b.Succs[jump.Index].Block())
p.Pos = b.Pos
to := jumps.Index
s.Branches = append(s.Branches, Branch{p, b.Succs[to].Block()})
}
func (s *SSAGenState) FPJump(b, next *ssa.Block, jumps *[2][2]FloatingEQNEJump) {
// CombJump generates combinational instructions (2 at present) for a block jump,
// thereby the behaviour of non-standard condition codes could be simulated
func (s *SSAGenState) CombJump(b, next *ssa.Block, jumps *[2][2]IndexJump) {
switch next {
case b.Succs[0].Block():
s.oneFPJump(b, &jumps[0][0])
s.oneFPJump(b, &jumps[0][1])
s.oneJump(b, &jumps[0][0])
s.oneJump(b, &jumps[0][1])
case b.Succs[1].Block():
s.oneFPJump(b, &jumps[1][0])
s.oneFPJump(b, &jumps[1][1])
s.oneJump(b, &jumps[1][0])
s.oneJump(b, &jumps[1][1])
default:
s.oneFPJump(b, &jumps[1][0])
s.oneFPJump(b, &jumps[1][1])
q := s.Prog(obj.AJMP)
var q *obj.Prog
if b.Likely != ssa.BranchUnlikely {
s.oneJump(b, &jumps[1][0])
s.oneJump(b, &jumps[1][1])
q = s.Br(obj.AJMP, b.Succs[1].Block())
} else {
s.oneJump(b, &jumps[0][0])
s.oneJump(b, &jumps[0][1])
q = s.Br(obj.AJMP, b.Succs[0].Block())
}
q.Pos = b.Pos
q.To.Type = obj.TYPE_BRANCH
s.Branches = append(s.Branches, Branch{q, b.Succs[1].Block()})
}
}

View file

@ -60,9 +60,15 @@ func adderrorname(n *Node) {
}
func adderr(pos src.XPos, format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
// Only add the position if know the position.
// See issue golang.org/issue/11361.
if pos.IsKnown() {
msg = fmt.Sprintf("%v: %s", linestr(pos), msg)
}
errors = append(errors, Error{
pos: pos,
msg: fmt.Sprintf("%v: %s\n", linestr(pos), fmt.Sprintf(format, args...)),
msg: msg + "\n",
})
}

View file

@ -208,12 +208,16 @@ func (n *Node) MarkNonNil() {
// SetBounded indicates whether operation n does not need safety checks.
// When n is an index or slice operation, n does not need bounds checks.
// When n is a dereferencing operation, n does not need nil checks.
// When n is a makeslice+copy operation, n does not need length and cap checks.
func (n *Node) SetBounded(b bool) {
switch n.Op {
case OINDEX, OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR:
// No bounds checks needed.
case ODOTPTR, ODEREF:
// No nil check needed.
case OMAKESLICECOPY:
// No length and cap checks needed
// since new slice and copied over slice data have same length.
default:
Fatalf("SetBounded(%v)", n)
}
@ -714,30 +718,38 @@ const (
ODCLCONST // const pi = 3.14
ODCLTYPE // type Int int or type Int = int
ODELETE // delete(Left, Right)
ODOT // Left.Sym (Left is of struct type)
ODOTPTR // Left.Sym (Left is of pointer to struct type)
ODOTMETH // Left.Sym (Left is non-interface, Right is method name)
ODOTINTER // Left.Sym (Left is interface, Right is method name)
OXDOT // Left.Sym (before rewrite to one of the preceding)
ODOTTYPE // Left.Right or Left.Type (.Right during parsing, .Type once resolved); after walk, .Right contains address of interface type descriptor and .Right.Right contains address of concrete type descriptor
ODOTTYPE2 // Left.Right or Left.Type (.Right during parsing, .Type once resolved; on rhs of OAS2DOTTYPE); after walk, .Right contains address of interface type descriptor
OEQ // Left == Right
ONE // Left != Right
OLT // Left < Right
OLE // Left <= Right
OGE // Left >= Right
OGT // Left > Right
ODEREF // *Left
OINDEX // Left[Right] (index of array or slice)
OINDEXMAP // Left[Right] (index of map)
OKEY // Left:Right (key:value in struct/array/map literal)
OSTRUCTKEY // Sym:Left (key:value in struct literal, after type checking)
OLEN // len(Left)
OMAKE // make(List) (before type checking converts to one of the following)
OMAKECHAN // make(Type, Left) (type is chan)
OMAKEMAP // make(Type, Left) (type is map)
OMAKESLICE // make(Type, Left, Right) (type is slice)
ODELETE // delete(Left, Right)
ODOT // Left.Sym (Left is of struct type)
ODOTPTR // Left.Sym (Left is of pointer to struct type)
ODOTMETH // Left.Sym (Left is non-interface, Right is method name)
ODOTINTER // Left.Sym (Left is interface, Right is method name)
OXDOT // Left.Sym (before rewrite to one of the preceding)
ODOTTYPE // Left.Right or Left.Type (.Right during parsing, .Type once resolved); after walk, .Right contains address of interface type descriptor and .Right.Right contains address of concrete type descriptor
ODOTTYPE2 // Left.Right or Left.Type (.Right during parsing, .Type once resolved; on rhs of OAS2DOTTYPE); after walk, .Right contains address of interface type descriptor
OEQ // Left == Right
ONE // Left != Right
OLT // Left < Right
OLE // Left <= Right
OGE // Left >= Right
OGT // Left > Right
ODEREF // *Left
OINDEX // Left[Right] (index of array or slice)
OINDEXMAP // Left[Right] (index of map)
OKEY // Left:Right (key:value in struct/array/map literal)
OSTRUCTKEY // Sym:Left (key:value in struct literal, after type checking)
OLEN // len(Left)
OMAKE // make(List) (before type checking converts to one of the following)
OMAKECHAN // make(Type, Left) (type is chan)
OMAKEMAP // make(Type, Left) (type is map)
OMAKESLICE // make(Type, Left, Right) (type is slice)
OMAKESLICECOPY // makeslicecopy(Type, Left, Right) (type is slice; Left is length and Right is the copied from slice)
// OMAKESLICECOPY is created by the order pass and corresponds to:
// s = make(Type, Left); copy(s, Right)
//
// Bounded can be set on the node when Left == len(Right) is known at compile time.
//
// This node is created so the walk pass can optimize this pattern which would
// otherwise be hard to detect after the order pass.
OMUL // Left * Right
ODIV // Left / Right
OMOD // Left % Right

View file

@ -0,0 +1,70 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package issue38068
// A type with a couple of inlinable, non-pointer-receiver methods
// that have params and local variables.
type A struct {
s string
next *A
prev *A
}
// Inlinable, value-received method with locals and parms.
func (a A) double(x string, y int) string {
if y == 191 {
a.s = ""
}
q := a.s + "a"
r := a.s + "b"
return q + r
}
// Inlinable, value-received method with locals and parms.
func (a A) triple(x string, y int) string {
q := a.s
if y == 998877 {
a.s = x
}
r := a.s + a.s
return q + r
}
type methods struct {
m1 func(a *A, x string, y int) string
m2 func(a *A, x string, y int) string
}
// Now a function that makes references to the methods via pointers,
// which should trigger the wrapper generation.
func P(a *A, ms *methods) {
if a != nil {
defer func() { println("done") }()
}
println(ms.m1(a, "a", 2))
println(ms.m2(a, "b", 3))
}
func G(x *A, n int) {
if n <= 0 {
println(n)
return
}
// Address-taken local of type A, which will insure that the
// compiler's dtypesym() routine will create a method wrapper.
var a, b A
a.next = x
a.prev = &b
x = &a
G(x, n-2)
}
var M methods
func F() {
M.m1 = (*A).double
M.m2 = (*A).triple
G(nil, 100)
}

View file

@ -1149,6 +1149,49 @@ func typecheck1(n *Node, top int) (res *Node) {
n.List.SetFirst(l)
n.List.SetSecond(c)
case OMAKESLICECOPY:
// Errors here are Fatalf instead of yyerror because only the compiler
// can construct an OMAKESLICECOPY node.
// Components used in OMAKESCLICECOPY that are supplied by parsed source code
// have already been typechecked in OMAKE and OCOPY earlier.
ok |= ctxExpr
t := n.Type
if t == nil {
Fatalf("no type specified for OMAKESLICECOPY")
}
if !t.IsSlice() {
Fatalf("invalid type %v for OMAKESLICECOPY", n.Type)
}
if n.Left == nil {
Fatalf("missing len argument for OMAKESLICECOPY")
}
if n.Right == nil {
Fatalf("missing slice argument to copy for OMAKESLICECOPY")
}
n.Left = typecheck(n.Left, ctxExpr)
n.Right = typecheck(n.Right, ctxExpr)
n.Left = defaultlit(n.Left, types.Types[TINT])
if !n.Left.Type.IsInteger() && n.Type.Etype != TIDEAL {
yyerror("non-integer len argument in OMAKESLICECOPY")
}
if Isconst(n.Left, CTINT) {
if n.Left.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 {
Fatalf("len for OMAKESLICECOPY too large")
}
if n.Left.Int64() < 0 {
Fatalf("len for OMAKESLICECOPY must be non-negative")
}
}
case OSLICE, OSLICE3:
ok |= ctxExpr
n.Left = typecheck(n.Left, ctxExpr)
@ -2924,6 +2967,8 @@ func typecheckcomplit(n *Node) (res *Node) {
if ci := lookdot1(nil, l.Sym, t, t.Fields(), 2); ci != nil { // Case-insensitive lookup.
if visible(ci.Sym) {
yyerror("unknown field '%v' in struct literal of type %v (but does have %v)", l.Sym, t, ci.Sym)
} else if nonexported(l.Sym) && l.Sym.Name == ci.Sym.Name { // Ensure exactness before the suggestion.
yyerror("cannot refer to unexported field '%v' in struct literal of type %v", l.Sym, t)
} else {
yyerror("unknown field '%v' in struct literal of type %v", l.Sym, t)
}
@ -3027,6 +3072,11 @@ func visible(sym *types.Sym) bool {
return sym != nil && (types.IsExported(sym.Name) || sym.Pkg == localpkg)
}
// nonexported reports whether sym is an unexported field.
func nonexported(sym *types.Sym) bool {
return sym != nil && !types.IsExported(sym.Name)
}
// lvalue etc
func islvalue(n *Node) bool {
switch n.Op {

View file

@ -1390,6 +1390,63 @@ opswitch:
n = m
}
case OMAKESLICECOPY:
if n.Esc == EscNone {
Fatalf("OMAKESLICECOPY with EscNone: %v", n)
}
t := n.Type
if t.Elem().NotInHeap() {
Fatalf("%v is go:notinheap; heap allocation disallowed", t.Elem())
}
length := conv(n.Left, types.Types[TINT])
copylen := nod(OLEN, n.Right, nil)
copyptr := nod(OSPTR, n.Right, nil)
if !types.Haspointers(t.Elem()) && n.Bounded() {
// When len(to)==len(from) and elements have no pointers:
// replace make+copy with runtime.mallocgc+runtime.memmove.
// We do not check for overflow of len(to)*elem.Width here
// since len(from) is an existing checked slice capacity
// with same elem.Width for the from slice.
size := nod(OMUL, conv(length, types.Types[TUINTPTR]), conv(nodintconst(t.Elem().Width), types.Types[TUINTPTR]))
// instantiate mallocgc(size uintptr, typ *byte, needszero bool) unsafe.Pointer
fn := syslook("mallocgc")
sh := nod(OSLICEHEADER, nil, nil)
sh.Left = mkcall1(fn, types.Types[TUNSAFEPTR], init, size, nodnil(), nodbool(false))
sh.Left.MarkNonNil()
sh.List.Set2(length, length)
sh.Type = t
s := temp(t)
r := typecheck(nod(OAS, s, sh), ctxStmt)
r = walkexpr(r, init)
init.Append(r)
// instantiate memmove(to *any, frm *any, size uintptr)
fn = syslook("memmove")
fn = substArgTypes(fn, t.Elem(), t.Elem())
ncopy := mkcall1(fn, nil, init, nod(OSPTR, s, nil), copyptr, size)
ncopy = typecheck(ncopy, ctxStmt)
ncopy = walkexpr(ncopy, init)
init.Append(ncopy)
n = s
} else { // Replace make+copy with runtime.makeslicecopy.
// instantiate makeslicecopy(typ *byte, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer
fn := syslook("makeslicecopy")
s := nod(OSLICEHEADER, nil, nil)
s.Left = mkcall1(fn, types.Types[TUNSAFEPTR], init, typename(t.Elem()), length, copylen, conv(copyptr, types.Types[TUNSAFEPTR]))
s.Left.MarkNonNil()
s.List.Set2(length, length)
s.Type = t
n = typecheck(s, ctxExpr)
n = walkexpr(n, init)
}
case ORUNESTR:
a := nodnil()
if n.Esc == EscNone {
@ -3772,6 +3829,9 @@ func candiscard(n *Node) bool {
// Difficult to tell what sizes are okay.
case OMAKESLICE:
return false
case OMAKESLICECOPY:
return false
}
if !candiscard(n.Left) || !candiscard(n.Right) || !candiscardlist(n.Ninit) || !candiscardlist(n.Nbody) || !candiscardlist(n.List) || !candiscardlist(n.Rlist) {

View file

@ -185,6 +185,11 @@ func checkFunc(f *Func) {
f.Fatalf("bad type %T for S390XRotateParams in %v", v.Aux, v)
}
canHaveAux = true
case auxFlagConstant:
if v.AuxInt < 0 || v.AuxInt > 15 {
f.Fatalf("bad FlagConstant AuxInt value for %v", v)
}
canHaveAuxInt = true
default:
f.Fatalf("unknown aux type for %s", v.Op)
}

View file

@ -451,6 +451,7 @@ var passes = [...]pass{
{name: "lowered deadcode for cse", fn: deadcode}, // deadcode immediately before CSE avoids CSE making dead values live again
{name: "lowered cse", fn: cse},
{name: "elim unread autos", fn: elimUnreadAutos},
{name: "tighten tuple selectors", fn: tightenTupleSelectors, required: true},
{name: "lowered deadcode", fn: deadcode, required: true},
{name: "checkLower", fn: checkLower, required: true},
{name: "late phielim", fn: phielim},
@ -509,6 +510,8 @@ var passOrder = [...]constraint{
{"decompose builtin", "late opt"},
// decompose builtin is the last pass that may introduce new float ops, so run softfloat after it
{"decompose builtin", "softfloat"},
// tuple selectors must be tightened to generators and de-duplicated before scheduling
{"tighten tuple selectors", "schedule"},
// remove critical edges before phi tighten, so that phi args get better placement
{"critical", "phi tighten"},
// don't layout blocks until critical edges have been removed

View file

@ -190,43 +190,6 @@ func cse(f *Func) {
}
}
// if we rewrite a tuple generator to a new one in a different block,
// copy its selectors to the new generator's block, so tuple generator
// and selectors stay together.
// be careful not to copy same selectors more than once (issue 16741).
copiedSelects := make(map[ID][]*Value)
for _, b := range f.Blocks {
out:
for _, v := range b.Values {
// New values are created when selectors are copied to
// a new block. We can safely ignore those new values,
// since they have already been copied (issue 17918).
if int(v.ID) >= len(rewrite) || rewrite[v.ID] != nil {
continue
}
if v.Op != OpSelect0 && v.Op != OpSelect1 {
continue
}
if !v.Args[0].Type.IsTuple() {
f.Fatalf("arg of tuple selector %s is not a tuple: %s", v.String(), v.Args[0].LongString())
}
t := rewrite[v.Args[0].ID]
if t != nil && t.Block != b {
// v.Args[0] is tuple generator, CSE'd into a different block as t, v is left behind
for _, c := range copiedSelects[t.ID] {
if v.Op == c.Op {
// an equivalent selector is already copied
rewrite[v.ID] = c
continue out
}
}
c := v.copyInto(t.Block)
rewrite[v.ID] = c
copiedSelects[t.ID] = append(copiedSelects[t.ID], c)
}
}
}
rewrites := int64(0)
// Apply substitutions
@ -259,6 +222,7 @@ func cse(f *Func) {
}
}
}
if f.pass.stats > 0 {
f.LogStat("CSE REWRITES", rewrites)
}

View file

@ -73,9 +73,11 @@ func dse(f *Func) {
}
// Walk backwards looking for dead stores. Keep track of shadowed addresses.
// An "address" is an SSA Value which encodes both the address and size of
// the write. This code will not remove dead stores to the same address
// of different types.
// A "shadowed address" is a pointer and a size describing a memory region that
// is known to be written. We keep track of shadowed addresses in the shadowed
// map, mapping the ID of the address to the size of the shadowed region.
// Since we're walking backwards, writes to a shadowed region are useless,
// as they will be immediately overwritten.
shadowed.clear()
v := last
@ -93,17 +95,13 @@ func dse(f *Func) {
sz = v.AuxInt
}
if shadowedSize := int64(shadowed.get(v.Args[0].ID)); shadowedSize != -1 && shadowedSize >= sz {
// Modify store into a copy
// Modify the store/zero into a copy of the memory state,
// effectively eliding the store operation.
if v.Op == OpStore {
// store addr value mem
v.SetArgs1(v.Args[2])
} else {
// zero addr mem
typesz := v.Args[0].Type.Elem().Size()
if sz != typesz {
f.Fatalf("mismatched zero/store sizes: %d and %d [%s]",
sz, typesz, v.LongString())
}
v.SetArgs1(v.Args[1])
}
v.Aux = nil

View file

@ -49,11 +49,11 @@ var gogcflags = os.Getenv("GO_GCFLAGS")
// optimizedLibs usually means "not running in a noopt test builder".
var optimizedLibs = (!strings.Contains(gogcflags, "-N") && !strings.Contains(gogcflags, "-l"))
// TestNexting go-builds a file, then uses a debugger (default gdb, optionally delve)
// TestNexting go-builds a file, then uses a debugger (default delve, optionally gdb)
// to next through the generated executable, recording each line landed at, and
// then compares those lines with reference file(s).
// Flag -u updates the reference file(s).
// Flag -d changes the debugger to delve (and uses delve-specific reference files)
// Flag -g changes the debugger to gdb (and uses gdb-specific reference files)
// Flag -v is ever-so-slightly verbose.
// Flag -n is for dry-run, and prints the shell and first debug commands.
//
@ -83,9 +83,9 @@ var optimizedLibs = (!strings.Contains(gogcflags, "-N") && !strings.Contains(gog
// to indicate normalization of Strings, (hex) addresses, and numbers.
// "O" is an explicit indication that we expect it to be optimized out.
// For example:
/*
if len(os.Args) > 1 { //gdb-dbg=(hist/A,cannedInput/A) //dlv-dbg=(hist/A,cannedInput/A)
*/
//
// if len(os.Args) > 1 { //gdb-dbg=(hist/A,cannedInput/A) //dlv-dbg=(hist/A,cannedInput/A)
//
// TODO: not implemented for Delve yet, but this is the plan
//
// After a compiler change that causes a difference in the debug behavior, check
@ -93,7 +93,7 @@ var optimizedLibs = (!strings.Contains(gogcflags, "-N") && !strings.Contains(gog
// go test debug_test.go -args -u
// (for Delve)
// go test debug_test.go -args -u -d
//
func TestNexting(t *testing.T) {
testenv.SkipFlaky(t, 37404)
@ -110,7 +110,13 @@ func TestNexting(t *testing.T) {
// Various architectures tend to differ slightly sometimes, and keeping them
// all in sync is a pain for people who don't have them all at hand,
// so limit testing to amd64 (for now)
skipReasons += "not run when testing gdb (-g) unless forced (-f) or linux-amd64"
skipReasons += "not run when testing gdb (-g) unless forced (-f) or linux-amd64; "
}
if !*useGdb && !*force && testenv.Builder() == "linux-386-longtest" {
// The latest version of Delve does support linux/386. However, the version currently
// installed in the linux-386-longtest builder does not. See golang.org/issue/39309.
skipReasons += "not run when testing delve on linux-386-longtest builder unless forced (-f); "
}
if *useGdb {

View file

@ -0,0 +1,31 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build amd64
#include "textflag.h"
TEXT ·asmAddFlags(SB),NOSPLIT,$0-24
MOVQ x+0(FP), AX
ADDQ y+8(FP), AX
PUSHFQ
POPQ AX
MOVQ AX, ret+16(FP)
RET
TEXT ·asmSubFlags(SB),NOSPLIT,$0-24
MOVQ x+0(FP), AX
SUBQ y+8(FP), AX
PUSHFQ
POPQ AX
MOVQ AX, ret+16(FP)
RET
TEXT ·asmAndFlags(SB),NOSPLIT,$0-24
MOVQ x+0(FP), AX
ANDQ y+8(FP), AX
PUSHFQ
POPQ AX
MOVQ AX, ret+16(FP)
RET

View file

@ -0,0 +1,32 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build arm64
#include "textflag.h"
TEXT ·asmAddFlags(SB),NOSPLIT,$0-24
MOVD x+0(FP), R0
MOVD y+8(FP), R1
CMN R0, R1
WORD $0xd53b4200 // MOVD NZCV, R0
MOVD R0, ret+16(FP)
RET
TEXT ·asmSubFlags(SB),NOSPLIT,$0-24
MOVD x+0(FP), R0
MOVD y+8(FP), R1
CMP R1, R0
WORD $0xd53b4200 // MOVD NZCV, R0
MOVD R0, ret+16(FP)
RET
TEXT ·asmAndFlags(SB),NOSPLIT,$0-24
MOVD x+0(FP), R0
MOVD y+8(FP), R1
TST R1, R0
WORD $0xd53b4200 // MOVD NZCV, R0
BIC $0x30000000, R0 // clear C, V bits, as TST does not change those flags
MOVD R0, ret+16(FP)
RET

View file

@ -0,0 +1,108 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build amd64 arm64
package ssa
// This file tests the functions addFlags64 and subFlags64 by comparing their
// results to what the chip calculates.
import (
"runtime"
"testing"
)
func TestAddFlagsNative(t *testing.T) {
var numbers = []int64{
1, 0, -1,
2, -2,
1<<63 - 1, -1 << 63,
}
coverage := map[flagConstant]bool{}
for _, x := range numbers {
for _, y := range numbers {
a := addFlags64(x, y)
b := flagRegister2flagConstant(asmAddFlags(x, y), false)
if a != b {
t.Errorf("asmAdd diff: x=%x y=%x got=%s want=%s\n", x, y, a, b)
}
coverage[a] = true
}
}
if len(coverage) != 9 { // TODO: can we cover all outputs?
t.Errorf("coverage too small, got %d want 9", len(coverage))
}
}
func TestSubFlagsNative(t *testing.T) {
var numbers = []int64{
1, 0, -1,
2, -2,
1<<63 - 1, -1 << 63,
}
coverage := map[flagConstant]bool{}
for _, x := range numbers {
for _, y := range numbers {
a := subFlags64(x, y)
b := flagRegister2flagConstant(asmSubFlags(x, y), true)
if a != b {
t.Errorf("asmSub diff: x=%x y=%x got=%s want=%s\n", x, y, a, b)
}
coverage[a] = true
}
}
if len(coverage) != 7 { // TODO: can we cover all outputs?
t.Errorf("coverage too small, got %d want 7", len(coverage))
}
}
func TestAndFlagsNative(t *testing.T) {
var numbers = []int64{
1, 0, -1,
2, -2,
1<<63 - 1, -1 << 63,
}
coverage := map[flagConstant]bool{}
for _, x := range numbers {
for _, y := range numbers {
a := logicFlags64(x & y)
b := flagRegister2flagConstant(asmAndFlags(x, y), false)
if a != b {
t.Errorf("asmAnd diff: x=%x y=%x got=%s want=%s\n", x, y, a, b)
}
coverage[a] = true
}
}
if len(coverage) != 3 {
t.Errorf("coverage too small, got %d want 3", len(coverage))
}
}
func asmAddFlags(x, y int64) int
func asmSubFlags(x, y int64) int
func asmAndFlags(x, y int64) int
func flagRegister2flagConstant(x int, sub bool) flagConstant {
var fcb flagConstantBuilder
switch runtime.GOARCH {
case "amd64":
fcb.Z = x>>6&1 != 0
fcb.N = x>>7&1 != 0
fcb.C = x>>0&1 != 0
if sub {
// Convert from amd64-sense to arm-sense
fcb.C = !fcb.C
}
fcb.V = x>>11&1 != 0
case "arm64":
fcb.Z = x>>30&1 != 0
fcb.N = x>>31&1 != 0
fcb.C = x>>29&1 != 0
fcb.V = x>>28&1 != 0
default:
panic("unsupported architecture: " + runtime.GOARCH)
}
return fcb.encode()
}

View file

@ -609,89 +609,59 @@
(Select1 (CALLudiv x (MOVWconst [c]))) && isPowerOfTwo(c) -> (ANDconst [c-1] x)
// constant comparisons
(CMPconst (MOVWconst [x]) [y]) && int32(x)==int32(y) -> (FlagEQ)
(CMPconst (MOVWconst [x]) [y]) && int32(x)<int32(y) && uint32(x)<uint32(y) -> (FlagLT_ULT)
(CMPconst (MOVWconst [x]) [y]) && int32(x)<int32(y) && uint32(x)>uint32(y) -> (FlagLT_UGT)
(CMPconst (MOVWconst [x]) [y]) && int32(x)>int32(y) && uint32(x)<uint32(y) -> (FlagGT_ULT)
(CMPconst (MOVWconst [x]) [y]) && int32(x)>int32(y) && uint32(x)>uint32(y) -> (FlagGT_UGT)
(CMNconst (MOVWconst [x]) [y]) && int32(x)==int32(-y) -> (FlagEQ)
(CMNconst (MOVWconst [x]) [y]) && int32(x)<int32(-y) && uint32(x)<uint32(-y) -> (FlagLT_ULT)
(CMNconst (MOVWconst [x]) [y]) && int32(x)<int32(-y) && uint32(x)>uint32(-y) -> (FlagLT_UGT)
(CMNconst (MOVWconst [x]) [y]) && int32(x)>int32(-y) && uint32(x)<uint32(-y) -> (FlagGT_ULT)
(CMNconst (MOVWconst [x]) [y]) && int32(x)>int32(-y) && uint32(x)>uint32(-y) -> (FlagGT_UGT)
(TSTconst (MOVWconst [x]) [y]) && int32(x&y)==0 -> (FlagEQ)
(TSTconst (MOVWconst [x]) [y]) && int32(x&y)<0 -> (FlagLT_UGT)
(TSTconst (MOVWconst [x]) [y]) && int32(x&y)>0 -> (FlagGT_UGT)
(TEQconst (MOVWconst [x]) [y]) && int32(x^y)==0 -> (FlagEQ)
(TEQconst (MOVWconst [x]) [y]) && int32(x^y)<0 -> (FlagLT_UGT)
(TEQconst (MOVWconst [x]) [y]) && int32(x^y)>0 -> (FlagGT_UGT)
(CMPconst (MOVWconst [x]) [y]) => (FlagConstant [subFlags32(x,y)])
(CMNconst (MOVWconst [x]) [y]) => (FlagConstant [addFlags32(x,y)])
(TSTconst (MOVWconst [x]) [y]) => (FlagConstant [logicFlags32(x&y)])
(TEQconst (MOVWconst [x]) [y]) => (FlagConstant [logicFlags32(x^y)])
// other known comparisons
(CMPconst (MOVBUreg _) [c]) && 0xff < c -> (FlagLT_ULT)
(CMPconst (MOVHUreg _) [c]) && 0xffff < c -> (FlagLT_ULT)
(CMPconst (ANDconst _ [m]) [n]) && 0 <= int32(m) && int32(m) < int32(n) -> (FlagLT_ULT)
(CMPconst (SRLconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 32 && (1<<uint32(32-c)) <= uint32(n) -> (FlagLT_ULT)
(CMPconst (MOVBUreg _) [c]) && 0xff < c => (FlagConstant [subFlags32(0, 1)])
(CMPconst (MOVHUreg _) [c]) && 0xffff < c => (FlagConstant [subFlags32(0, 1)])
(CMPconst (ANDconst _ [m]) [n]) && 0 <= m && m < n => (FlagConstant [subFlags32(0, 1)])
(CMPconst (SRLconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 32 && (1<<uint32(32-c)) <= uint32(n) => (FlagConstant [subFlags32(0, 1)])
// absorb flag constants into branches
(EQ (FlagEQ) yes no) -> (First yes no)
(EQ (FlagLT_ULT) yes no) -> (First no yes)
(EQ (FlagLT_UGT) yes no) -> (First no yes)
(EQ (FlagGT_ULT) yes no) -> (First no yes)
(EQ (FlagGT_UGT) yes no) -> (First no yes)
(EQ (FlagConstant [fc]) yes no) && fc.eq() => (First yes no)
(EQ (FlagConstant [fc]) yes no) && !fc.eq() => (First no yes)
(NE (FlagEQ) yes no) -> (First no yes)
(NE (FlagLT_ULT) yes no) -> (First yes no)
(NE (FlagLT_UGT) yes no) -> (First yes no)
(NE (FlagGT_ULT) yes no) -> (First yes no)
(NE (FlagGT_UGT) yes no) -> (First yes no)
(NE (FlagConstant [fc]) yes no) && fc.ne() => (First yes no)
(NE (FlagConstant [fc]) yes no) && !fc.ne() => (First no yes)
(LT (FlagEQ) yes no) -> (First no yes)
(LT (FlagLT_ULT) yes no) -> (First yes no)
(LT (FlagLT_UGT) yes no) -> (First yes no)
(LT (FlagGT_ULT) yes no) -> (First no yes)
(LT (FlagGT_UGT) yes no) -> (First no yes)
(LT (FlagConstant [fc]) yes no) && fc.lt() => (First yes no)
(LT (FlagConstant [fc]) yes no) && !fc.lt() => (First no yes)
(LE (FlagEQ) yes no) -> (First yes no)
(LE (FlagLT_ULT) yes no) -> (First yes no)
(LE (FlagLT_UGT) yes no) -> (First yes no)
(LE (FlagGT_ULT) yes no) -> (First no yes)
(LE (FlagGT_UGT) yes no) -> (First no yes)
(LE (FlagConstant [fc]) yes no) && fc.le() => (First yes no)
(LE (FlagConstant [fc]) yes no) && !fc.le() => (First no yes)
(GT (FlagEQ) yes no) -> (First no yes)
(GT (FlagLT_ULT) yes no) -> (First no yes)
(GT (FlagLT_UGT) yes no) -> (First no yes)
(GT (FlagGT_ULT) yes no) -> (First yes no)
(GT (FlagGT_UGT) yes no) -> (First yes no)
(GT (FlagConstant [fc]) yes no) && fc.gt() => (First yes no)
(GT (FlagConstant [fc]) yes no) && !fc.gt() => (First no yes)
(GE (FlagEQ) yes no) -> (First yes no)
(GE (FlagLT_ULT) yes no) -> (First no yes)
(GE (FlagLT_UGT) yes no) -> (First no yes)
(GE (FlagGT_ULT) yes no) -> (First yes no)
(GE (FlagGT_UGT) yes no) -> (First yes no)
(GE (FlagConstant [fc]) yes no) && fc.ge() => (First yes no)
(GE (FlagConstant [fc]) yes no) && !fc.ge() => (First no yes)
(ULT (FlagEQ) yes no) -> (First no yes)
(ULT (FlagLT_ULT) yes no) -> (First yes no)
(ULT (FlagLT_UGT) yes no) -> (First no yes)
(ULT (FlagGT_ULT) yes no) -> (First yes no)
(ULT (FlagGT_UGT) yes no) -> (First no yes)
(ULT (FlagConstant [fc]) yes no) && fc.ult() => (First yes no)
(ULT (FlagConstant [fc]) yes no) && !fc.ult() => (First no yes)
(ULE (FlagEQ) yes no) -> (First yes no)
(ULE (FlagLT_ULT) yes no) -> (First yes no)
(ULE (FlagLT_UGT) yes no) -> (First no yes)
(ULE (FlagGT_ULT) yes no) -> (First yes no)
(ULE (FlagGT_UGT) yes no) -> (First no yes)
(ULE (FlagConstant [fc]) yes no) && fc.ule() => (First yes no)
(ULE (FlagConstant [fc]) yes no) && !fc.ule() => (First no yes)
(UGT (FlagEQ) yes no) -> (First no yes)
(UGT (FlagLT_ULT) yes no) -> (First no yes)
(UGT (FlagLT_UGT) yes no) -> (First yes no)
(UGT (FlagGT_ULT) yes no) -> (First no yes)
(UGT (FlagGT_UGT) yes no) -> (First yes no)
(UGT (FlagConstant [fc]) yes no) && fc.ugt() => (First yes no)
(UGT (FlagConstant [fc]) yes no) && !fc.ugt() => (First no yes)
(UGE (FlagEQ) yes no) -> (First yes no)
(UGE (FlagLT_ULT) yes no) -> (First no yes)
(UGE (FlagLT_UGT) yes no) -> (First yes no)
(UGE (FlagGT_ULT) yes no) -> (First no yes)
(UGE (FlagGT_UGT) yes no) -> (First yes no)
(UGE (FlagConstant [fc]) yes no) && fc.uge() => (First yes no)
(UGE (FlagConstant [fc]) yes no) && !fc.uge() => (First no yes)
(LTnoov (FlagConstant [fc]) yes no) && fc.ltNoov() => (First yes no)
(LTnoov (FlagConstant [fc]) yes no) && !fc.ltNoov() => (First no yes)
(LEnoov (FlagConstant [fc]) yes no) && fc.leNoov() => (First yes no)
(LEnoov (FlagConstant [fc]) yes no) && !fc.leNoov() => (First no yes)
(GTnoov (FlagConstant [fc]) yes no) && fc.gtNoov() => (First yes no)
(GTnoov (FlagConstant [fc]) yes no) && !fc.gtNoov() => (First no yes)
(GEnoov (FlagConstant [fc]) yes no) && fc.geNoov() => (First yes no)
(GEnoov (FlagConstant [fc]) yes no) && !fc.geNoov() => (First no yes)
// absorb InvertFlags into branches
(LT (InvertFlags cmp) yes no) -> (GT cmp yes no)
@ -704,67 +674,22 @@
(UGE (InvertFlags cmp) yes no) -> (ULE cmp yes no)
(EQ (InvertFlags cmp) yes no) -> (EQ cmp yes no)
(NE (InvertFlags cmp) yes no) -> (NE cmp yes no)
(LTnoov (InvertFlags cmp) yes no) => (GTnoov cmp yes no)
(GEnoov (InvertFlags cmp) yes no) => (LEnoov cmp yes no)
(LEnoov (InvertFlags cmp) yes no) => (GEnoov cmp yes no)
(GTnoov (InvertFlags cmp) yes no) => (LTnoov cmp yes no)
// absorb flag constants into boolean values
(Equal (FlagEQ)) -> (MOVWconst [1])
(Equal (FlagLT_ULT)) -> (MOVWconst [0])
(Equal (FlagLT_UGT)) -> (MOVWconst [0])
(Equal (FlagGT_ULT)) -> (MOVWconst [0])
(Equal (FlagGT_UGT)) -> (MOVWconst [0])
(NotEqual (FlagEQ)) -> (MOVWconst [0])
(NotEqual (FlagLT_ULT)) -> (MOVWconst [1])
(NotEqual (FlagLT_UGT)) -> (MOVWconst [1])
(NotEqual (FlagGT_ULT)) -> (MOVWconst [1])
(NotEqual (FlagGT_UGT)) -> (MOVWconst [1])
(LessThan (FlagEQ)) -> (MOVWconst [0])
(LessThan (FlagLT_ULT)) -> (MOVWconst [1])
(LessThan (FlagLT_UGT)) -> (MOVWconst [1])
(LessThan (FlagGT_ULT)) -> (MOVWconst [0])
(LessThan (FlagGT_UGT)) -> (MOVWconst [0])
(LessThanU (FlagEQ)) -> (MOVWconst [0])
(LessThanU (FlagLT_ULT)) -> (MOVWconst [1])
(LessThanU (FlagLT_UGT)) -> (MOVWconst [0])
(LessThanU (FlagGT_ULT)) -> (MOVWconst [1])
(LessThanU (FlagGT_UGT)) -> (MOVWconst [0])
(LessEqual (FlagEQ)) -> (MOVWconst [1])
(LessEqual (FlagLT_ULT)) -> (MOVWconst [1])
(LessEqual (FlagLT_UGT)) -> (MOVWconst [1])
(LessEqual (FlagGT_ULT)) -> (MOVWconst [0])
(LessEqual (FlagGT_UGT)) -> (MOVWconst [0])
(LessEqualU (FlagEQ)) -> (MOVWconst [1])
(LessEqualU (FlagLT_ULT)) -> (MOVWconst [1])
(LessEqualU (FlagLT_UGT)) -> (MOVWconst [0])
(LessEqualU (FlagGT_ULT)) -> (MOVWconst [1])
(LessEqualU (FlagGT_UGT)) -> (MOVWconst [0])
(GreaterThan (FlagEQ)) -> (MOVWconst [0])
(GreaterThan (FlagLT_ULT)) -> (MOVWconst [0])
(GreaterThan (FlagLT_UGT)) -> (MOVWconst [0])
(GreaterThan (FlagGT_ULT)) -> (MOVWconst [1])
(GreaterThan (FlagGT_UGT)) -> (MOVWconst [1])
(GreaterThanU (FlagEQ)) -> (MOVWconst [0])
(GreaterThanU (FlagLT_ULT)) -> (MOVWconst [0])
(GreaterThanU (FlagLT_UGT)) -> (MOVWconst [1])
(GreaterThanU (FlagGT_ULT)) -> (MOVWconst [0])
(GreaterThanU (FlagGT_UGT)) -> (MOVWconst [1])
(GreaterEqual (FlagEQ)) -> (MOVWconst [1])
(GreaterEqual (FlagLT_ULT)) -> (MOVWconst [0])
(GreaterEqual (FlagLT_UGT)) -> (MOVWconst [0])
(GreaterEqual (FlagGT_ULT)) -> (MOVWconst [1])
(GreaterEqual (FlagGT_UGT)) -> (MOVWconst [1])
(GreaterEqualU (FlagEQ)) -> (MOVWconst [1])
(GreaterEqualU (FlagLT_ULT)) -> (MOVWconst [0])
(GreaterEqualU (FlagLT_UGT)) -> (MOVWconst [1])
(GreaterEqualU (FlagGT_ULT)) -> (MOVWconst [0])
(GreaterEqualU (FlagGT_UGT)) -> (MOVWconst [1])
(Equal (FlagConstant [fc])) => (MOVWconst [b2i32(fc.eq())])
(NotEqual (FlagConstant [fc])) => (MOVWconst [b2i32(fc.ne())])
(LessThan (FlagConstant [fc])) => (MOVWconst [b2i32(fc.lt())])
(LessThanU (FlagConstant [fc])) => (MOVWconst [b2i32(fc.ult())])
(LessEqual (FlagConstant [fc])) => (MOVWconst [b2i32(fc.le())])
(LessEqualU (FlagConstant [fc])) => (MOVWconst [b2i32(fc.ule())])
(GreaterThan (FlagConstant [fc])) => (MOVWconst [b2i32(fc.gt())])
(GreaterThanU (FlagConstant [fc])) => (MOVWconst [b2i32(fc.ugt())])
(GreaterEqual (FlagConstant [fc])) => (MOVWconst [b2i32(fc.ge())])
(GreaterEqualU (FlagConstant [fc])) => (MOVWconst [b2i32(fc.uge())])
// absorb InvertFlags into boolean values
(Equal (InvertFlags x)) -> (Equal x)
@ -779,26 +704,17 @@
(GreaterEqualU (InvertFlags x)) -> (LessEqualU x)
// absorb flag constants into conditional instructions
(CMOVWLSconst _ (FlagEQ) [c]) -> (MOVWconst [c])
(CMOVWLSconst _ (FlagLT_ULT) [c]) -> (MOVWconst [c])
(CMOVWLSconst x (FlagLT_UGT)) -> x
(CMOVWLSconst _ (FlagGT_ULT) [c]) -> (MOVWconst [c])
(CMOVWLSconst x (FlagGT_UGT)) -> x
(CMOVWLSconst _ (FlagConstant [fc]) [c]) && fc.ule() => (MOVWconst [c])
(CMOVWLSconst x (FlagConstant [fc]) [c]) && fc.ugt() => x
(CMOVWHSconst _ (FlagEQ) [c]) -> (MOVWconst [c])
(CMOVWHSconst x (FlagLT_ULT)) -> x
(CMOVWHSconst _ (FlagLT_UGT) [c]) -> (MOVWconst [c])
(CMOVWHSconst x (FlagGT_ULT)) -> x
(CMOVWHSconst _ (FlagGT_UGT) [c]) -> (MOVWconst [c])
(CMOVWHSconst _ (FlagConstant [fc]) [c]) && fc.uge() => (MOVWconst [c])
(CMOVWHSconst x (FlagConstant [fc]) [c]) && fc.ult() => x
(CMOVWLSconst x (InvertFlags flags) [c]) -> (CMOVWHSconst x flags [c])
(CMOVWHSconst x (InvertFlags flags) [c]) -> (CMOVWLSconst x flags [c])
(SRAcond x _ (FlagEQ)) -> (SRAconst x [31])
(SRAcond x y (FlagLT_ULT)) -> (SRA x y)
(SRAcond x _ (FlagLT_UGT)) -> (SRAconst x [31])
(SRAcond x y (FlagGT_ULT)) -> (SRA x y)
(SRAcond x _ (FlagGT_UGT)) -> (SRAconst x [31])
(SRAcond x _ (FlagConstant [fc])) && fc.uge() => (SRAconst x [31])
(SRAcond x y (FlagConstant [fc])) && fc.ult() => (SRA x y)
// remove redundant *const ops
(ADDconst [0] x) -> x
@ -1417,42 +1333,42 @@
(NE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 -> (NE (TEQshiftLLreg x y z) yes no)
(NE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 -> (NE (TEQshiftRLreg x y z) yes no)
(NE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 -> (NE (TEQshiftRAreg x y z) yes no)
(LT (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (LT (CMP x y) yes no)
(LT (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (LT (CMP a (MUL <x.Type> x y)) yes no)
(LT (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (LT (CMPconst [c] x) yes no)
(LT (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (LT (CMPshiftLL x y [c]) yes no)
(LT (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (LT (CMPshiftRL x y [c]) yes no)
(LT (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (LT (CMPshiftRA x y [c]) yes no)
(LT (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (LT (CMPshiftLLreg x y z) yes no)
(LT (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (LT (CMPshiftRLreg x y z) yes no)
(LT (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (LT (CMPshiftRAreg x y z) yes no)
(LE (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (LE (CMP x y) yes no)
(LE (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (LE (CMP a (MUL <x.Type> x y)) yes no)
(LE (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (LE (CMPconst [c] x) yes no)
(LE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (LE (CMPshiftLL x y [c]) yes no)
(LE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (LE (CMPshiftRL x y [c]) yes no)
(LE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (LE (CMPshiftRA x y [c]) yes no)
(LE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (LE (CMPshiftLLreg x y z) yes no)
(LE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (LE (CMPshiftRLreg x y z) yes no)
(LE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (LE (CMPshiftRAreg x y z) yes no)
(LT (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (LT (CMN x y) yes no)
(LT (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (LT (CMN a (MUL <x.Type> x y)) yes no)
(LT (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (LT (CMNconst [c] x) yes no)
(LT (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (LT (CMNshiftLL x y [c]) yes no)
(LT (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (LT (CMNshiftRL x y [c]) yes no)
(LT (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (LT (CMNshiftRA x y [c]) yes no)
(LT (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (LT (CMNshiftLLreg x y z) yes no)
(LT (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (LT (CMNshiftRLreg x y z) yes no)
(LT (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (LT (CMNshiftRAreg x y z) yes no)
(LE (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (LE (CMN x y) yes no)
(LE (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (LE (CMN a (MUL <x.Type> x y)) yes no)
(LE (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (LE (CMNconst [c] x) yes no)
(LE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (LE (CMNshiftLL x y [c]) yes no)
(LE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (LE (CMNshiftRL x y [c]) yes no)
(LE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (LE (CMNshiftRA x y [c]) yes no)
(LE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (LE (CMNshiftLLreg x y z) yes no)
(LE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (LE (CMNshiftRLreg x y z) yes no)
(LE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (LE (CMNshiftRAreg x y z) yes no)
(LT (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (LTnoov (CMP x y) yes no)
(LT (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (LTnoov (CMP a (MUL <x.Type> x y)) yes no)
(LT (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (LTnoov (CMPconst [c] x) yes no)
(LT (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMPshiftLL x y [c]) yes no)
(LT (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMPshiftRL x y [c]) yes no)
(LT (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMPshiftRA x y [c]) yes no)
(LT (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMPshiftLLreg x y z) yes no)
(LT (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMPshiftRLreg x y z) yes no)
(LT (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMPshiftRAreg x y z) yes no)
(LE (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (LEnoov (CMP x y) yes no)
(LE (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (LEnoov (CMP a (MUL <x.Type> x y)) yes no)
(LE (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (LEnoov (CMPconst [c] x) yes no)
(LE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMPshiftLL x y [c]) yes no)
(LE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMPshiftRL x y [c]) yes no)
(LE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMPshiftRA x y [c]) yes no)
(LE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMPshiftLLreg x y z) yes no)
(LE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMPshiftRLreg x y z) yes no)
(LE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMPshiftRAreg x y z) yes no)
(LT (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (LTnoov (CMN x y) yes no)
(LT (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (LTnoov (CMN a (MUL <x.Type> x y)) yes no)
(LT (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (LTnoov (CMNconst [c] x) yes no)
(LT (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMNshiftLL x y [c]) yes no)
(LT (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMNshiftRL x y [c]) yes no)
(LT (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMNshiftRA x y [c]) yes no)
(LT (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMNshiftLLreg x y z) yes no)
(LT (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMNshiftRLreg x y z) yes no)
(LT (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMNshiftRAreg x y z) yes no)
(LE (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (LEnoov (CMN x y) yes no)
(LE (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (LEnoov (CMN a (MUL <x.Type> x y)) yes no)
(LE (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (LEnoov (CMNconst [c] x) yes no)
(LE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMNshiftLL x y [c]) yes no)
(LE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMNshiftRL x y [c]) yes no)
(LE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMNshiftRA x y [c]) yes no)
(LE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMNshiftLLreg x y z) yes no)
(LE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMNshiftRLreg x y z) yes no)
(LE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMNshiftRAreg x y z) yes no)
(LT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 -> (LT (TST x y) yes no)
(LT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 -> (LT (TSTconst [c] x) yes no)
(LT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 -> (LT (TSTshiftLL x y [c]) yes no)
@ -1485,43 +1401,43 @@
(LE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 -> (LE (TEQshiftLLreg x y z) yes no)
(LE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 -> (LE (TEQshiftRLreg x y z) yes no)
(LE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 -> (LE (TEQshiftRAreg x y z) yes no)
(GT (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (GT (CMP x y) yes no)
(GT (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (GT (CMP a (MUL <x.Type> x y)) yes no)
(GT (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (GT (CMPconst [c] x) yes no)
(GT (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (GT (CMPshiftLL x y [c]) yes no)
(GT (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (GT (CMPshiftRL x y [c]) yes no)
(GT (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (GT (CMPshiftRA x y [c]) yes no)
(GT (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (GT (CMPshiftLLreg x y z) yes no)
(GT (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (GT (CMPshiftRLreg x y z) yes no)
(GT (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (GT (CMPshiftRAreg x y z) yes no)
(GE (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (GE (CMP x y) yes no)
(GE (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (GE (CMP a (MUL <x.Type> x y)) yes no)
(GE (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (GE (CMPconst [c] x) yes no)
(GE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (GE (CMPshiftLL x y [c]) yes no)
(GE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (GE (CMPshiftRL x y [c]) yes no)
(GE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (GE (CMPshiftRA x y [c]) yes no)
(GE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (GE (CMPshiftLLreg x y z) yes no)
(GE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (GE (CMPshiftRLreg x y z) yes no)
(GE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (GE (CMPshiftRAreg x y z) yes no)
(GT (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (GT (CMN x y) yes no)
(GT (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (GT (CMNconst [c] x) yes no)
(GT (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (GT (CMNshiftLL x y [c]) yes no)
(GT (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (GT (CMNshiftRL x y [c]) yes no)
(GT (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (GT (CMNshiftRA x y [c]) yes no)
(GT (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (GT (CMNshiftLLreg x y z) yes no)
(GT (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (GT (CMNshiftRLreg x y z) yes no)
(GT (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (GT (CMNshiftRAreg x y z) yes no)
(GE (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (GE (CMN x y) yes no)
(GE (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (GE (CMN a (MUL <x.Type> x y)) yes no)
(GE (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (GE (CMNconst [c] x) yes no)
(GE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (GE (CMNshiftLL x y [c]) yes no)
(GE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (GE (CMNshiftRL x y [c]) yes no)
(GE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (GE (CMNshiftRA x y [c]) yes no)
(GE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (GE (CMNshiftLLreg x y z) yes no)
(GE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (GE (CMNshiftRLreg x y z) yes no)
(GE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (GE (CMNshiftRAreg x y z) yes no)
(GT (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (GTnoov (CMP x y) yes no)
(GT (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (GTnoov (CMP a (MUL <x.Type> x y)) yes no)
(GT (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (GTnoov (CMPconst [c] x) yes no)
(GT (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMPshiftLL x y [c]) yes no)
(GT (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMPshiftRL x y [c]) yes no)
(GT (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMPshiftRA x y [c]) yes no)
(GT (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMPshiftLLreg x y z) yes no)
(GT (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMPshiftRLreg x y z) yes no)
(GT (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMPshiftRAreg x y z) yes no)
(GE (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (GEnoov (CMP x y) yes no)
(GE (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (GEnoov (CMP a (MUL <x.Type> x y)) yes no)
(GE (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (GEnoov (CMPconst [c] x) yes no)
(GE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMPshiftLL x y [c]) yes no)
(GE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMPshiftRL x y [c]) yes no)
(GE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMPshiftRA x y [c]) yes no)
(GE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMPshiftLLreg x y z) yes no)
(GE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMPshiftRLreg x y z) yes no)
(GE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMPshiftRAreg x y z) yes no)
(GT (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (GTnoov (CMN x y) yes no)
(GT (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (GTnoov (CMNconst [c] x) yes no)
(GT (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMNshiftLL x y [c]) yes no)
(GT (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMNshiftRL x y [c]) yes no)
(GT (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMNshiftRA x y [c]) yes no)
(GT (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMNshiftLLreg x y z) yes no)
(GT (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMNshiftRLreg x y z) yes no)
(GT (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMNshiftRAreg x y z) yes no)
(GE (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (GEnoov (CMN x y) yes no)
(GE (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (GEnoov (CMN a (MUL <x.Type> x y)) yes no)
(GE (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (GEnoov (CMNconst [c] x) yes no)
(GE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMNshiftLL x y [c]) yes no)
(GE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMNshiftRL x y [c]) yes no)
(GE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMNshiftRA x y [c]) yes no)
(GE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMNshiftLLreg x y z) yes no)
(GE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMNshiftRLreg x y z) yes no)
(GE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMNshiftRAreg x y z) yes no)
(GT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 -> (GT (TST x y) yes no)
(GT (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (GT (CMN a (MUL <x.Type> x y)) yes no)
(GT (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (GTnoov (CMN a (MUL <x.Type> x y)) yes no)
(GT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 -> (GT (TSTconst [c] x) yes no)
(GT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 -> (GT (TSTshiftLL x y [c]) yes no)
(GT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 -> (GT (TSTshiftRL x y [c]) yes no)

View file

@ -598,31 +598,31 @@
(EQ (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (EQ (CMNconst [c] y) yes no)
(NE (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (NE (CMNconst [c] y) yes no)
(LT (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (LT (CMNconst [c] y) yes no)
(LE (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (LE (CMNconst [c] y) yes no)
(GT (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (GT (CMNconst [c] y) yes no)
(GE (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (GE (CMNconst [c] y) yes no)
(LT (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (LTnoov (CMNconst [c] y) yes no)
(LE (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (LEnoov (CMNconst [c] y) yes no)
(GT (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (GTnoov (CMNconst [c] y) yes no)
(GE (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (GEnoov (CMNconst [c] y) yes no)
(EQ (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (EQ (CMNWconst [int32(c)] y) yes no)
(NE (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (NE (CMNWconst [int32(c)] y) yes no)
(LT (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (LT (CMNWconst [int32(c)] y) yes no)
(LE (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (LE (CMNWconst [int32(c)] y) yes no)
(GT (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (GT (CMNWconst [int32(c)] y) yes no)
(GE (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (GE (CMNWconst [int32(c)] y) yes no)
(LT (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (LTnoov (CMNWconst [int32(c)] y) yes no)
(LE (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (LEnoov (CMNWconst [int32(c)] y) yes no)
(GT (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (GTnoov (CMNWconst [int32(c)] y) yes no)
(GE (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (GEnoov (CMNWconst [int32(c)] y) yes no)
(EQ (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (EQ (CMN x y) yes no)
(NE (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (NE (CMN x y) yes no)
(LT (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (LT (CMN x y) yes no)
(LE (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (LE (CMN x y) yes no)
(GT (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (GT (CMN x y) yes no)
(GE (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (GE (CMN x y) yes no)
(LT (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (LTnoov (CMN x y) yes no)
(LE (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (LEnoov (CMN x y) yes no)
(GT (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (GTnoov (CMN x y) yes no)
(GE (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (GEnoov (CMN x y) yes no)
(EQ (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (EQ (CMNW x y) yes no)
(NE (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (NE (CMNW x y) yes no)
(LT (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (LT (CMNW x y) yes no)
(LE (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (LE (CMNW x y) yes no)
(GT (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (GT (CMNW x y) yes no)
(GE (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (GE (CMNW x y) yes no)
(LT (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (LTnoov (CMNW x y) yes no)
(LE (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (LEnoov (CMNW x y) yes no)
(GT (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (GTnoov (CMNW x y) yes no)
(GE (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (GEnoov (CMNW x y) yes no)
(EQ (CMP x z:(NEG y)) yes no) && z.Uses == 1 => (EQ (CMN x y) yes no)
(NE (CMP x z:(NEG y)) yes no) && z.Uses == 1 => (NE (CMN x y) yes no)
@ -645,31 +645,31 @@
(EQ (CMPconst [0] z:(MADD a x y)) yes no) && z.Uses==1 => (EQ (CMN a (MUL <x.Type> x y)) yes no)
(NE (CMPconst [0] z:(MADD a x y)) yes no) && z.Uses==1 => (NE (CMN a (MUL <x.Type> x y)) yes no)
(LT (CMPconst [0] z:(MADD a x y)) yes no) && z.Uses==1 => (LT (CMN a (MUL <x.Type> x y)) yes no)
(LE (CMPconst [0] z:(MADD a x y)) yes no) && z.Uses==1 => (LE (CMN a (MUL <x.Type> x y)) yes no)
(GT (CMPconst [0] z:(MADD a x y)) yes no) && z.Uses==1 => (GT (CMN a (MUL <x.Type> x y)) yes no)
(GE (CMPconst [0] z:(MADD a x y)) yes no) && z.Uses==1 => (GE (CMN a (MUL <x.Type> x y)) yes no)
(LT (CMPconst [0] z:(MADD a x y)) yes no) && z.Uses==1 => (LTnoov (CMN a (MUL <x.Type> x y)) yes no)
(LE (CMPconst [0] z:(MADD a x y)) yes no) && z.Uses==1 => (LEnoov (CMN a (MUL <x.Type> x y)) yes no)
(GT (CMPconst [0] z:(MADD a x y)) yes no) && z.Uses==1 => (GTnoov (CMN a (MUL <x.Type> x y)) yes no)
(GE (CMPconst [0] z:(MADD a x y)) yes no) && z.Uses==1 => (GEnoov (CMN a (MUL <x.Type> x y)) yes no)
(EQ (CMPconst [0] z:(MSUB a x y)) yes no) && z.Uses==1 => (EQ (CMP a (MUL <x.Type> x y)) yes no)
(NE (CMPconst [0] z:(MSUB a x y)) yes no) && z.Uses==1 => (NE (CMP a (MUL <x.Type> x y)) yes no)
(LE (CMPconst [0] z:(MSUB a x y)) yes no) && z.Uses==1 => (LE (CMP a (MUL <x.Type> x y)) yes no)
(LT (CMPconst [0] z:(MSUB a x y)) yes no) && z.Uses==1 => (LT (CMP a (MUL <x.Type> x y)) yes no)
(GE (CMPconst [0] z:(MSUB a x y)) yes no) && z.Uses==1 => (GE (CMP a (MUL <x.Type> x y)) yes no)
(GT (CMPconst [0] z:(MSUB a x y)) yes no) && z.Uses==1 => (GT (CMP a (MUL <x.Type> x y)) yes no)
(LE (CMPconst [0] z:(MSUB a x y)) yes no) && z.Uses==1 => (LEnoov (CMP a (MUL <x.Type> x y)) yes no)
(LT (CMPconst [0] z:(MSUB a x y)) yes no) && z.Uses==1 => (LTnoov (CMP a (MUL <x.Type> x y)) yes no)
(GE (CMPconst [0] z:(MSUB a x y)) yes no) && z.Uses==1 => (GEnoov (CMP a (MUL <x.Type> x y)) yes no)
(GT (CMPconst [0] z:(MSUB a x y)) yes no) && z.Uses==1 => (GTnoov (CMP a (MUL <x.Type> x y)) yes no)
(EQ (CMPWconst [0] z:(MADDW a x y)) yes no) && z.Uses==1 => (EQ (CMNW a (MULW <x.Type> x y)) yes no)
(NE (CMPWconst [0] z:(MADDW a x y)) yes no) && z.Uses==1 => (NE (CMNW a (MULW <x.Type> x y)) yes no)
(LE (CMPWconst [0] z:(MADDW a x y)) yes no) && z.Uses==1 => (LE (CMNW a (MULW <x.Type> x y)) yes no)
(LT (CMPWconst [0] z:(MADDW a x y)) yes no) && z.Uses==1 => (LT (CMNW a (MULW <x.Type> x y)) yes no)
(GE (CMPWconst [0] z:(MADDW a x y)) yes no) && z.Uses==1 => (GE (CMNW a (MULW <x.Type> x y)) yes no)
(GT (CMPWconst [0] z:(MADDW a x y)) yes no) && z.Uses==1 => (GT (CMNW a (MULW <x.Type> x y)) yes no)
(LE (CMPWconst [0] z:(MADDW a x y)) yes no) && z.Uses==1 => (LEnoov (CMNW a (MULW <x.Type> x y)) yes no)
(LT (CMPWconst [0] z:(MADDW a x y)) yes no) && z.Uses==1 => (LTnoov (CMNW a (MULW <x.Type> x y)) yes no)
(GE (CMPWconst [0] z:(MADDW a x y)) yes no) && z.Uses==1 => (GEnoov (CMNW a (MULW <x.Type> x y)) yes no)
(GT (CMPWconst [0] z:(MADDW a x y)) yes no) && z.Uses==1 => (GTnoov (CMNW a (MULW <x.Type> x y)) yes no)
(EQ (CMPWconst [0] z:(MSUBW a x y)) yes no) && z.Uses==1 => (EQ (CMPW a (MULW <x.Type> x y)) yes no)
(NE (CMPWconst [0] z:(MSUBW a x y)) yes no) && z.Uses==1 => (NE (CMPW a (MULW <x.Type> x y)) yes no)
(LE (CMPWconst [0] z:(MSUBW a x y)) yes no) && z.Uses==1 => (LE (CMPW a (MULW <x.Type> x y)) yes no)
(LT (CMPWconst [0] z:(MSUBW a x y)) yes no) && z.Uses==1 => (LT (CMPW a (MULW <x.Type> x y)) yes no)
(GE (CMPWconst [0] z:(MSUBW a x y)) yes no) && z.Uses==1 => (GE (CMPW a (MULW <x.Type> x y)) yes no)
(GT (CMPWconst [0] z:(MSUBW a x y)) yes no) && z.Uses==1 => (GT (CMPW a (MULW <x.Type> x y)) yes no)
(LE (CMPWconst [0] z:(MSUBW a x y)) yes no) && z.Uses==1 => (LEnoov (CMPW a (MULW <x.Type> x y)) yes no)
(LT (CMPWconst [0] z:(MSUBW a x y)) yes no) && z.Uses==1 => (LTnoov (CMPW a (MULW <x.Type> x y)) yes no)
(GE (CMPWconst [0] z:(MSUBW a x y)) yes no) && z.Uses==1 => (GEnoov (CMPW a (MULW <x.Type> x y)) yes no)
(GT (CMPWconst [0] z:(MSUBW a x y)) yes no) && z.Uses==1 => (GTnoov (CMPW a (MULW <x.Type> x y)) yes no)
// Absorb bit-tests into block
(Z (ANDconst [c] x) yes no) && oneBit(c) => (TBZ [int64(ntz64(c))] x yes no)
@ -1381,103 +1381,64 @@
(MOVDreg (MOVDconst [c])) -> (MOVDconst [c])
// constant comparisons
(CMPconst (MOVDconst [x]) [y]) && x==y -> (FlagEQ)
(CMPconst (MOVDconst [x]) [y]) && x<y && uint64(x)<uint64(y) -> (FlagLT_ULT)
(CMPconst (MOVDconst [x]) [y]) && x<y && uint64(x)>uint64(y) -> (FlagLT_UGT)
(CMPconst (MOVDconst [x]) [y]) && x>y && uint64(x)<uint64(y) -> (FlagGT_ULT)
(CMPconst (MOVDconst [x]) [y]) && x>y && uint64(x)>uint64(y) -> (FlagGT_UGT)
(CMPWconst (MOVDconst [x]) [y]) && int32(x)==int32(y) -> (FlagEQ)
(CMPWconst (MOVDconst [x]) [y]) && int32(x)<int32(y) && uint32(x)<uint32(y) -> (FlagLT_ULT)
(CMPWconst (MOVDconst [x]) [y]) && int32(x)<int32(y) && uint32(x)>uint32(y) -> (FlagLT_UGT)
(CMPWconst (MOVDconst [x]) [y]) && int32(x)>int32(y) && uint32(x)<uint32(y) -> (FlagGT_ULT)
(CMPWconst (MOVDconst [x]) [y]) && int32(x)>int32(y) && uint32(x)>uint32(y) -> (FlagGT_UGT)
(TSTconst (MOVDconst [x]) [y]) && int64(x&y)==0 -> (FlagEQ)
(TSTconst (MOVDconst [x]) [y]) && int64(x&y)<0 -> (FlagLT_UGT)
(TSTconst (MOVDconst [x]) [y]) && int64(x&y)>0 -> (FlagGT_UGT)
(TSTWconst (MOVDconst [x]) [y]) && int32(x&y)==0 -> (FlagEQ)
(TSTWconst (MOVDconst [x]) [y]) && int32(x&y)<0 -> (FlagLT_UGT)
(TSTWconst (MOVDconst [x]) [y]) && int32(x&y)>0 -> (FlagGT_UGT)
(CMNconst (MOVDconst [x]) [y]) && int64(x)==int64(-y) -> (FlagEQ)
(CMNconst (MOVDconst [x]) [y]) && int64(x)<int64(-y) && uint64(x)<uint64(-y) -> (FlagLT_ULT)
(CMNconst (MOVDconst [x]) [y]) && int64(x)<int64(-y) && uint64(x)>uint64(-y) -> (FlagLT_UGT)
(CMNconst (MOVDconst [x]) [y]) && int64(x)>int64(-y) && uint64(x)<uint64(-y) -> (FlagGT_ULT)
(CMNconst (MOVDconst [x]) [y]) && int64(x)>int64(-y) && uint64(x)>uint64(-y) -> (FlagGT_UGT)
(CMNWconst (MOVDconst [x]) [y]) && int32(x)==int32(-y) -> (FlagEQ)
(CMNWconst (MOVDconst [x]) [y]) && int32(x)<int32(-y) && uint32(x)<uint32(-y) -> (FlagLT_ULT)
(CMNWconst (MOVDconst [x]) [y]) && int32(x)<int32(-y) && uint32(x)>uint32(-y) -> (FlagLT_UGT)
(CMNWconst (MOVDconst [x]) [y]) && int32(x)>int32(-y) && uint32(x)<uint32(-y) -> (FlagGT_ULT)
(CMNWconst (MOVDconst [x]) [y]) && int32(x)>int32(-y) && uint32(x)>uint32(-y) -> (FlagGT_UGT)
(CMPconst (MOVDconst [x]) [y]) => (FlagConstant [subFlags64(x,y)])
(CMPWconst (MOVDconst [x]) [y]) => (FlagConstant [subFlags32(int32(x),y)])
(TSTconst (MOVDconst [x]) [y]) => (FlagConstant [logicFlags64(x&y)])
(TSTWconst (MOVDconst [x]) [y]) => (FlagConstant [logicFlags32(int32(x)&y)])
(CMNconst (MOVDconst [x]) [y]) => (FlagConstant [addFlags64(x,y)])
(CMNWconst (MOVDconst [x]) [y]) => (FlagConstant [addFlags32(int32(x),y)])
// other known comparisons
(CMPconst (MOVBUreg _) [c]) && 0xff < c -> (FlagLT_ULT)
(CMPconst (MOVHUreg _) [c]) && 0xffff < c -> (FlagLT_ULT)
(CMPconst (MOVWUreg _) [c]) && 0xffffffff < c -> (FlagLT_ULT)
(CMPconst (ANDconst _ [m]) [n]) && 0 <= m && m < n -> (FlagLT_ULT)
(CMPconst (SRLconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 63 && (1<<uint64(64-c)) <= uint64(n) -> (FlagLT_ULT)
(CMPWconst (MOVBUreg _) [c]) && 0xff < int32(c) -> (FlagLT_ULT)
(CMPWconst (MOVHUreg _) [c]) && 0xffff < int32(c) -> (FlagLT_ULT)
(CMPconst (MOVBUreg _) [c]) && 0xff < c => (FlagConstant [subFlags64(0,1)])
(CMPconst (MOVHUreg _) [c]) && 0xffff < c => (FlagConstant [subFlags64(0,1)])
(CMPconst (MOVWUreg _) [c]) && 0xffffffff < c => (FlagConstant [subFlags64(0,1)])
(CMPconst (ANDconst _ [m]) [n]) && 0 <= m && m < n => (FlagConstant [subFlags64(0,1)])
(CMPconst (SRLconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 63 && (1<<uint64(64-c)) <= uint64(n) => (FlagConstant [subFlags64(0,1)])
(CMPWconst (MOVBUreg _) [c]) && 0xff < c => (FlagConstant [subFlags64(0,1)])
(CMPWconst (MOVHUreg _) [c]) && 0xffff < c => (FlagConstant [subFlags64(0,1)])
// absorb flag constants into branches
(EQ (FlagEQ) yes no) -> (First yes no)
(EQ (FlagLT_ULT) yes no) -> (First no yes)
(EQ (FlagLT_UGT) yes no) -> (First no yes)
(EQ (FlagGT_ULT) yes no) -> (First no yes)
(EQ (FlagGT_UGT) yes no) -> (First no yes)
(EQ (FlagConstant [fc]) yes no) && fc.eq() => (First yes no)
(EQ (FlagConstant [fc]) yes no) && !fc.eq() => (First no yes)
(NE (FlagEQ) yes no) -> (First no yes)
(NE (FlagLT_ULT) yes no) -> (First yes no)
(NE (FlagLT_UGT) yes no) -> (First yes no)
(NE (FlagGT_ULT) yes no) -> (First yes no)
(NE (FlagGT_UGT) yes no) -> (First yes no)
(NE (FlagConstant [fc]) yes no) && fc.ne() => (First yes no)
(NE (FlagConstant [fc]) yes no) && !fc.ne() => (First no yes)
(LT (FlagEQ) yes no) -> (First no yes)
(LT (FlagLT_ULT) yes no) -> (First yes no)
(LT (FlagLT_UGT) yes no) -> (First yes no)
(LT (FlagGT_ULT) yes no) -> (First no yes)
(LT (FlagGT_UGT) yes no) -> (First no yes)
(LT (FlagConstant [fc]) yes no) && fc.lt() => (First yes no)
(LT (FlagConstant [fc]) yes no) && !fc.lt() => (First no yes)
(LE (FlagEQ) yes no) -> (First yes no)
(LE (FlagLT_ULT) yes no) -> (First yes no)
(LE (FlagLT_UGT) yes no) -> (First yes no)
(LE (FlagGT_ULT) yes no) -> (First no yes)
(LE (FlagGT_UGT) yes no) -> (First no yes)
(LE (FlagConstant [fc]) yes no) && fc.le() => (First yes no)
(LE (FlagConstant [fc]) yes no) && !fc.le() => (First no yes)
(GT (FlagEQ) yes no) -> (First no yes)
(GT (FlagLT_ULT) yes no) -> (First no yes)
(GT (FlagLT_UGT) yes no) -> (First no yes)
(GT (FlagGT_ULT) yes no) -> (First yes no)
(GT (FlagGT_UGT) yes no) -> (First yes no)
(GT (FlagConstant [fc]) yes no) && fc.gt() => (First yes no)
(GT (FlagConstant [fc]) yes no) && !fc.gt() => (First no yes)
(GE (FlagEQ) yes no) -> (First yes no)
(GE (FlagLT_ULT) yes no) -> (First no yes)
(GE (FlagLT_UGT) yes no) -> (First no yes)
(GE (FlagGT_ULT) yes no) -> (First yes no)
(GE (FlagGT_UGT) yes no) -> (First yes no)
(GE (FlagConstant [fc]) yes no) && fc.ge() => (First yes no)
(GE (FlagConstant [fc]) yes no) && !fc.ge() => (First no yes)
(ULT (FlagEQ) yes no) -> (First no yes)
(ULT (FlagLT_ULT) yes no) -> (First yes no)
(ULT (FlagLT_UGT) yes no) -> (First no yes)
(ULT (FlagGT_ULT) yes no) -> (First yes no)
(ULT (FlagGT_UGT) yes no) -> (First no yes)
(ULT (FlagConstant [fc]) yes no) && fc.ult() => (First yes no)
(ULT (FlagConstant [fc]) yes no) && !fc.ult() => (First no yes)
(ULE (FlagEQ) yes no) -> (First yes no)
(ULE (FlagLT_ULT) yes no) -> (First yes no)
(ULE (FlagLT_UGT) yes no) -> (First no yes)
(ULE (FlagGT_ULT) yes no) -> (First yes no)
(ULE (FlagGT_UGT) yes no) -> (First no yes)
(ULE (FlagConstant [fc]) yes no) && fc.ule() => (First yes no)
(ULE (FlagConstant [fc]) yes no) && !fc.ule() => (First no yes)
(UGT (FlagEQ) yes no) -> (First no yes)
(UGT (FlagLT_ULT) yes no) -> (First no yes)
(UGT (FlagLT_UGT) yes no) -> (First yes no)
(UGT (FlagGT_ULT) yes no) -> (First no yes)
(UGT (FlagGT_UGT) yes no) -> (First yes no)
(UGT (FlagConstant [fc]) yes no) && fc.ugt() => (First yes no)
(UGT (FlagConstant [fc]) yes no) && !fc.ugt() => (First no yes)
(UGE (FlagEQ) yes no) -> (First yes no)
(UGE (FlagLT_ULT) yes no) -> (First no yes)
(UGE (FlagLT_UGT) yes no) -> (First yes no)
(UGE (FlagGT_ULT) yes no) -> (First no yes)
(UGE (FlagGT_UGT) yes no) -> (First yes no)
(UGE (FlagConstant [fc]) yes no) && fc.uge() => (First yes no)
(UGE (FlagConstant [fc]) yes no) && !fc.uge() => (First no yes)
(LTnoov (FlagConstant [fc]) yes no) && fc.ltNoov() => (First yes no)
(LTnoov (FlagConstant [fc]) yes no) && !fc.ltNoov() => (First no yes)
(LEnoov (FlagConstant [fc]) yes no) && fc.leNoov() => (First yes no)
(LEnoov (FlagConstant [fc]) yes no) && !fc.leNoov() => (First no yes)
(GTnoov (FlagConstant [fc]) yes no) && fc.gtNoov() => (First yes no)
(GTnoov (FlagConstant [fc]) yes no) && !fc.gtNoov() => (First no yes)
(GEnoov (FlagConstant [fc]) yes no) && fc.geNoov() => (First yes no)
(GEnoov (FlagConstant [fc]) yes no) && !fc.geNoov() => (First no yes)
(Z (MOVDconst [0]) yes no) -> (First yes no)
(Z (MOVDconst [c]) yes no) && c != 0 -> (First no yes)
@ -1503,71 +1464,26 @@
(FGT (InvertFlags cmp) yes no) -> (FLT cmp yes no)
(FLE (InvertFlags cmp) yes no) -> (FGE cmp yes no)
(FGE (InvertFlags cmp) yes no) -> (FLE cmp yes no)
(LTnoov (InvertFlags cmp) yes no) => (GTnoov cmp yes no)
(GEnoov (InvertFlags cmp) yes no) => (LEnoov cmp yes no)
(LEnoov (InvertFlags cmp) yes no) => (GEnoov cmp yes no)
(GTnoov (InvertFlags cmp) yes no) => (LTnoov cmp yes no)
// absorb InvertFlags into CSEL(0)
(CSEL {cc} x y (InvertFlags cmp)) -> (CSEL {arm64Invert(cc.(Op))} x y cmp)
(CSEL0 {cc} x (InvertFlags cmp)) -> (CSEL0 {arm64Invert(cc.(Op))} x cmp)
// absorb flag constants into boolean values
(Equal (FlagEQ)) -> (MOVDconst [1])
(Equal (FlagLT_ULT)) -> (MOVDconst [0])
(Equal (FlagLT_UGT)) -> (MOVDconst [0])
(Equal (FlagGT_ULT)) -> (MOVDconst [0])
(Equal (FlagGT_UGT)) -> (MOVDconst [0])
(NotEqual (FlagEQ)) -> (MOVDconst [0])
(NotEqual (FlagLT_ULT)) -> (MOVDconst [1])
(NotEqual (FlagLT_UGT)) -> (MOVDconst [1])
(NotEqual (FlagGT_ULT)) -> (MOVDconst [1])
(NotEqual (FlagGT_UGT)) -> (MOVDconst [1])
(LessThan (FlagEQ)) -> (MOVDconst [0])
(LessThan (FlagLT_ULT)) -> (MOVDconst [1])
(LessThan (FlagLT_UGT)) -> (MOVDconst [1])
(LessThan (FlagGT_ULT)) -> (MOVDconst [0])
(LessThan (FlagGT_UGT)) -> (MOVDconst [0])
(LessThanU (FlagEQ)) -> (MOVDconst [0])
(LessThanU (FlagLT_ULT)) -> (MOVDconst [1])
(LessThanU (FlagLT_UGT)) -> (MOVDconst [0])
(LessThanU (FlagGT_ULT)) -> (MOVDconst [1])
(LessThanU (FlagGT_UGT)) -> (MOVDconst [0])
(LessEqual (FlagEQ)) -> (MOVDconst [1])
(LessEqual (FlagLT_ULT)) -> (MOVDconst [1])
(LessEqual (FlagLT_UGT)) -> (MOVDconst [1])
(LessEqual (FlagGT_ULT)) -> (MOVDconst [0])
(LessEqual (FlagGT_UGT)) -> (MOVDconst [0])
(LessEqualU (FlagEQ)) -> (MOVDconst [1])
(LessEqualU (FlagLT_ULT)) -> (MOVDconst [1])
(LessEqualU (FlagLT_UGT)) -> (MOVDconst [0])
(LessEqualU (FlagGT_ULT)) -> (MOVDconst [1])
(LessEqualU (FlagGT_UGT)) -> (MOVDconst [0])
(GreaterThan (FlagEQ)) -> (MOVDconst [0])
(GreaterThan (FlagLT_ULT)) -> (MOVDconst [0])
(GreaterThan (FlagLT_UGT)) -> (MOVDconst [0])
(GreaterThan (FlagGT_ULT)) -> (MOVDconst [1])
(GreaterThan (FlagGT_UGT)) -> (MOVDconst [1])
(GreaterThanU (FlagEQ)) -> (MOVDconst [0])
(GreaterThanU (FlagLT_ULT)) -> (MOVDconst [0])
(GreaterThanU (FlagLT_UGT)) -> (MOVDconst [1])
(GreaterThanU (FlagGT_ULT)) -> (MOVDconst [0])
(GreaterThanU (FlagGT_UGT)) -> (MOVDconst [1])
(GreaterEqual (FlagEQ)) -> (MOVDconst [1])
(GreaterEqual (FlagLT_ULT)) -> (MOVDconst [0])
(GreaterEqual (FlagLT_UGT)) -> (MOVDconst [0])
(GreaterEqual (FlagGT_ULT)) -> (MOVDconst [1])
(GreaterEqual (FlagGT_UGT)) -> (MOVDconst [1])
(GreaterEqualU (FlagEQ)) -> (MOVDconst [1])
(GreaterEqualU (FlagLT_ULT)) -> (MOVDconst [0])
(GreaterEqualU (FlagLT_UGT)) -> (MOVDconst [1])
(GreaterEqualU (FlagGT_ULT)) -> (MOVDconst [0])
(GreaterEqualU (FlagGT_UGT)) -> (MOVDconst [1])
(Equal (FlagConstant [fc])) => (MOVDconst [b2i(fc.eq())])
(NotEqual (FlagConstant [fc])) => (MOVDconst [b2i(fc.ne())])
(LessThan (FlagConstant [fc])) => (MOVDconst [b2i(fc.lt())])
(LessThanU (FlagConstant [fc])) => (MOVDconst [b2i(fc.ult())])
(LessEqual (FlagConstant [fc])) => (MOVDconst [b2i(fc.le())])
(LessEqualU (FlagConstant [fc])) => (MOVDconst [b2i(fc.ule())])
(GreaterThan (FlagConstant [fc])) => (MOVDconst [b2i(fc.gt())])
(GreaterThanU (FlagConstant [fc])) => (MOVDconst [b2i(fc.ugt())])
(GreaterEqual (FlagConstant [fc])) => (MOVDconst [b2i(fc.ge())])
(GreaterEqualU (FlagConstant [fc])) => (MOVDconst [b2i(fc.uge())])
// absorb InvertFlags into boolean values
(Equal (InvertFlags x)) -> (Equal x)

View file

@ -587,18 +587,12 @@ func init() {
// See runtime/stubs.go for a more detailed discussion.
{name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true},
// Constant flag values. For any comparison, there are 5 possible
// outcomes: the three from the signed total order (<,==,>) and the
// three from the unsigned total order. The == cases overlap.
// Note: there's a sixth "unordered" outcome for floating-point
// Constant flag value.
// Note: there's an "unordered" outcome for floating-point
// comparisons, but we don't use such a beast yet.
// These ops are for temporary use by rewrite rules. They
// This op is for temporary use by rewrite rules. It
// cannot appear in the generated assembly.
{name: "FlagEQ"}, // equal
{name: "FlagLT_ULT"}, // signed < and unsigned <
{name: "FlagLT_UGT"}, // signed < and unsigned >
{name: "FlagGT_UGT"}, // signed > and unsigned <
{name: "FlagGT_ULT"}, // signed > and unsigned >
{name: "FlagConstant", aux: "FlagConstant"},
// (InvertFlags (CMP a b)) == (CMP b a)
// InvertFlags is a pseudo-op which can't appear in assembly output.
@ -701,6 +695,10 @@ func init() {
{name: "FLE", controls: 1},
{name: "FGT", controls: 1},
{name: "FGE", controls: 1},
{name: "LTnoov", controls: 1}, // 'LT' but without honoring overflow
{name: "LEnoov", controls: 1}, // 'LE' but without honoring overflow
{name: "GTnoov", controls: 1}, // 'GT' but without honoring overflow
{name: "GEnoov", controls: 1}, // 'GE' but without honoring overflow
}
archs = append(archs, arch{

View file

@ -550,18 +550,12 @@ func init() {
{name: "LoweredPanicExtendB", argLength: 4, aux: "Int64", reg: regInfo{inputs: []regMask{r4, r1, r2}}, typ: "Mem", call: true}, // arg0=idxHi, arg1=idxLo, arg2=len, arg3=mem, returns memory. AuxInt contains report code (see PanicExtend in genericOps.go).
{name: "LoweredPanicExtendC", argLength: 4, aux: "Int64", reg: regInfo{inputs: []regMask{r4, r0, r1}}, typ: "Mem", call: true}, // arg0=idxHi, arg1=idxLo, arg2=len, arg3=mem, returns memory. AuxInt contains report code (see PanicExtend in genericOps.go).
// Constant flag values. For any comparison, there are 5 possible
// outcomes: the three from the signed total order (<,==,>) and the
// three from the unsigned total order. The == cases overlap.
// Note: there's a sixth "unordered" outcome for floating-point
// Constant flag value.
// Note: there's an "unordered" outcome for floating-point
// comparisons, but we don't use such a beast yet.
// These ops are for temporary use by rewrite rules. They
// This op is for temporary use by rewrite rules. It
// cannot appear in the generated assembly.
{name: "FlagEQ"}, // equal
{name: "FlagLT_ULT"}, // signed < and unsigned <
{name: "FlagLT_UGT"}, // signed < and unsigned >
{name: "FlagGT_UGT"}, // signed > and unsigned <
{name: "FlagGT_ULT"}, // signed > and unsigned >
{name: "FlagConstant", aux: "FlagConstant"},
// (InvertFlags (CMP a b)) == (CMP b a)
// InvertFlags is a pseudo-op which can't appear in assembly output.
@ -584,6 +578,10 @@ func init() {
{name: "ULE", controls: 1},
{name: "UGT", controls: 1},
{name: "UGE", controls: 1},
{name: "LTnoov", controls: 1}, // 'LT' but without honoring overflow
{name: "LEnoov", controls: 1}, // 'LE' but without honoring overflow
{name: "GTnoov", controls: 1}, // 'GT' but without honoring overflow
{name: "GEnoov", controls: 1}, // 'GE' but without honoring overflow
}
archs = append(archs, arch{

View file

@ -153,18 +153,18 @@
(Rsh8x64 x (MOVDconst [c])) && uint64(c) < 8 => (SRAWconst (SignExt8to32 x) [c])
(Rsh8Ux64 x (MOVDconst [c])) && uint64(c) < 8 => (SRWconst (ZeroExt8to32 x) [c])
(Lsh64x32 x (MOVDconst [c])) && uint32(c) < 64 => (SLDconst x [c])
(Rsh64x32 x (MOVDconst [c])) && uint32(c) < 64 => (SRADconst x [c])
(Rsh64Ux32 x (MOVDconst [c])) && uint32(c) < 64 => (SRDconst x [c])
(Lsh32x32 x (MOVDconst [c])) && uint32(c) < 32 => (SLWconst x [c])
(Rsh32x32 x (MOVDconst [c])) && uint32(c) < 32 => (SRAWconst x [c])
(Rsh32Ux32 x (MOVDconst [c])) && uint32(c) < 32 => (SRWconst x [c])
(Lsh16x32 x (MOVDconst [c])) && uint32(c) < 16 => (SLWconst x [c])
(Rsh16x32 x (MOVDconst [c])) && uint32(c) < 16 => (SRAWconst (SignExt16to32 x) [c])
(Rsh16Ux32 x (MOVDconst [c])) && uint32(c) < 16 => (SRWconst (ZeroExt16to32 x) [c])
(Lsh8x32 x (MOVDconst [c])) && uint32(c) < 8 => (SLWconst x [c])
(Rsh8x32 x (MOVDconst [c])) && uint32(c) < 8 => (SRAWconst (SignExt8to32 x) [c])
(Rsh8Ux32 x (MOVDconst [c])) && uint32(c) < 8 => (SRWconst (ZeroExt8to32 x) [c])
(Lsh64x32 x (MOVDconst [c])) && uint32(c) < 64 => (SLDconst x [c&63])
(Rsh64x32 x (MOVDconst [c])) && uint32(c) < 64 => (SRADconst x [c&63])
(Rsh64Ux32 x (MOVDconst [c])) && uint32(c) < 64 => (SRDconst x [c&63])
(Lsh32x32 x (MOVDconst [c])) && uint32(c) < 32 => (SLWconst x [c&31])
(Rsh32x32 x (MOVDconst [c])) && uint32(c) < 32 => (SRAWconst x [c&31])
(Rsh32Ux32 x (MOVDconst [c])) && uint32(c) < 32 => (SRWconst x [c&31])
(Lsh16x32 x (MOVDconst [c])) && uint32(c) < 16 => (SLWconst x [c&31])
(Rsh16x32 x (MOVDconst [c])) && uint32(c) < 16 => (SRAWconst (SignExt16to32 x) [c&15])
(Rsh16Ux32 x (MOVDconst [c])) && uint32(c) < 16 => (SRWconst (ZeroExt16to32 x) [c&15])
(Lsh8x32 x (MOVDconst [c])) && uint32(c) < 8 => (SLWconst x [c&7])
(Rsh8x32 x (MOVDconst [c])) && uint32(c) < 8 => (SRAWconst (SignExt8to32 x) [c&7])
(Rsh8Ux32 x (MOVDconst [c])) && uint32(c) < 8 => (SRWconst (ZeroExt8to32 x) [c&7])
// Lower bounded shifts first. No need to check shift value.
(Lsh64x(64|32|16|8) x y) && shiftIsBounded(v) => (SLD x y)
@ -285,7 +285,8 @@
(MaskIfNotCarry (FlagCarrySet)) => (MOVDconst [0])
(MaskIfNotCarry (FlagCarryClear)) => (MOVDconst [-1])
(S(RAD|RAW|RD|RW|LD|LW) x (MOVDconst [c])) => (S(RAD|RAW|RD|RW|LD|LW)const [c] x)
(S(RAD|RD|LD) x (MOVDconst [c])) => (S(RAD|RD|LD)const [c&63 | (c>>6&1*63)] x)
(S(RAW|RW|LW) x (MOVDconst [c])) => (S(RAW|RW|LW)const [c&31 | (c>>5&1*31)] x)
(Addr {sym} base) => (MOVDaddr {sym} [0] base)
(LocalAddr {sym} base _) => (MOVDaddr {sym} base)
@ -785,7 +786,7 @@
(FMOVDstore [off] {sym} ptr (MTVSRD x) mem) => (MOVDstore [off] {sym} ptr x mem)
(MOVDstore [off] {sym} ptr (MFVSRD x) mem) => (FMOVDstore [off] {sym} ptr x mem)
(MTVSRD (MOVDconst [c])) => (FMOVDconst [math.Float64frombits(uint64(c))])
(MTVSRD (MOVDconst [c])) && !math.IsNaN(math.Float64frombits(uint64(c))) => (FMOVDconst [math.Float64frombits(uint64(c))])
(MFVSRD (FMOVDconst [c])) => (MOVDconst [int64(math.Float64bits(c))])
(MTVSRD x:(MOVDload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) => @x.Block (FMOVDload [off] {sym} ptr mem)

View file

@ -194,12 +194,12 @@ func init() {
{name: "FMSUB", argLength: 3, reg: fp31, asm: "FMSUB"}, // arg0*arg1 - arg2
{name: "FMSUBS", argLength: 3, reg: fp31, asm: "FMSUBS"}, // arg0*arg1 - arg2
{name: "SRAD", argLength: 2, reg: gp21, asm: "SRAD"}, // arg0 >>a arg1, 64 bits (all sign if arg1 & 64 != 0)
{name: "SRAW", argLength: 2, reg: gp21, asm: "SRAW"}, // arg0 >>a arg1, 32 bits (all sign if arg1 & 32 != 0)
{name: "SRD", argLength: 2, reg: gp21, asm: "SRD"}, // arg0 >> arg1, 64 bits (0 if arg1 & 64 != 0)
{name: "SRW", argLength: 2, reg: gp21, asm: "SRW"}, // arg0 >> arg1, 32 bits (0 if arg1 & 32 != 0)
{name: "SLD", argLength: 2, reg: gp21, asm: "SLD"}, // arg0 << arg1, 64 bits (0 if arg1 & 64 != 0)
{name: "SLW", argLength: 2, reg: gp21, asm: "SLW"}, // arg0 << arg1, 32 bits (0 if arg1 & 32 != 0)
{name: "SRAD", argLength: 2, reg: gp21, asm: "SRAD"}, // signed arg0 >> (arg1&127), 64 bit width (note: 127, not 63!)
{name: "SRAW", argLength: 2, reg: gp21, asm: "SRAW"}, // signed arg0 >> (arg1&63), 32 bit width
{name: "SRD", argLength: 2, reg: gp21, asm: "SRD"}, // unsigned arg0 >> (arg1&127), 64 bit width
{name: "SRW", argLength: 2, reg: gp21, asm: "SRW"}, // unsigned arg0 >> (arg1&63), 32 bit width
{name: "SLD", argLength: 2, reg: gp21, asm: "SLD"}, // arg0 << (arg1&127), 64 bit width
{name: "SLW", argLength: 2, reg: gp21, asm: "SLW"}, // arg0 << (arg1&63), 32 bit width
{name: "ROTL", argLength: 2, reg: gp21, asm: "ROTL"}, // arg0 rotate left by arg1 mod 64
{name: "ROTLW", argLength: 2, reg: gp21, asm: "ROTLW"}, // uint32(arg0) rotate left by arg1 mod 32
@ -208,12 +208,12 @@ func init() {
{name: "ADDconstForCarry", argLength: 1, reg: regInfo{inputs: []regMask{gp | sp | sb}, clobbers: tmp}, aux: "Int16", asm: "ADDC", typ: "Flags"}, // _, carry := arg0 + auxint
{name: "MaskIfNotCarry", argLength: 1, reg: crgp, asm: "ADDME", typ: "Int64"}, // carry - 1 (if carry then 0 else -1)
{name: "SRADconst", argLength: 1, reg: gp11, asm: "SRAD", aux: "Int64"}, // arg0 >>a aux, 64 bits
{name: "SRAWconst", argLength: 1, reg: gp11, asm: "SRAW", aux: "Int64"}, // arg0 >>a aux, 32 bits
{name: "SRDconst", argLength: 1, reg: gp11, asm: "SRD", aux: "Int64"}, // arg0 >> aux, 64 bits
{name: "SRWconst", argLength: 1, reg: gp11, asm: "SRW", aux: "Int64"}, // arg0 >> aux, 32 bits
{name: "SLDconst", argLength: 1, reg: gp11, asm: "SLD", aux: "Int64"}, // arg0 << aux, 64 bits
{name: "SLWconst", argLength: 1, reg: gp11, asm: "SLW", aux: "Int64"}, // arg0 << aux, 32 bits
{name: "SRADconst", argLength: 1, reg: gp11, asm: "SRAD", aux: "Int64"}, // signed arg0 >> auxInt, 0 <= auxInt < 64, 64 bit width
{name: "SRAWconst", argLength: 1, reg: gp11, asm: "SRAW", aux: "Int64"}, // signed arg0 >> auxInt, 0 <= auxInt < 32, 32 bit width
{name: "SRDconst", argLength: 1, reg: gp11, asm: "SRD", aux: "Int64"}, // unsigned arg0 >> auxInt, 0 <= auxInt < 64, 64 bit width
{name: "SRWconst", argLength: 1, reg: gp11, asm: "SRW", aux: "Int64"}, // unsigned arg0 >> auxInt, 0 <= auxInt < 32, 32 bit width
{name: "SLDconst", argLength: 1, reg: gp11, asm: "SLD", aux: "Int64"}, // arg0 << auxInt, 0 <= auxInt < 64, 64 bit width
{name: "SLWconst", argLength: 1, reg: gp11, asm: "SLW", aux: "Int64"}, // arg0 << auxInt, 0 <= auxInt < 32, 32 bit width
{name: "ROTLconst", argLength: 1, reg: gp11, asm: "ROTL", aux: "Int64"}, // arg0 rotate left by auxInt bits
{name: "ROTLWconst", argLength: 1, reg: gp11, asm: "ROTLW", aux: "Int64"}, // uint32(arg0) rotate left by auxInt bits

View file

@ -445,16 +445,6 @@
(Addr {sym} base) => (MOVaddr {sym} [0] base)
(LocalAddr {sym} base _) => (MOVaddr {sym} base)
// Conditional branches
//
// cond is 1 if true.
//
// TODO(prattmic): RISCV branch instructions take two operands to compare,
// so we could generate more efficient code by computing the condition in the
// branch itself. This should be revisited now that the compiler has support
// for two control values (https://golang.org/cl/196557).
(If cond yes no) => (BNEZ cond yes no)
// Calls
(StaticCall ...) => (CALLstatic ...)
(ClosureCall ...) => (CALLclosure ...)
@ -480,11 +470,31 @@
(AtomicExchange32 ...) => (LoweredAtomicExchange32 ...)
(AtomicExchange64 ...) => (LoweredAtomicExchange64 ...)
// Conditional branches
(If cond yes no) => (BNEZ cond yes no)
// Optimizations
// Absorb SNEZ into branch.
// Absorb SEQZ/SNEZ into branch.
(BEQZ (SEQZ x) yes no) => (BNEZ x yes no)
(BEQZ (SNEZ x) yes no) => (BEQZ x yes no)
(BNEZ (SEQZ x) yes no) => (BEQZ x yes no)
(BNEZ (SNEZ x) yes no) => (BNEZ x yes no)
// Convert BEQZ/BNEZ into more optimal branch conditions.
(BEQZ (SUB x y) yes no) => (BEQ x y yes no)
(BNEZ (SUB x y) yes no) => (BNE x y yes no)
(BEQZ (SLT x y) yes no) => (BGE x y yes no)
(BNEZ (SLT x y) yes no) => (BLT x y yes no)
(BEQZ (SLTU x y) yes no) => (BGEU x y yes no)
(BNEZ (SLTU x y) yes no) => (BLTU x y yes no)
// Convert branch with zero to BEQZ/BNEZ.
(BEQ (MOVDconst [0]) cond yes no) => (BEQZ cond yes no)
(BEQ cond (MOVDconst [0]) yes no) => (BEQZ cond yes no)
(BNE (MOVDconst [0]) cond yes no) => (BNEZ cond yes no)
(BNE cond (MOVDconst [0]) yes no) => (BNEZ cond yes no)
// Store zero
(MOVBstore [off] {sym} ptr (MOVBconst [0]) mem) => (MOVBstorezero [off] {sym} ptr mem)
(MOVHstore [off] {sym} ptr (MOVHconst [0]) mem) => (MOVHstorezero [off] {sym} ptr mem)

View file

@ -394,24 +394,25 @@ func init() {
{name: "MOVDconst", reg: gp01, asm: "MOVD", typ: "UInt64", aux: "Int64", rematerializeable: true}, // auxint
{name: "LDGR", argLength: 1, reg: gpfp, asm: "LDGR"}, // move int64 to float64 (no conversion)
{name: "LGDR", argLength: 1, reg: fpgp, asm: "LGDR"}, // move float64 to int64 (no conversion)
{name: "CFDBRA", argLength: 1, reg: fpgp, asm: "CFDBRA"}, // convert float64 to int32
{name: "CGDBRA", argLength: 1, reg: fpgp, asm: "CGDBRA"}, // convert float64 to int64
{name: "CFEBRA", argLength: 1, reg: fpgp, asm: "CFEBRA"}, // convert float32 to int32
{name: "CGEBRA", argLength: 1, reg: fpgp, asm: "CGEBRA"}, // convert float32 to int64
{name: "CEFBRA", argLength: 1, reg: gpfp, asm: "CEFBRA"}, // convert int32 to float32
{name: "CDFBRA", argLength: 1, reg: gpfp, asm: "CDFBRA"}, // convert int32 to float64
{name: "CEGBRA", argLength: 1, reg: gpfp, asm: "CEGBRA"}, // convert int64 to float32
{name: "CDGBRA", argLength: 1, reg: gpfp, asm: "CDGBRA"}, // convert int64 to float64
{name: "CLFEBR", argLength: 1, reg: fpgp, asm: "CLFEBR"}, // convert float32 to uint32
{name: "CLFDBR", argLength: 1, reg: fpgp, asm: "CLFDBR"}, // convert float64 to uint32
{name: "CLGEBR", argLength: 1, reg: fpgp, asm: "CLGEBR"}, // convert float32 to uint64
{name: "CLGDBR", argLength: 1, reg: fpgp, asm: "CLGDBR"}, // convert float64 to uint64
{name: "CELFBR", argLength: 1, reg: gpfp, asm: "CELFBR"}, // convert uint32 to float32
{name: "CDLFBR", argLength: 1, reg: gpfp, asm: "CDLFBR"}, // convert uint32 to float64
{name: "CELGBR", argLength: 1, reg: gpfp, asm: "CELGBR"}, // convert uint64 to float32
{name: "CDLGBR", argLength: 1, reg: gpfp, asm: "CDLGBR"}, // convert uint64 to float64
{name: "LDGR", argLength: 1, reg: gpfp, asm: "LDGR"}, // move int64 to float64 (no conversion)
{name: "LGDR", argLength: 1, reg: fpgp, asm: "LGDR"}, // move float64 to int64 (no conversion)
{name: "CFDBRA", argLength: 1, reg: fpgp, asm: "CFDBRA", clobberFlags: true}, // convert float64 to int32
{name: "CGDBRA", argLength: 1, reg: fpgp, asm: "CGDBRA", clobberFlags: true}, // convert float64 to int64
{name: "CFEBRA", argLength: 1, reg: fpgp, asm: "CFEBRA", clobberFlags: true}, // convert float32 to int32
{name: "CGEBRA", argLength: 1, reg: fpgp, asm: "CGEBRA", clobberFlags: true}, // convert float32 to int64
{name: "CEFBRA", argLength: 1, reg: gpfp, asm: "CEFBRA", clobberFlags: true}, // convert int32 to float32
{name: "CDFBRA", argLength: 1, reg: gpfp, asm: "CDFBRA", clobberFlags: true}, // convert int32 to float64
{name: "CEGBRA", argLength: 1, reg: gpfp, asm: "CEGBRA", clobberFlags: true}, // convert int64 to float32
{name: "CDGBRA", argLength: 1, reg: gpfp, asm: "CDGBRA", clobberFlags: true}, // convert int64 to float64
{name: "CLFEBR", argLength: 1, reg: fpgp, asm: "CLFEBR", clobberFlags: true}, // convert float32 to uint32
{name: "CLFDBR", argLength: 1, reg: fpgp, asm: "CLFDBR", clobberFlags: true}, // convert float64 to uint32
{name: "CLGEBR", argLength: 1, reg: fpgp, asm: "CLGEBR", clobberFlags: true}, // convert float32 to uint64
{name: "CLGDBR", argLength: 1, reg: fpgp, asm: "CLGDBR", clobberFlags: true}, // convert float64 to uint64
{name: "CELFBR", argLength: 1, reg: gpfp, asm: "CELFBR", clobberFlags: true}, // convert uint32 to float32
{name: "CDLFBR", argLength: 1, reg: gpfp, asm: "CDLFBR", clobberFlags: true}, // convert uint32 to float64
{name: "CELGBR", argLength: 1, reg: gpfp, asm: "CELGBR", clobberFlags: true}, // convert uint64 to float32
{name: "CDLGBR", argLength: 1, reg: gpfp, asm: "CDLGBR", clobberFlags: true}, // convert uint64 to float64
{name: "LEDBR", argLength: 1, reg: fp11, asm: "LEDBR"}, // convert float64 to float32
{name: "LDEBR", argLength: 1, reg: fp11, asm: "LDEBR"}, // convert float32 to float64

View file

@ -1423,7 +1423,7 @@ func parseValue(val string, arch arch, loc string) (op opData, oparch, typ, auxi
func opHasAuxInt(op opData) bool {
switch op.aux {
case "Bool", "Int8", "Int16", "Int32", "Int64", "Int128", "Float32", "Float64", "SymOff", "SymValAndOff", "TypSize", "ARM64BitField":
case "Bool", "Int8", "Int16", "Int32", "Int64", "Int128", "Float32", "Float64", "SymOff", "SymValAndOff", "TypSize", "ARM64BitField", "FlagConstant":
return true
}
return false
@ -1818,6 +1818,8 @@ func (op opData) auxIntType() string {
return "int64"
case "CCop":
return "Op"
case "FlagConstant":
return "flagConstant"
default:
return "invalid"
}

View file

@ -77,6 +77,7 @@ const (
auxInt128 // auxInt represents a 128-bit integer. Always 0.
auxFloat32 // auxInt is a float32 (encoded with math.Float64bits)
auxFloat64 // auxInt is a float64 (encoded with math.Float64bits)
auxFlagConstant // auxInt is a flagConstant
auxString // aux is a string
auxSym // aux is a symbol (a *gc.Node for locals, an *obj.LSym for globals, or nil for none)
auxSymOff // aux is a symbol, auxInt is an offset

View file

@ -61,6 +61,10 @@ const (
BlockARMULE
BlockARMUGT
BlockARMUGE
BlockARMLTnoov
BlockARMLEnoov
BlockARMGTnoov
BlockARMGEnoov
BlockARM64EQ
BlockARM64NE
@ -82,6 +86,10 @@ const (
BlockARM64FLE
BlockARM64FGT
BlockARM64FGE
BlockARM64LTnoov
BlockARM64LEnoov
BlockARM64GTnoov
BlockARM64GEnoov
BlockMIPSEQ
BlockMIPSNE
@ -181,37 +189,45 @@ var blockString = [...]string{
BlockAMD64ORD: "ORD",
BlockAMD64NAN: "NAN",
BlockARMEQ: "EQ",
BlockARMNE: "NE",
BlockARMLT: "LT",
BlockARMLE: "LE",
BlockARMGT: "GT",
BlockARMGE: "GE",
BlockARMULT: "ULT",
BlockARMULE: "ULE",
BlockARMUGT: "UGT",
BlockARMUGE: "UGE",
BlockARMEQ: "EQ",
BlockARMNE: "NE",
BlockARMLT: "LT",
BlockARMLE: "LE",
BlockARMGT: "GT",
BlockARMGE: "GE",
BlockARMULT: "ULT",
BlockARMULE: "ULE",
BlockARMUGT: "UGT",
BlockARMUGE: "UGE",
BlockARMLTnoov: "LTnoov",
BlockARMLEnoov: "LEnoov",
BlockARMGTnoov: "GTnoov",
BlockARMGEnoov: "GEnoov",
BlockARM64EQ: "EQ",
BlockARM64NE: "NE",
BlockARM64LT: "LT",
BlockARM64LE: "LE",
BlockARM64GT: "GT",
BlockARM64GE: "GE",
BlockARM64ULT: "ULT",
BlockARM64ULE: "ULE",
BlockARM64UGT: "UGT",
BlockARM64UGE: "UGE",
BlockARM64Z: "Z",
BlockARM64NZ: "NZ",
BlockARM64ZW: "ZW",
BlockARM64NZW: "NZW",
BlockARM64TBZ: "TBZ",
BlockARM64TBNZ: "TBNZ",
BlockARM64FLT: "FLT",
BlockARM64FLE: "FLE",
BlockARM64FGT: "FGT",
BlockARM64FGE: "FGE",
BlockARM64EQ: "EQ",
BlockARM64NE: "NE",
BlockARM64LT: "LT",
BlockARM64LE: "LE",
BlockARM64GT: "GT",
BlockARM64GE: "GE",
BlockARM64ULT: "ULT",
BlockARM64ULE: "ULE",
BlockARM64UGT: "UGT",
BlockARM64UGE: "UGE",
BlockARM64Z: "Z",
BlockARM64NZ: "NZ",
BlockARM64ZW: "ZW",
BlockARM64NZW: "NZW",
BlockARM64TBZ: "TBZ",
BlockARM64TBNZ: "TBNZ",
BlockARM64FLT: "FLT",
BlockARM64FLE: "FLE",
BlockARM64FGT: "FGT",
BlockARM64FGE: "FGE",
BlockARM64LTnoov: "LTnoov",
BlockARM64LEnoov: "LEnoov",
BlockARM64GTnoov: "GTnoov",
BlockARM64GEnoov: "GEnoov",
BlockMIPSEQ: "EQ",
BlockMIPSNE: "NE",
@ -1267,11 +1283,7 @@ const (
OpARMLoweredPanicExtendA
OpARMLoweredPanicExtendB
OpARMLoweredPanicExtendC
OpARMFlagEQ
OpARMFlagLT_ULT
OpARMFlagLT_UGT
OpARMFlagGT_UGT
OpARMFlagGT_ULT
OpARMFlagConstant
OpARMInvertFlags
OpARMLoweredWB
@ -1542,11 +1554,7 @@ const (
OpARM64LoweredGetClosurePtr
OpARM64LoweredGetCallerSP
OpARM64LoweredGetCallerPC
OpARM64FlagEQ
OpARM64FlagLT_ULT
OpARM64FlagLT_UGT
OpARM64FlagGT_UGT
OpARM64FlagGT_ULT
OpARM64FlagConstant
OpARM64InvertFlags
OpARM64LDAR
OpARM64LDARB
@ -16895,29 +16903,10 @@ var opcodeTable = [...]opInfo{
},
},
{
name: "FlagEQ",
argLen: 0,
reg: regInfo{},
},
{
name: "FlagLT_ULT",
argLen: 0,
reg: regInfo{},
},
{
name: "FlagLT_UGT",
argLen: 0,
reg: regInfo{},
},
{
name: "FlagGT_UGT",
argLen: 0,
reg: regInfo{},
},
{
name: "FlagGT_ULT",
argLen: 0,
reg: regInfo{},
name: "FlagConstant",
auxType: auxFlagConstant,
argLen: 0,
reg: regInfo{},
},
{
name: "InvertFlags",
@ -20505,29 +20494,10 @@ var opcodeTable = [...]opInfo{
},
},
{
name: "FlagEQ",
argLen: 0,
reg: regInfo{},
},
{
name: "FlagLT_ULT",
argLen: 0,
reg: regInfo{},
},
{
name: "FlagLT_UGT",
argLen: 0,
reg: regInfo{},
},
{
name: "FlagGT_UGT",
argLen: 0,
reg: regInfo{},
},
{
name: "FlagGT_ULT",
argLen: 0,
reg: regInfo{},
name: "FlagConstant",
auxType: auxFlagConstant,
argLen: 0,
reg: regInfo{},
},
{
name: "InvertFlags",
@ -30175,9 +30145,10 @@ var opcodeTable = [...]opInfo{
},
},
{
name: "CFDBRA",
argLen: 1,
asm: s390x.ACFDBRA,
name: "CFDBRA",
argLen: 1,
clobberFlags: true,
asm: s390x.ACFDBRA,
reg: regInfo{
inputs: []inputInfo{
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
@ -30188,9 +30159,10 @@ var opcodeTable = [...]opInfo{
},
},
{
name: "CGDBRA",
argLen: 1,
asm: s390x.ACGDBRA,
name: "CGDBRA",
argLen: 1,
clobberFlags: true,
asm: s390x.ACGDBRA,
reg: regInfo{
inputs: []inputInfo{
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
@ -30201,9 +30173,10 @@ var opcodeTable = [...]opInfo{
},
},
{
name: "CFEBRA",
argLen: 1,
asm: s390x.ACFEBRA,
name: "CFEBRA",
argLen: 1,
clobberFlags: true,
asm: s390x.ACFEBRA,
reg: regInfo{
inputs: []inputInfo{
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
@ -30214,9 +30187,10 @@ var opcodeTable = [...]opInfo{
},
},
{
name: "CGEBRA",
argLen: 1,
asm: s390x.ACGEBRA,
name: "CGEBRA",
argLen: 1,
clobberFlags: true,
asm: s390x.ACGEBRA,
reg: regInfo{
inputs: []inputInfo{
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
@ -30227,9 +30201,10 @@ var opcodeTable = [...]opInfo{
},
},
{
name: "CEFBRA",
argLen: 1,
asm: s390x.ACEFBRA,
name: "CEFBRA",
argLen: 1,
clobberFlags: true,
asm: s390x.ACEFBRA,
reg: regInfo{
inputs: []inputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
@ -30240,9 +30215,10 @@ var opcodeTable = [...]opInfo{
},
},
{
name: "CDFBRA",
argLen: 1,
asm: s390x.ACDFBRA,
name: "CDFBRA",
argLen: 1,
clobberFlags: true,
asm: s390x.ACDFBRA,
reg: regInfo{
inputs: []inputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
@ -30253,9 +30229,10 @@ var opcodeTable = [...]opInfo{
},
},
{
name: "CEGBRA",
argLen: 1,
asm: s390x.ACEGBRA,
name: "CEGBRA",
argLen: 1,
clobberFlags: true,
asm: s390x.ACEGBRA,
reg: regInfo{
inputs: []inputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
@ -30266,9 +30243,10 @@ var opcodeTable = [...]opInfo{
},
},
{
name: "CDGBRA",
argLen: 1,
asm: s390x.ACDGBRA,
name: "CDGBRA",
argLen: 1,
clobberFlags: true,
asm: s390x.ACDGBRA,
reg: regInfo{
inputs: []inputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
@ -30279,9 +30257,10 @@ var opcodeTable = [...]opInfo{
},
},
{
name: "CLFEBR",
argLen: 1,
asm: s390x.ACLFEBR,
name: "CLFEBR",
argLen: 1,
clobberFlags: true,
asm: s390x.ACLFEBR,
reg: regInfo{
inputs: []inputInfo{
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
@ -30292,9 +30271,10 @@ var opcodeTable = [...]opInfo{
},
},
{
name: "CLFDBR",
argLen: 1,
asm: s390x.ACLFDBR,
name: "CLFDBR",
argLen: 1,
clobberFlags: true,
asm: s390x.ACLFDBR,
reg: regInfo{
inputs: []inputInfo{
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
@ -30305,9 +30285,10 @@ var opcodeTable = [...]opInfo{
},
},
{
name: "CLGEBR",
argLen: 1,
asm: s390x.ACLGEBR,
name: "CLGEBR",
argLen: 1,
clobberFlags: true,
asm: s390x.ACLGEBR,
reg: regInfo{
inputs: []inputInfo{
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
@ -30318,9 +30299,10 @@ var opcodeTable = [...]opInfo{
},
},
{
name: "CLGDBR",
argLen: 1,
asm: s390x.ACLGDBR,
name: "CLGDBR",
argLen: 1,
clobberFlags: true,
asm: s390x.ACLGDBR,
reg: regInfo{
inputs: []inputInfo{
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
@ -30331,9 +30313,10 @@ var opcodeTable = [...]opInfo{
},
},
{
name: "CELFBR",
argLen: 1,
asm: s390x.ACELFBR,
name: "CELFBR",
argLen: 1,
clobberFlags: true,
asm: s390x.ACELFBR,
reg: regInfo{
inputs: []inputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
@ -30344,9 +30327,10 @@ var opcodeTable = [...]opInfo{
},
},
{
name: "CDLFBR",
argLen: 1,
asm: s390x.ACDLFBR,
name: "CDLFBR",
argLen: 1,
clobberFlags: true,
asm: s390x.ACDLFBR,
reg: regInfo{
inputs: []inputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
@ -30357,9 +30341,10 @@ var opcodeTable = [...]opInfo{
},
},
{
name: "CELGBR",
argLen: 1,
asm: s390x.ACELGBR,
name: "CELGBR",
argLen: 1,
clobberFlags: true,
asm: s390x.ACELGBR,
reg: regInfo{
inputs: []inputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
@ -30370,9 +30355,10 @@ var opcodeTable = [...]opInfo{
},
},
{
name: "CDLGBR",
argLen: 1,
asm: s390x.ACDLGBR,
name: "CDLGBR",
argLen: 1,
clobberFlags: true,
asm: s390x.ACDLGBR,
reg: regInfo{
inputs: []inputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14

View file

@ -1189,15 +1189,38 @@ func simplifyBlock(sdom SparseTree, ft *factsTable, b *Block) {
}
v.Op = ctzNonZeroOp[v.Op]
}
case OpRsh8x8, OpRsh8x16, OpRsh8x32, OpRsh8x64,
OpRsh16x8, OpRsh16x16, OpRsh16x32, OpRsh16x64,
OpRsh32x8, OpRsh32x16, OpRsh32x32, OpRsh32x64,
OpRsh64x8, OpRsh64x16, OpRsh64x32, OpRsh64x64:
// Check whether, for a >> b, we know that a is non-negative
// and b is all of a's bits except the MSB. If so, a is shifted to zero.
bits := 8 * v.Type.Size()
if v.Args[1].isGenericIntConst() && v.Args[1].AuxInt >= bits-1 && ft.isNonNegative(v.Args[0]) {
if b.Func.pass.debug > 0 {
b.Func.Warnl(v.Pos, "Proved %v shifts to zero", v.Op)
}
switch bits {
case 64:
v.reset(OpConst64)
case 32:
v.reset(OpConst32)
case 16:
v.reset(OpConst16)
case 8:
v.reset(OpConst8)
default:
panic("unexpected integer size")
}
v.AuxInt = 0
continue // Be sure not to fallthrough - this is no longer OpRsh.
}
// If the Rsh hasn't been replaced with 0, still check if it is bounded.
fallthrough
case OpLsh8x8, OpLsh8x16, OpLsh8x32, OpLsh8x64,
OpLsh16x8, OpLsh16x16, OpLsh16x32, OpLsh16x64,
OpLsh32x8, OpLsh32x16, OpLsh32x32, OpLsh32x64,
OpLsh64x8, OpLsh64x16, OpLsh64x32, OpLsh64x64,
OpRsh8x8, OpRsh8x16, OpRsh8x32, OpRsh8x64,
OpRsh16x8, OpRsh16x16, OpRsh16x32, OpRsh16x64,
OpRsh32x8, OpRsh32x16, OpRsh32x32, OpRsh32x64,
OpRsh64x8, OpRsh64x16, OpRsh64x32, OpRsh64x64,
OpRsh8Ux8, OpRsh8Ux16, OpRsh8Ux32, OpRsh8Ux64,
OpRsh16Ux8, OpRsh16Ux16, OpRsh16Ux32, OpRsh16Ux64,
OpRsh32Ux8, OpRsh32Ux16, OpRsh32Ux32, OpRsh32Ux64,

View file

@ -511,6 +511,14 @@ func b2i(b bool) int64 {
return 0
}
// b2i32 translates a boolean value to 0 or 1.
func b2i32(b bool) int32 {
if b {
return 1
}
return 0
}
// shiftIsBounded reports whether (left/right) shift Value v is known to be bounded.
// A shift is bounded if it is shifting by less than the width of the shifted value.
func shiftIsBounded(v *Value) bool {
@ -616,6 +624,9 @@ func auxIntToInt128(x int64) int128 {
}
return 0
}
func auxIntToFlagConstant(x int64) flagConstant {
return flagConstant(x)
}
func boolToAuxInt(b bool) int64 {
if b {
@ -653,6 +664,9 @@ func int128ToAuxInt(x int128) int64 {
}
return 0
}
func flagConstantToAuxInt(x flagConstant) int64 {
return int64(x)
}
func auxToString(i interface{}) string {
return i.(string)
@ -997,52 +1011,42 @@ func arm64Invert(op Op) Op {
func ccARM64Eval(cc interface{}, flags *Value) int {
op := cc.(Op)
fop := flags.Op
switch fop {
case OpARM64InvertFlags:
if fop == OpARM64InvertFlags {
return -ccARM64Eval(op, flags.Args[0])
case OpARM64FlagEQ:
switch op {
case OpARM64Equal, OpARM64GreaterEqual, OpARM64LessEqual,
OpARM64GreaterEqualU, OpARM64LessEqualU:
return 1
default:
return -1
}
case OpARM64FlagLT_ULT:
switch op {
case OpARM64LessThan, OpARM64LessThanU,
OpARM64LessEqual, OpARM64LessEqualU:
return 1
default:
return -1
}
case OpARM64FlagLT_UGT:
switch op {
case OpARM64LessThan, OpARM64GreaterThanU,
OpARM64LessEqual, OpARM64GreaterEqualU:
return 1
default:
return -1
}
case OpARM64FlagGT_ULT:
switch op {
case OpARM64GreaterThan, OpARM64LessThanU,
OpARM64GreaterEqual, OpARM64LessEqualU:
return 1
default:
return -1
}
case OpARM64FlagGT_UGT:
switch op {
case OpARM64GreaterThan, OpARM64GreaterThanU,
OpARM64GreaterEqual, OpARM64GreaterEqualU:
return 1
default:
return -1
}
default:
}
if fop != OpARM64FlagConstant {
return 0
}
fc := flagConstant(flags.AuxInt)
b2i := func(b bool) int {
if b {
return 1
}
return -1
}
switch op {
case OpARM64Equal:
return b2i(fc.eq())
case OpARM64NotEqual:
return b2i(fc.ne())
case OpARM64LessThan:
return b2i(fc.lt())
case OpARM64LessThanU:
return b2i(fc.ult())
case OpARM64GreaterThan:
return b2i(fc.gt())
case OpARM64GreaterThanU:
return b2i(fc.ugt())
case OpARM64LessEqual:
return b2i(fc.le())
case OpARM64LessEqualU:
return b2i(fc.ule())
case OpARM64GreaterEqual:
return b2i(fc.ge())
case OpARM64GreaterEqualU:
return b2i(fc.uge())
}
return 0
}
// logRule logs the use of the rule s. This will only be enabled if
@ -1473,3 +1477,170 @@ func sequentialAddresses(x, y *Value, n int64) bool {
}
return false
}
// flagConstant represents the result of a compile-time comparison.
// The sense of these flags does not necessarily represent the hardware's notion
// of a flags register - these are just a compile-time construct.
// We happen to match the semantics to those of arm/arm64.
// Note that these semantics differ from x86: the carry flag has the opposite
// sense on a subtraction!
// On amd64, C=1 represents a borrow, e.g. SBB on amd64 does x - y - C.
// On arm64, C=0 represents a borrow, e.g. SBC on arm64 does x - y - ^C.
// (because it does x + ^y + C).
// See https://en.wikipedia.org/wiki/Carry_flag#Vs._borrow_flag
type flagConstant uint8
// N reports whether the result of an operation is negative (high bit set).
func (fc flagConstant) N() bool {
return fc&1 != 0
}
// Z reports whether the result of an operation is 0.
func (fc flagConstant) Z() bool {
return fc&2 != 0
}
// C reports whether an unsigned add overflowed (carry), or an
// unsigned subtract did not underflow (borrow).
func (fc flagConstant) C() bool {
return fc&4 != 0
}
// V reports whether a signed operation overflowed or underflowed.
func (fc flagConstant) V() bool {
return fc&8 != 0
}
func (fc flagConstant) eq() bool {
return fc.Z()
}
func (fc flagConstant) ne() bool {
return !fc.Z()
}
func (fc flagConstant) lt() bool {
return fc.N() != fc.V()
}
func (fc flagConstant) le() bool {
return fc.Z() || fc.lt()
}
func (fc flagConstant) gt() bool {
return !fc.Z() && fc.ge()
}
func (fc flagConstant) ge() bool {
return fc.N() == fc.V()
}
func (fc flagConstant) ult() bool {
return !fc.C()
}
func (fc flagConstant) ule() bool {
return fc.Z() || fc.ult()
}
func (fc flagConstant) ugt() bool {
return !fc.Z() && fc.uge()
}
func (fc flagConstant) uge() bool {
return fc.C()
}
func (fc flagConstant) ltNoov() bool {
return fc.lt() && !fc.V()
}
func (fc flagConstant) leNoov() bool {
return fc.le() && !fc.V()
}
func (fc flagConstant) gtNoov() bool {
return fc.gt() && !fc.V()
}
func (fc flagConstant) geNoov() bool {
return fc.ge() && !fc.V()
}
func (fc flagConstant) String() string {
return fmt.Sprintf("N=%v,Z=%v,C=%v,V=%v", fc.N(), fc.Z(), fc.C(), fc.V())
}
type flagConstantBuilder struct {
N bool
Z bool
C bool
V bool
}
func (fcs flagConstantBuilder) encode() flagConstant {
var fc flagConstant
if fcs.N {
fc |= 1
}
if fcs.Z {
fc |= 2
}
if fcs.C {
fc |= 4
}
if fcs.V {
fc |= 8
}
return fc
}
// Note: addFlags(x,y) != subFlags(x,-y) in some situations:
// - the results of the C flag are different
// - the results of the V flag when y==minint are different
// addFlags64 returns the flags that would be set from computing x+y.
func addFlags64(x, y int64) flagConstant {
var fcb flagConstantBuilder
fcb.Z = x+y == 0
fcb.N = x+y < 0
fcb.C = uint64(x+y) < uint64(x)
fcb.V = x >= 0 && y >= 0 && x+y < 0 || x < 0 && y < 0 && x+y >= 0
return fcb.encode()
}
// subFlags64 returns the flags that would be set from computing x-y.
func subFlags64(x, y int64) flagConstant {
var fcb flagConstantBuilder
fcb.Z = x-y == 0
fcb.N = x-y < 0
fcb.C = uint64(y) <= uint64(x) // This code follows the arm carry flag model.
fcb.V = x >= 0 && y < 0 && x-y < 0 || x < 0 && y >= 0 && x-y >= 0
return fcb.encode()
}
// addFlags32 returns the flags that would be set from computing x+y.
func addFlags32(x, y int32) flagConstant {
var fcb flagConstantBuilder
fcb.Z = x+y == 0
fcb.N = x+y < 0
fcb.C = uint32(x+y) < uint32(x)
fcb.V = x >= 0 && y >= 0 && x+y < 0 || x < 0 && y < 0 && x+y >= 0
return fcb.encode()
}
// subFlags32 returns the flags that would be set from computing x-y.
func subFlags32(x, y int32) flagConstant {
var fcb flagConstantBuilder
fcb.Z = x-y == 0
fcb.N = x-y < 0
fcb.C = uint32(y) <= uint32(x) // This code follows the arm carry flag model.
fcb.V = x >= 0 && y < 0 && x-y < 0 || x < 0 && y >= 0 && x-y >= 0
return fcb.encode()
}
// logicFlags64 returns flags set to the sign/zeroness of x.
// C and V are set to false.
func logicFlags64(x int64) flagConstant {
var fcb flagConstantBuilder
fcb.Z = x == 0
fcb.N = x < 0
return fcb.encode()
}
// logicFlags32 returns flags set to the sign/zeroness of x.
// C and V are set to false.
func logicFlags32(x int32) flagConstant {
var fcb flagConstantBuilder
fcb.Z = x == 0
fcb.N = x < 0
return fcb.encode()
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,597 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ssa
import (
"math"
"math/rand"
"testing"
)
var (
x64 int64 = math.MaxInt64 - 2
x64b int64 = math.MaxInt64 - 2
x64c int64 = math.MaxInt64 - 2
y64 int64 = math.MinInt64 + 1
x32 int32 = math.MaxInt32 - 2
x32b int32 = math.MaxInt32 - 2
x32c int32 = math.MaxInt32 - 2
y32 int32 = math.MinInt32 + 1
one64 int64 = 1
one32 int32 = 1
v64 int64 = 11 // ensure it's not 2**n +/- 1
v64_n int64 = -11
v32 int32 = 11
v32_n int32 = -11
uv32 uint32 = 19
uz uint8 = 1 // for lowering to SLL/SRL/SRA
)
var crTests = []struct {
name string
tf func(t *testing.T)
}{
{"AddConst64", testAddConst64},
{"AddConst32", testAddConst32},
{"AddVar64", testAddVar64},
{"AddVar32", testAddVar32},
{"MAddVar64", testMAddVar64},
{"MAddVar32", testMAddVar32},
{"MSubVar64", testMSubVar64},
{"MSubVar32", testMSubVar32},
{"AddShift32", testAddShift32},
{"SubShift32", testSubShift32},
}
var crBenches = []struct {
name string
bf func(b *testing.B)
}{
{"SoloJump", benchSoloJump},
{"CombJump", benchCombJump},
}
// Test int32/int64's add/sub/madd/msub operations with boundary values to
// ensure the optimization to 'comparing to zero' expressions of if-statements
// yield expected results.
// 32 rewriting rules are covered. At least two scenarios for "Canonicalize
// the order of arguments to comparisons", which helps with CSE, are covered.
// The tedious if-else structures are necessary to ensure all concerned rules
// and machine code sequences are covered.
// It's for arm64 initially, please see https://github.com/golang/go/issues/38740
func TestCondRewrite(t *testing.T) {
for _, test := range crTests {
t.Run(test.name, test.tf)
}
}
// Profile the aforementioned optimization from two angles:
// SoloJump: generated branching code has one 'jump', for '<' and '>='
// CombJump: generated branching code has two consecutive 'jump', for '<=' and '>'
// We expect that 'CombJump' is generally on par with the non-optimized code, and
// 'SoloJump' demonstrates some improvement.
// It's for arm64 initially, please see https://github.com/golang/go/issues/38740
func BenchmarkCondRewrite(b *testing.B) {
for _, bench := range crBenches {
b.Run(bench.name, bench.bf)
}
}
// var +/- const
func testAddConst64(t *testing.T) {
if x64+11 < 0 {
} else {
t.Errorf("'%#x + 11 < 0' failed", x64)
}
if x64+13 <= 0 {
} else {
t.Errorf("'%#x + 13 <= 0' failed", x64)
}
if y64-11 > 0 {
} else {
t.Errorf("'%#x - 11 > 0' failed", y64)
}
if y64-13 >= 0 {
} else {
t.Errorf("'%#x - 13 >= 0' failed", y64)
}
if x64+19 > 0 {
t.Errorf("'%#x + 19 > 0' failed", x64)
}
if x64+23 >= 0 {
t.Errorf("'%#x + 23 >= 0' failed", x64)
}
if y64-19 < 0 {
t.Errorf("'%#x - 19 < 0' failed", y64)
}
if y64-23 <= 0 {
t.Errorf("'%#x - 23 <= 0' failed", y64)
}
}
// 32-bit var +/- const
func testAddConst32(t *testing.T) {
if x32+11 < 0 {
} else {
t.Errorf("'%#x + 11 < 0' failed", x32)
}
if x32+13 <= 0 {
} else {
t.Errorf("'%#x + 13 <= 0' failed", x32)
}
if y32-11 > 0 {
} else {
t.Errorf("'%#x - 11 > 0' failed", y32)
}
if y32-13 >= 0 {
} else {
t.Errorf("'%#x - 13 >= 0' failed", y32)
}
if x32+19 > 0 {
t.Errorf("'%#x + 19 > 0' failed", x32)
}
if x32+23 >= 0 {
t.Errorf("'%#x + 23 >= 0' failed", x32)
}
if y32-19 < 0 {
t.Errorf("'%#x - 19 < 0' failed", y32)
}
if y32-23 <= 0 {
t.Errorf("'%#x - 23 <= 0' failed", y32)
}
}
// var + var
func testAddVar64(t *testing.T) {
if x64+v64 < 0 {
} else {
t.Errorf("'%#x + %#x < 0' failed", x64, v64)
}
if x64+v64 <= 0 {
} else {
t.Errorf("'%#x + %#x <= 0' failed", x64, v64)
}
if y64+v64_n > 0 {
} else {
t.Errorf("'%#x + %#x > 0' failed", y64, v64_n)
}
if y64+v64_n >= 0 {
} else {
t.Errorf("'%#x + %#x >= 0' failed", y64, v64_n)
}
if x64+v64 > 0 {
t.Errorf("'%#x + %#x > 0' failed", x64, v64)
}
if x64+v64 >= 0 {
t.Errorf("'%#x + %#x >= 0' failed", x64, v64)
}
if y64+v64_n < 0 {
t.Errorf("'%#x + %#x < 0' failed", y64, v64_n)
}
if y64+v64_n <= 0 {
t.Errorf("'%#x + %#x <= 0' failed", y64, v64_n)
}
}
// 32-bit var+var
func testAddVar32(t *testing.T) {
if x32+v32 < 0 {
} else {
t.Errorf("'%#x + %#x < 0' failed", x32, v32)
}
if x32+v32 <= 0 {
} else {
t.Errorf("'%#x + %#x <= 0' failed", x32, v32)
}
if y32+v32_n > 0 {
} else {
t.Errorf("'%#x + %#x > 0' failed", y32, v32_n)
}
if y32+v32_n >= 0 {
} else {
t.Errorf("'%#x + %#x >= 0' failed", y32, v32_n)
}
if x32+v32 > 0 {
t.Errorf("'%#x + %#x > 0' failed", x32, v32)
}
if x32+v32 >= 0 {
t.Errorf("'%#x + %#x >= 0' failed", x32, v32)
}
if y32+v32_n < 0 {
t.Errorf("'%#x + %#x < 0' failed", y32, v32_n)
}
if y32+v32_n <= 0 {
t.Errorf("'%#x + %#x <= 0' failed", y32, v32_n)
}
}
// multiply-add
func testMAddVar64(t *testing.T) {
if x64+v64*one64 < 0 {
} else {
t.Errorf("'%#x + %#x*1 < 0' failed", x64, v64)
}
if x64+v64*one64 <= 0 {
} else {
t.Errorf("'%#x + %#x*1 <= 0' failed", x64, v64)
}
if y64+v64_n*one64 > 0 {
} else {
t.Errorf("'%#x + %#x*1 > 0' failed", y64, v64_n)
}
if y64+v64_n*one64 >= 0 {
} else {
t.Errorf("'%#x + %#x*1 >= 0' failed", y64, v64_n)
}
if x64+v64*one64 > 0 {
t.Errorf("'%#x + %#x*1 > 0' failed", x64, v64)
}
if x64+v64*one64 >= 0 {
t.Errorf("'%#x + %#x*1 >= 0' failed", x64, v64)
}
if y64+v64_n*one64 < 0 {
t.Errorf("'%#x + %#x*1 < 0' failed", y64, v64_n)
}
if y64+v64_n*one64 <= 0 {
t.Errorf("'%#x + %#x*1 <= 0' failed", y64, v64_n)
}
}
// 32-bit multiply-add
func testMAddVar32(t *testing.T) {
if x32+v32*one32 < 0 {
} else {
t.Errorf("'%#x + %#x*1 < 0' failed", x32, v32)
}
if x32+v32*one32 <= 0 {
} else {
t.Errorf("'%#x + %#x*1 <= 0' failed", x32, v32)
}
if y32+v32_n*one32 > 0 {
} else {
t.Errorf("'%#x + %#x*1 > 0' failed", y32, v32_n)
}
if y32+v32_n*one32 >= 0 {
} else {
t.Errorf("'%#x + %#x*1 >= 0' failed", y32, v32_n)
}
if x32+v32*one32 > 0 {
t.Errorf("'%#x + %#x*1 > 0' failed", x32, v32)
}
if x32+v32*one32 >= 0 {
t.Errorf("'%#x + %#x*1 >= 0' failed", x32, v32)
}
if y32+v32_n*one32 < 0 {
t.Errorf("'%#x + %#x*1 < 0' failed", y32, v32_n)
}
if y32+v32_n*one32 <= 0 {
t.Errorf("'%#x + %#x*1 <= 0' failed", y32, v32_n)
}
}
// multiply-sub
func testMSubVar64(t *testing.T) {
if x64-v64_n*one64 < 0 {
} else {
t.Errorf("'%#x - %#x*1 < 0' failed", x64, v64_n)
}
if x64-v64_n*one64 <= 0 {
} else {
t.Errorf("'%#x - %#x*1 <= 0' failed", x64, v64_n)
}
if y64-v64*one64 > 0 {
} else {
t.Errorf("'%#x - %#x*1 > 0' failed", y64, v64)
}
if y64-v64*one64 >= 0 {
} else {
t.Errorf("'%#x - %#x*1 >= 0' failed", y64, v64)
}
if x64-v64_n*one64 > 0 {
t.Errorf("'%#x - %#x*1 > 0' failed", x64, v64_n)
}
if x64-v64_n*one64 >= 0 {
t.Errorf("'%#x - %#x*1 >= 0' failed", x64, v64_n)
}
if y64-v64*one64 < 0 {
t.Errorf("'%#x - %#x*1 < 0' failed", y64, v64)
}
if y64-v64*one64 <= 0 {
t.Errorf("'%#x - %#x*1 <= 0' failed", y64, v64)
}
if x64-x64b*one64 < 0 {
t.Errorf("'%#x - %#x*1 < 0' failed", x64, x64b)
}
if x64-x64b*one64 >= 0 {
} else {
t.Errorf("'%#x - %#x*1 >= 0' failed", x64, x64b)
}
}
// 32-bit multiply-sub
func testMSubVar32(t *testing.T) {
if x32-v32_n*one32 < 0 {
} else {
t.Errorf("'%#x - %#x*1 < 0' failed", x32, v32_n)
}
if x32-v32_n*one32 <= 0 {
} else {
t.Errorf("'%#x - %#x*1 <= 0' failed", x32, v32_n)
}
if y32-v32*one32 > 0 {
} else {
t.Errorf("'%#x - %#x*1 > 0' failed", y32, v32)
}
if y32-v32*one32 >= 0 {
} else {
t.Errorf("'%#x - %#x*1 >= 0' failed", y32, v32)
}
if x32-v32_n*one32 > 0 {
t.Errorf("'%#x - %#x*1 > 0' failed", x32, v32_n)
}
if x32-v32_n*one32 >= 0 {
t.Errorf("'%#x - %#x*1 >= 0' failed", x32, v32_n)
}
if y32-v32*one32 < 0 {
t.Errorf("'%#x - %#x*1 < 0' failed", y32, v32)
}
if y32-v32*one32 <= 0 {
t.Errorf("'%#x - %#x*1 <= 0' failed", y32, v32)
}
if x32-x32b*one32 < 0 {
t.Errorf("'%#x - %#x*1 < 0' failed", x32, x32b)
}
if x32-x32b*one32 >= 0 {
} else {
t.Errorf("'%#x - %#x*1 >= 0' failed", x32, x32b)
}
}
// 32-bit ADDshift, pick up 1~2 scenarios randomly for each condition
func testAddShift32(t *testing.T) {
if x32+v32<<1 < 0 {
} else {
t.Errorf("'%#x + %#x<<%#x < 0' failed", x32, v32, 1)
}
if x32+v32>>1 <= 0 {
} else {
t.Errorf("'%#x + %#x>>%#x <= 0' failed", x32, v32, 1)
}
if x32+int32(uv32>>1) > 0 {
t.Errorf("'%#x + int32(%#x>>%#x) > 0' failed", x32, uv32, 1)
}
if x32+v32<<uz >= 0 {
t.Errorf("'%#x + %#x<<%#x >= 0' failed", x32, v32, uz)
}
if x32+v32>>uz > 0 {
t.Errorf("'%#x + %#x>>%#x > 0' failed", x32, v32, uz)
}
if x32+int32(uv32>>uz) < 0 {
} else {
t.Errorf("'%#x + int32(%#x>>%#x) < 0' failed", x32, uv32, uz)
}
}
// 32-bit SUBshift, pick up 1~2 scenarios randomly for each condition
func testSubShift32(t *testing.T) {
if y32-v32<<1 > 0 {
} else {
t.Errorf("'%#x - %#x<<%#x > 0' failed", y32, v32, 1)
}
if y32-v32>>1 < 0 {
t.Errorf("'%#x - %#x>>%#x < 0' failed", y32, v32, 1)
}
if y32-int32(uv32>>1) >= 0 {
} else {
t.Errorf("'%#x - int32(%#x>>%#x) >= 0' failed", y32, uv32, 1)
}
if y32-v32<<uz < 0 {
t.Errorf("'%#x - %#x<<%#x < 0' failed", y32, v32, uz)
}
if y32-v32>>uz >= 0 {
} else {
t.Errorf("'%#x - %#x>>%#x >= 0' failed", y32, v32, uz)
}
if y32-int32(uv32>>uz) <= 0 {
t.Errorf("'%#x - int32(%#x>>%#x) <= 0' failed", y32, uv32, uz)
}
}
var rnd = rand.New(rand.NewSource(0))
var sink int64
func benchSoloJump(b *testing.B) {
r1 := x64
r2 := x64b
r3 := x64c
r4 := y64
d := rnd.Int63n(10)
// 6 out 10 conditions evaluate to true
for i := 0; i < b.N; i++ {
if r1+r2 < 0 {
d *= 2
d /= 2
}
if r1+r3 >= 0 {
d *= 2
d /= 2
}
if r1+r2*one64 < 0 {
d *= 2
d /= 2
}
if r2+r3*one64 >= 0 {
d *= 2
d /= 2
}
if r1-r2*v64 >= 0 {
d *= 2
d /= 2
}
if r3-r4*v64 < 0 {
d *= 2
d /= 2
}
if r1+11 < 0 {
d *= 2
d /= 2
}
if r1+13 >= 0 {
d *= 2
d /= 2
}
if r4-17 < 0 {
d *= 2
d /= 2
}
if r4-19 >= 0 {
d *= 2
d /= 2
}
}
sink = d
}
func benchCombJump(b *testing.B) {
r1 := x64
r2 := x64b
r3 := x64c
r4 := y64
d := rnd.Int63n(10)
// 6 out 10 conditions evaluate to true
for i := 0; i < b.N; i++ {
if r1+r2 <= 0 {
d *= 2
d /= 2
}
if r1+r3 > 0 {
d *= 2
d /= 2
}
if r1+r2*one64 <= 0 {
d *= 2
d /= 2
}
if r2+r3*one64 > 0 {
d *= 2
d /= 2
}
if r1-r2*v64 > 0 {
d *= 2
d /= 2
}
if r3-r4*v64 <= 0 {
d *= 2
d /= 2
}
if r1+11 <= 0 {
d *= 2
d /= 2
}
if r1+13 > 0 {
d *= 2
d /= 2
}
if r4-17 <= 0 {
d *= 2
d /= 2
}
if r4-19 > 0 {
d *= 2
d /= 2
}
}
sink = d
}

View file

@ -2351,7 +2351,7 @@ func rewriteValuePPC64_OpLsh16x32(v *Value) bool {
typ := &b.Func.Config.Types
// match: (Lsh16x32 x (MOVDconst [c]))
// cond: uint32(c) < 16
// result: (SLWconst x [c])
// result: (SLWconst x [c&31])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@ -2362,7 +2362,7 @@ func rewriteValuePPC64_OpLsh16x32(v *Value) bool {
break
}
v.reset(OpPPC64SLWconst)
v.AuxInt = int64ToAuxInt(c)
v.AuxInt = int64ToAuxInt(c & 31)
v.AddArg(x)
return true
}
@ -2552,7 +2552,7 @@ func rewriteValuePPC64_OpLsh32x32(v *Value) bool {
typ := &b.Func.Config.Types
// match: (Lsh32x32 x (MOVDconst [c]))
// cond: uint32(c) < 32
// result: (SLWconst x [c])
// result: (SLWconst x [c&31])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@ -2563,7 +2563,7 @@ func rewriteValuePPC64_OpLsh32x32(v *Value) bool {
break
}
v.reset(OpPPC64SLWconst)
v.AuxInt = int64ToAuxInt(c)
v.AuxInt = int64ToAuxInt(c & 31)
v.AddArg(x)
return true
}
@ -2792,7 +2792,7 @@ func rewriteValuePPC64_OpLsh64x32(v *Value) bool {
typ := &b.Func.Config.Types
// match: (Lsh64x32 x (MOVDconst [c]))
// cond: uint32(c) < 64
// result: (SLDconst x [c])
// result: (SLDconst x [c&63])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@ -2803,7 +2803,7 @@ func rewriteValuePPC64_OpLsh64x32(v *Value) bool {
break
}
v.reset(OpPPC64SLDconst)
v.AuxInt = int64ToAuxInt(c)
v.AuxInt = int64ToAuxInt(c & 63)
v.AddArg(x)
return true
}
@ -3032,7 +3032,7 @@ func rewriteValuePPC64_OpLsh8x32(v *Value) bool {
typ := &b.Func.Config.Types
// match: (Lsh8x32 x (MOVDconst [c]))
// cond: uint32(c) < 8
// result: (SLWconst x [c])
// result: (SLWconst x [c&7])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@ -3043,7 +3043,7 @@ func rewriteValuePPC64_OpLsh8x32(v *Value) bool {
break
}
v.reset(OpPPC64SLWconst)
v.AuxInt = int64ToAuxInt(c)
v.AuxInt = int64ToAuxInt(c & 7)
v.AddArg(x)
return true
}
@ -10314,12 +10314,16 @@ func rewriteValuePPC64_OpPPC64MTVSRD(v *Value) bool {
b := v.Block
typ := &b.Func.Config.Types
// match: (MTVSRD (MOVDconst [c]))
// cond: !math.IsNaN(math.Float64frombits(uint64(c)))
// result: (FMOVDconst [math.Float64frombits(uint64(c))])
for {
if v_0.Op != OpPPC64MOVDconst {
break
}
c := auxIntToInt64(v_0.AuxInt)
if !(!math.IsNaN(math.Float64frombits(uint64(c)))) {
break
}
v.reset(OpPPC64FMOVDconst)
v.AuxInt = float64ToAuxInt(math.Float64frombits(uint64(c)))
return true
@ -12042,7 +12046,7 @@ func rewriteValuePPC64_OpPPC64SLD(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (SLD x (MOVDconst [c]))
// result: (SLDconst [c] x)
// result: (SLDconst [c&63 | (c>>6&1*63)] x)
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@ -12050,7 +12054,7 @@ func rewriteValuePPC64_OpPPC64SLD(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
v.reset(OpPPC64SLDconst)
v.AuxInt = int64ToAuxInt(c)
v.AuxInt = int64ToAuxInt(c&63 | (c >> 6 & 1 * 63))
v.AddArg(x)
return true
}
@ -12060,7 +12064,7 @@ func rewriteValuePPC64_OpPPC64SLW(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (SLW x (MOVDconst [c]))
// result: (SLWconst [c] x)
// result: (SLWconst [c&31 | (c>>5&1*31)] x)
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@ -12068,7 +12072,7 @@ func rewriteValuePPC64_OpPPC64SLW(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
v.reset(OpPPC64SLWconst)
v.AuxInt = int64ToAuxInt(c)
v.AuxInt = int64ToAuxInt(c&31 | (c >> 5 & 1 * 31))
v.AddArg(x)
return true
}
@ -12078,7 +12082,7 @@ func rewriteValuePPC64_OpPPC64SRAD(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (SRAD x (MOVDconst [c]))
// result: (SRADconst [c] x)
// result: (SRADconst [c&63 | (c>>6&1*63)] x)
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@ -12086,7 +12090,7 @@ func rewriteValuePPC64_OpPPC64SRAD(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
v.reset(OpPPC64SRADconst)
v.AuxInt = int64ToAuxInt(c)
v.AuxInt = int64ToAuxInt(c&63 | (c >> 6 & 1 * 63))
v.AddArg(x)
return true
}
@ -12096,7 +12100,7 @@ func rewriteValuePPC64_OpPPC64SRAW(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (SRAW x (MOVDconst [c]))
// result: (SRAWconst [c] x)
// result: (SRAWconst [c&31 | (c>>5&1*31)] x)
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@ -12104,7 +12108,7 @@ func rewriteValuePPC64_OpPPC64SRAW(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
v.reset(OpPPC64SRAWconst)
v.AuxInt = int64ToAuxInt(c)
v.AuxInt = int64ToAuxInt(c&31 | (c >> 5 & 1 * 31))
v.AddArg(x)
return true
}
@ -12114,7 +12118,7 @@ func rewriteValuePPC64_OpPPC64SRD(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (SRD x (MOVDconst [c]))
// result: (SRDconst [c] x)
// result: (SRDconst [c&63 | (c>>6&1*63)] x)
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@ -12122,7 +12126,7 @@ func rewriteValuePPC64_OpPPC64SRD(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
v.reset(OpPPC64SRDconst)
v.AuxInt = int64ToAuxInt(c)
v.AuxInt = int64ToAuxInt(c&63 | (c >> 6 & 1 * 63))
v.AddArg(x)
return true
}
@ -12132,7 +12136,7 @@ func rewriteValuePPC64_OpPPC64SRW(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (SRW x (MOVDconst [c]))
// result: (SRWconst [c] x)
// result: (SRWconst [c&31 | (c>>5&1*31)] x)
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@ -12140,7 +12144,7 @@ func rewriteValuePPC64_OpPPC64SRW(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
v.reset(OpPPC64SRWconst)
v.AuxInt = int64ToAuxInt(c)
v.AuxInt = int64ToAuxInt(c&31 | (c >> 5 & 1 * 31))
v.AddArg(x)
return true
}
@ -12626,7 +12630,7 @@ func rewriteValuePPC64_OpRsh16Ux32(v *Value) bool {
typ := &b.Func.Config.Types
// match: (Rsh16Ux32 x (MOVDconst [c]))
// cond: uint32(c) < 16
// result: (SRWconst (ZeroExt16to32 x) [c])
// result: (SRWconst (ZeroExt16to32 x) [c&15])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@ -12637,7 +12641,7 @@ func rewriteValuePPC64_OpRsh16Ux32(v *Value) bool {
break
}
v.reset(OpPPC64SRWconst)
v.AuxInt = int64ToAuxInt(c)
v.AuxInt = int64ToAuxInt(c & 15)
v0 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
v0.AddArg(x)
v.AddArg(v0)
@ -12847,7 +12851,7 @@ func rewriteValuePPC64_OpRsh16x32(v *Value) bool {
typ := &b.Func.Config.Types
// match: (Rsh16x32 x (MOVDconst [c]))
// cond: uint32(c) < 16
// result: (SRAWconst (SignExt16to32 x) [c])
// result: (SRAWconst (SignExt16to32 x) [c&15])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@ -12858,7 +12862,7 @@ func rewriteValuePPC64_OpRsh16x32(v *Value) bool {
break
}
v.reset(OpPPC64SRAWconst)
v.AuxInt = int64ToAuxInt(c)
v.AuxInt = int64ToAuxInt(c & 15)
v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
v0.AddArg(x)
v.AddArg(v0)
@ -13068,7 +13072,7 @@ func rewriteValuePPC64_OpRsh32Ux32(v *Value) bool {
typ := &b.Func.Config.Types
// match: (Rsh32Ux32 x (MOVDconst [c]))
// cond: uint32(c) < 32
// result: (SRWconst x [c])
// result: (SRWconst x [c&31])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@ -13079,7 +13083,7 @@ func rewriteValuePPC64_OpRsh32Ux32(v *Value) bool {
break
}
v.reset(OpPPC64SRWconst)
v.AuxInt = int64ToAuxInt(c)
v.AuxInt = int64ToAuxInt(c & 31)
v.AddArg(x)
return true
}
@ -13373,7 +13377,7 @@ func rewriteValuePPC64_OpRsh32x32(v *Value) bool {
typ := &b.Func.Config.Types
// match: (Rsh32x32 x (MOVDconst [c]))
// cond: uint32(c) < 32
// result: (SRAWconst x [c])
// result: (SRAWconst x [c&31])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@ -13384,7 +13388,7 @@ func rewriteValuePPC64_OpRsh32x32(v *Value) bool {
break
}
v.reset(OpPPC64SRAWconst)
v.AuxInt = int64ToAuxInt(c)
v.AuxInt = int64ToAuxInt(c & 31)
v.AddArg(x)
return true
}
@ -13680,7 +13684,7 @@ func rewriteValuePPC64_OpRsh64Ux32(v *Value) bool {
typ := &b.Func.Config.Types
// match: (Rsh64Ux32 x (MOVDconst [c]))
// cond: uint32(c) < 64
// result: (SRDconst x [c])
// result: (SRDconst x [c&63])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@ -13691,7 +13695,7 @@ func rewriteValuePPC64_OpRsh64Ux32(v *Value) bool {
break
}
v.reset(OpPPC64SRDconst)
v.AuxInt = int64ToAuxInt(c)
v.AuxInt = int64ToAuxInt(c & 63)
v.AddArg(x)
return true
}
@ -13985,7 +13989,7 @@ func rewriteValuePPC64_OpRsh64x32(v *Value) bool {
typ := &b.Func.Config.Types
// match: (Rsh64x32 x (MOVDconst [c]))
// cond: uint32(c) < 64
// result: (SRADconst x [c])
// result: (SRADconst x [c&63])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@ -13996,7 +14000,7 @@ func rewriteValuePPC64_OpRsh64x32(v *Value) bool {
break
}
v.reset(OpPPC64SRADconst)
v.AuxInt = int64ToAuxInt(c)
v.AuxInt = int64ToAuxInt(c & 63)
v.AddArg(x)
return true
}
@ -14296,7 +14300,7 @@ func rewriteValuePPC64_OpRsh8Ux32(v *Value) bool {
typ := &b.Func.Config.Types
// match: (Rsh8Ux32 x (MOVDconst [c]))
// cond: uint32(c) < 8
// result: (SRWconst (ZeroExt8to32 x) [c])
// result: (SRWconst (ZeroExt8to32 x) [c&7])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@ -14307,7 +14311,7 @@ func rewriteValuePPC64_OpRsh8Ux32(v *Value) bool {
break
}
v.reset(OpPPC64SRWconst)
v.AuxInt = int64ToAuxInt(c)
v.AuxInt = int64ToAuxInt(c & 7)
v0 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
v0.AddArg(x)
v.AddArg(v0)
@ -14517,7 +14521,7 @@ func rewriteValuePPC64_OpRsh8x32(v *Value) bool {
typ := &b.Func.Config.Types
// match: (Rsh8x32 x (MOVDconst [c]))
// cond: uint32(c) < 8
// result: (SRAWconst (SignExt8to32 x) [c])
// result: (SRAWconst (SignExt8to32 x) [c&7])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@ -14528,7 +14532,7 @@ func rewriteValuePPC64_OpRsh8x32(v *Value) bool {
break
}
v.reset(OpPPC64SRAWconst)
v.AuxInt = int64ToAuxInt(c)
v.AuxInt = int64ToAuxInt(c & 7)
v0 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
v0.AddArg(x)
v.AddArg(v0)

View file

@ -5120,7 +5120,105 @@ func rewriteValueRISCV64_OpZeroExt8to64(v *Value) bool {
}
func rewriteBlockRISCV64(b *Block) bool {
switch b.Kind {
case BlockRISCV64BEQ:
// match: (BEQ (MOVDconst [0]) cond yes no)
// result: (BEQZ cond yes no)
for b.Controls[0].Op == OpRISCV64MOVDconst {
v_0 := b.Controls[0]
if auxIntToInt64(v_0.AuxInt) != 0 {
break
}
cond := b.Controls[1]
b.resetWithControl(BlockRISCV64BEQZ, cond)
return true
}
// match: (BEQ cond (MOVDconst [0]) yes no)
// result: (BEQZ cond yes no)
for b.Controls[1].Op == OpRISCV64MOVDconst {
cond := b.Controls[0]
v_1 := b.Controls[1]
if auxIntToInt64(v_1.AuxInt) != 0 {
break
}
b.resetWithControl(BlockRISCV64BEQZ, cond)
return true
}
case BlockRISCV64BEQZ:
// match: (BEQZ (SEQZ x) yes no)
// result: (BNEZ x yes no)
for b.Controls[0].Op == OpRISCV64SEQZ {
v_0 := b.Controls[0]
x := v_0.Args[0]
b.resetWithControl(BlockRISCV64BNEZ, x)
return true
}
// match: (BEQZ (SNEZ x) yes no)
// result: (BEQZ x yes no)
for b.Controls[0].Op == OpRISCV64SNEZ {
v_0 := b.Controls[0]
x := v_0.Args[0]
b.resetWithControl(BlockRISCV64BEQZ, x)
return true
}
// match: (BEQZ (SUB x y) yes no)
// result: (BEQ x y yes no)
for b.Controls[0].Op == OpRISCV64SUB {
v_0 := b.Controls[0]
y := v_0.Args[1]
x := v_0.Args[0]
b.resetWithControl2(BlockRISCV64BEQ, x, y)
return true
}
// match: (BEQZ (SLT x y) yes no)
// result: (BGE x y yes no)
for b.Controls[0].Op == OpRISCV64SLT {
v_0 := b.Controls[0]
y := v_0.Args[1]
x := v_0.Args[0]
b.resetWithControl2(BlockRISCV64BGE, x, y)
return true
}
// match: (BEQZ (SLTU x y) yes no)
// result: (BGEU x y yes no)
for b.Controls[0].Op == OpRISCV64SLTU {
v_0 := b.Controls[0]
y := v_0.Args[1]
x := v_0.Args[0]
b.resetWithControl2(BlockRISCV64BGEU, x, y)
return true
}
case BlockRISCV64BNE:
// match: (BNE (MOVDconst [0]) cond yes no)
// result: (BNEZ cond yes no)
for b.Controls[0].Op == OpRISCV64MOVDconst {
v_0 := b.Controls[0]
if auxIntToInt64(v_0.AuxInt) != 0 {
break
}
cond := b.Controls[1]
b.resetWithControl(BlockRISCV64BNEZ, cond)
return true
}
// match: (BNE cond (MOVDconst [0]) yes no)
// result: (BNEZ cond yes no)
for b.Controls[1].Op == OpRISCV64MOVDconst {
cond := b.Controls[0]
v_1 := b.Controls[1]
if auxIntToInt64(v_1.AuxInt) != 0 {
break
}
b.resetWithControl(BlockRISCV64BNEZ, cond)
return true
}
case BlockRISCV64BNEZ:
// match: (BNEZ (SEQZ x) yes no)
// result: (BEQZ x yes no)
for b.Controls[0].Op == OpRISCV64SEQZ {
v_0 := b.Controls[0]
x := v_0.Args[0]
b.resetWithControl(BlockRISCV64BEQZ, x)
return true
}
// match: (BNEZ (SNEZ x) yes no)
// result: (BNEZ x yes no)
for b.Controls[0].Op == OpRISCV64SNEZ {
@ -5129,6 +5227,33 @@ func rewriteBlockRISCV64(b *Block) bool {
b.resetWithControl(BlockRISCV64BNEZ, x)
return true
}
// match: (BNEZ (SUB x y) yes no)
// result: (BNE x y yes no)
for b.Controls[0].Op == OpRISCV64SUB {
v_0 := b.Controls[0]
y := v_0.Args[1]
x := v_0.Args[0]
b.resetWithControl2(BlockRISCV64BNE, x, y)
return true
}
// match: (BNEZ (SLT x y) yes no)
// result: (BLT x y yes no)
for b.Controls[0].Op == OpRISCV64SLT {
v_0 := b.Controls[0]
y := v_0.Args[1]
x := v_0.Args[0]
b.resetWithControl2(BlockRISCV64BLT, x, y)
return true
}
// match: (BNEZ (SLTU x y) yes no)
// result: (BLTU x y yes no)
for b.Controls[0].Op == OpRISCV64SLTU {
v_0 := b.Controls[0]
y := v_0.Args[1]
x := v_0.Args[0]
b.resetWithControl2(BlockRISCV64BLTU, x, y)
return true
}
case BlockIf:
// match: (If cond yes no)
// result: (BNEZ cond yes no)

View file

@ -27,3 +27,12 @@ func TestMoveSmall(t *testing.T) {
}
}
}
func TestSubFlags(t *testing.T) {
if !subFlags32(0, 1).lt() {
t.Errorf("subFlags32(0,1).lt() returned false")
}
if !subFlags32(0, 1).ult() {
t.Errorf("subFlags32(0,1).ult() returned false")
}
}

View file

@ -0,0 +1,59 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ssa
// tightenTupleSelectors ensures that tuple selectors (Select0 and
// Select1 ops) are in the same block as their tuple generator. The
// function also ensures that there are no duplicate tuple selectors.
// These properties are expected by the scheduler but may not have
// been maintained by the optimization pipeline up to this point.
//
// See issues 16741 and 39472.
func tightenTupleSelectors(f *Func) {
selectors := make(map[struct {
id ID
op Op
}]*Value)
for _, b := range f.Blocks {
for _, selector := range b.Values {
if selector.Op != OpSelect0 && selector.Op != OpSelect1 {
continue
}
// Get the tuple generator to use as a key for de-duplication.
tuple := selector.Args[0]
if !tuple.Type.IsTuple() {
f.Fatalf("arg of tuple selector %s is not a tuple: %s", selector.String(), tuple.LongString())
}
// If there is a pre-existing selector in the target block then
// use that. Do this even if the selector is already in the
// target block to avoid duplicate tuple selectors.
key := struct {
id ID
op Op
}{tuple.ID, selector.Op}
if t := selectors[key]; t != nil {
if selector != t {
selector.copyOf(t)
}
continue
}
// If the selector is in the wrong block copy it into the target
// block.
if selector.Block != tuple.Block {
t := selector.copyInto(tuple.Block)
selector.copyOf(t)
selectors[key] = t
continue
}
// The selector is in the target block. Add it to the map so it
// cannot be duplicated.
selectors[key] = selector
}
}
}

View file

@ -206,6 +206,8 @@ func (v *Value) auxString() string {
return fmt.Sprintf(" {%s}", v.Aux.(Op))
case auxS390XCCMask, auxS390XRotateParams:
return fmt.Sprintf(" {%v}", v.Aux)
case auxFlagConstant:
return fmt.Sprintf("[%s]", flagConstant(v.AuxInt))
}
return ""
}

View file

@ -885,11 +885,11 @@ var blockJump = [...]struct {
ssa.Block386NAN: {x86.AJPS, x86.AJPC},
}
var eqfJumps = [2][2]gc.FloatingEQNEJump{
var eqfJumps = [2][2]gc.IndexJump{
{{Jump: x86.AJNE, Index: 1}, {Jump: x86.AJPS, Index: 1}}, // next == b.Succs[0]
{{Jump: x86.AJNE, Index: 1}, {Jump: x86.AJPC, Index: 0}}, // next == b.Succs[1]
}
var nefJumps = [2][2]gc.FloatingEQNEJump{
var nefJumps = [2][2]gc.IndexJump{
{{Jump: x86.AJNE, Index: 0}, {Jump: x86.AJPC, Index: 1}}, // next == b.Succs[0]
{{Jump: x86.AJNE, Index: 0}, {Jump: x86.AJPS, Index: 0}}, // next == b.Succs[1]
}
@ -929,10 +929,10 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
p.To.Sym = b.Aux.(*obj.LSym)
case ssa.Block386EQF:
s.FPJump(b, next, &eqfJumps)
s.CombJump(b, next, &eqfJumps)
case ssa.Block386NEF:
s.FPJump(b, next, &nefJumps)
s.CombJump(b, next, &nefJumps)
case ssa.Block386EQ, ssa.Block386NE,
ssa.Block386LT, ssa.Block386GE,

11
src/cmd/dist/build.go vendored
View file

@ -31,7 +31,6 @@ var (
goos string
goarm string
go386 string
goamd64 string
gomips string
gomips64 string
goppc64 string
@ -152,12 +151,6 @@ func xinit() {
}
go386 = b
b = os.Getenv("GOAMD64")
if b == "" {
b = "alignedjumps"
}
goamd64 = b
b = os.Getenv("GOMIPS")
if b == "" {
b = "hardfloat"
@ -230,7 +223,6 @@ func xinit() {
// For tools being invoked but also for os.ExpandEnv.
os.Setenv("GO386", go386)
os.Setenv("GOAMD64", goamd64)
os.Setenv("GOARCH", goarch)
os.Setenv("GOARM", goarm)
os.Setenv("GOHOSTARCH", gohostarch)
@ -1171,9 +1163,6 @@ func cmdenv() {
if goarch == "386" {
xprintf(format, "GO386", go386)
}
if goarch == "amd64" {
xprintf(format, "GOAMD64", goamd64)
}
if goarch == "mips" || goarch == "mipsle" {
xprintf(format, "GOMIPS", gomips)
}

View file

@ -42,7 +42,6 @@ func mkzversion(dir, file string) {
//
// const defaultGOROOT = <goroot>
// const defaultGO386 = <go386>
// const defaultGOAMD64 = <goamd64>
// const defaultGOARM = <goarm>
// const defaultGOMIPS = <gomips>
// const defaultGOMIPS64 = <gomips64>
@ -72,7 +71,6 @@ func mkzbootstrap(file string) {
fmt.Fprintf(&buf, "import \"runtime\"\n")
fmt.Fprintln(&buf)
fmt.Fprintf(&buf, "const defaultGO386 = `%s`\n", go386)
fmt.Fprintf(&buf, "const defaultGOAMD64 = `%s`\n", goamd64)
fmt.Fprintf(&buf, "const defaultGOARM = `%s`\n", goarm)
fmt.Fprintf(&buf, "const defaultGOMIPS = `%s`\n", gomips)
fmt.Fprintf(&buf, "const defaultGOMIPS64 = `%s`\n", gomips64)

View file

@ -115,6 +115,7 @@ var ignorePrefixes = []string{
// These must not be copied into the bootstrap build directory.
var ignoreSuffixes = []string{
"_arm64.s",
"_arm64_test.s",
"_arm64.go",
"_riscv64.s",
"_riscv64.go",

21
src/cmd/dist/test.go vendored
View file

@ -178,15 +178,6 @@ func (t *tester) run() {
return
}
// We must unset GOROOT_FINAL before tests, because runtime/debug requires
// correct access to source code, so if we have GOROOT_FINAL in effect,
// at least runtime/debug test will fail.
// If GOROOT_FINAL was set before, then now all the commands will appear stale.
// Nothing we can do about that other than not checking them below.
// (We call checkNotStale but only with "std" not "cmd".)
os.Setenv("GOROOT_FINAL_OLD", os.Getenv("GOROOT_FINAL")) // for cmd/link test
os.Unsetenv("GOROOT_FINAL")
for _, name := range t.runNames {
if !t.isRegisteredTestName(name) {
fatalf("unknown test %q", name)
@ -470,6 +461,18 @@ func (t *tester) registerTests() {
})
}
// Test the ios build tag on darwin/amd64 for the iOS simulator.
if goos == "darwin" && !t.iOS() {
t.tests = append(t.tests, distTest{
name: "amd64ios",
heading: "ios tag on darwin/amd64",
fn: func(dt *distTest) error {
t.addCmd(dt, "src", t.goTest(), t.timeout(300), "-tags=ios", "-run=SystemRoots", "crypto/x509")
return nil
},
})
}
if t.race {
return
}

View file

@ -9,13 +9,14 @@ import (
)
func init() {
register(eglFix)
register(eglFixDisplay)
register(eglFixConfig)
}
var eglFix = fix{
var eglFixDisplay = fix{
name: "egl",
date: "2018-12-15",
f: eglfix,
f: eglfixDisp,
desc: `Fixes initializers of EGLDisplay`,
disabled: false,
}
@ -25,8 +26,27 @@ var eglFix = fix{
// New state:
// type EGLDisplay uintptr
// This fix finds nils initializing these types and replaces the nils with 0s.
func eglfix(f *ast.File) bool {
func eglfixDisp(f *ast.File) bool {
return typefix(f, func(s string) bool {
return s == "C.EGLDisplay"
})
}
var eglFixConfig = fix{
name: "eglconf",
date: "2020-05-30",
f: eglfixConfig,
desc: `Fixes initializers of EGLConfig`,
disabled: false,
}
// Old state:
// type EGLConfig unsafe.Pointer
// New state:
// type EGLConfig uintptr
// This fix finds nils initializing these types and replaces the nils with 0s.
func eglfixConfig(f *ast.File) bool {
return typefix(f, func(s string) bool {
return s == "C.EGLConfig"
})
}

View file

@ -4,182 +4,193 @@
package main
import "strings"
func init() {
addTestCases(eglTests, eglfix)
addTestCases(eglTestsFor("EGLDisplay"), eglfixDisp)
addTestCases(eglTestsFor("EGLConfig"), eglfixConfig)
}
var eglTests = []testCase{
{
Name: "egl.localVariable",
In: `package main
func eglTestsFor(tname string) []testCase {
var eglTests = []testCase{
{
Name: "egl.localVariable",
In: `package main
import "C"
func f() {
var x C.EGLDisplay = nil
var x C.$EGLTYPE = nil
x = nil
x, x = nil, nil
}
`,
Out: `package main
Out: `package main
import "C"
func f() {
var x C.EGLDisplay = 0
var x C.$EGLTYPE = 0
x = 0
x, x = 0, 0
}
`,
},
{
Name: "egl.globalVariable",
In: `package main
},
{
Name: "egl.globalVariable",
In: `package main
import "C"
var x C.EGLDisplay = nil
var x C.$EGLTYPE = nil
func f() {
x = nil
}
`,
Out: `package main
Out: `package main
import "C"
var x C.EGLDisplay = 0
var x C.$EGLTYPE = 0
func f() {
x = 0
}
`,
},
{
Name: "egl.EqualArgument",
In: `package main
},
{
Name: "egl.EqualArgument",
In: `package main
import "C"
var x C.EGLDisplay
var x C.$EGLTYPE
var y = x == nil
var z = x != nil
`,
Out: `package main
Out: `package main
import "C"
var x C.EGLDisplay
var x C.$EGLTYPE
var y = x == 0
var z = x != 0
`,
},
{
Name: "egl.StructField",
In: `package main
},
{
Name: "egl.StructField",
In: `package main
import "C"
type T struct {
x C.EGLDisplay
x C.$EGLTYPE
}
var t = T{x: nil}
`,
Out: `package main
Out: `package main
import "C"
type T struct {
x C.EGLDisplay
x C.$EGLTYPE
}
var t = T{x: 0}
`,
},
{
Name: "egl.FunctionArgument",
In: `package main
},
{
Name: "egl.FunctionArgument",
In: `package main
import "C"
func f(x C.EGLDisplay) {
func f(x C.$EGLTYPE) {
}
func g() {
f(nil)
}
`,
Out: `package main
Out: `package main
import "C"
func f(x C.EGLDisplay) {
func f(x C.$EGLTYPE) {
}
func g() {
f(0)
}
`,
},
{
Name: "egl.ArrayElement",
In: `package main
},
{
Name: "egl.ArrayElement",
In: `package main
import "C"
var x = [3]C.EGLDisplay{nil, nil, nil}
var x = [3]C.$EGLTYPE{nil, nil, nil}
`,
Out: `package main
Out: `package main
import "C"
var x = [3]C.EGLDisplay{0, 0, 0}
var x = [3]C.$EGLTYPE{0, 0, 0}
`,
},
{
Name: "egl.SliceElement",
In: `package main
},
{
Name: "egl.SliceElement",
In: `package main
import "C"
var x = []C.EGLDisplay{nil, nil, nil}
var x = []C.$EGLTYPE{nil, nil, nil}
`,
Out: `package main
Out: `package main
import "C"
var x = []C.EGLDisplay{0, 0, 0}
var x = []C.$EGLTYPE{0, 0, 0}
`,
},
{
Name: "egl.MapKey",
In: `package main
},
{
Name: "egl.MapKey",
In: `package main
import "C"
var x = map[C.EGLDisplay]int{nil: 0}
var x = map[C.$EGLTYPE]int{nil: 0}
`,
Out: `package main
Out: `package main
import "C"
var x = map[C.EGLDisplay]int{0: 0}
var x = map[C.$EGLTYPE]int{0: 0}
`,
},
{
Name: "egl.MapValue",
In: `package main
},
{
Name: "egl.MapValue",
In: `package main
import "C"
var x = map[int]C.EGLDisplay{0: nil}
var x = map[int]C.$EGLTYPE{0: nil}
`,
Out: `package main
Out: `package main
import "C"
var x = map[int]C.EGLDisplay{0: 0}
var x = map[int]C.$EGLTYPE{0: 0}
`,
},
},
}
for i := range eglTests {
t := &eglTests[i]
t.In = strings.ReplaceAll(t.In, "$EGLTYPE", tname)
t.Out = strings.ReplaceAll(t.Out, "$EGLTYPE", tname)
}
return eglTests
}

View file

@ -5,9 +5,9 @@ go 1.15
require (
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3
github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340 // indirect
golang.org/x/arch v0.0.0-20200312215426-ff8b605520f4
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79
golang.org/x/mod v0.2.1-0.20200429172858-859b3ef565e2
golang.org/x/arch v0.0.0-20200511175325-f7c78586839d
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
golang.org/x/mod v0.3.0
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 // indirect
golang.org/x/tools v0.0.0-20200504152539-33427f1b0364
golang.org/x/tools v0.0.0-20200616133436-c1934b75d054
)

View file

@ -7,15 +7,15 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340 h1:S1+yTUaFPXuDZnPDbO+TrDFIjPzQraYH8/CwSlu9Fac=
github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/arch v0.0.0-20200312215426-ff8b605520f4 h1:cZG+Ns0n5bdEEsURGnDinFswSebRNMqspbLvxrLZoIc=
golang.org/x/arch v0.0.0-20200312215426-ff8b605520f4/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
golang.org/x/arch v0.0.0-20200511175325-f7c78586839d h1:YvwchuJby5xEAPdBGmdAVSiVME50C+RJfJJwJJsGEV8=
golang.org/x/arch v0.0.0-20200511175325-f7c78586839d/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 h1:IaQbIIB2X/Mp/DKctl6ROxz1KyMlKp4uyvL6+kQ7C88=
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.2.1-0.20200429172858-859b3ef565e2 h1:VUsRDZIYpMs3R7PyYeN7BSbDfYjhxaX6HlWvM5iAEqs=
golang.org/x/mod v0.2.1-0.20200429172858-859b3ef565e2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@ -28,8 +28,8 @@ golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 h1:5B6i6EAiSYyejWfvc5Rc9BbI3
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200504152539-33427f1b0364 h1:B3dlRmcq+I6Bd22nHKKa7E+r0/6mLEoJQa75WjfILUE=
golang.org/x/tools v0.0.0-20200504152539-33427f1b0364/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200616133436-c1934b75d054 h1:HHeAlu5H9b71C+Fx0K+1dGgVFN1DM1/wz4aoGOA5qS8=
golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=

View file

@ -1313,10 +1313,10 @@
// and its test source files to identify significant problems. If go vet
// finds any problems, go test reports those and does not run the test
// binary. Only a high-confidence subset of the default go vet checks are
// used. That subset is: 'atomic', 'bool', 'buildtags', 'nilfunc', and
// 'printf'. You can see the documentation for these and other vet tests
// via "go doc cmd/vet". To disable the running of go vet, use the
// -vet=off flag.
// used. That subset is: 'atomic', 'bool', 'buildtags', 'errorsas',
// 'ifaceassert', 'nilfunc', 'printf', and 'stringintconv'. You can see
// the documentation for these and other vet tests via "go doc cmd/vet".
// To disable the running of go vet, use the -vet=off flag.
//
// All test output and summary lines are printed to the go command's
// standard output, even if the test printed them to its own standard
@ -1480,56 +1480,91 @@
//
// Build constraints
//
// Build constraints describe the conditions under which each source file
// should be included in the corresponding package. Build constraints
// for a given source file may be added by build constraint comments
// within the file, or by specific patterns in the file's name.
//
// A build constraint comment appears before the file's package clause and
// must be separated from the package clause by at least one blank line.
// The comment begins with:
// A build constraint, also known as a build tag, is a line comment that begins
//
// // +build
//
// and follows with a space-separated list of options on the same line.
// The constraint is evaluated as the OR of the options.
// that lists the conditions under which a file should be included in the package.
// Constraints may appear in any kind of source file (not just Go), but
// they must appear near the top of the file, preceded
// only by blank lines and other line comments. These rules mean that in Go
// files a build constraint must appear before the package clause.
//
// To distinguish build constraints from package documentation, a series of
// build constraints must be followed by a blank line.
//
// A build constraint is evaluated as the OR of space-separated options.
// Each option evaluates as the AND of its comma-separated terms.
// Each term consists of letters, digits, underscores, and dots.
// Each term may be negated with a leading exclamation point.
//
// A term may be negated with a preceding !.
// For example, the build constraint:
//
// // +build linux,386 darwin,!cgo arm
// // +build linux,386 darwin,!cgo
//
// corresponds to boolean formula:
// corresponds to the boolean formula:
//
// (linux AND 386) OR (darwin AND NOT cgo) OR arm
// (linux AND 386) OR (darwin AND (NOT cgo))
//
// During a particular build, the following terms are satisfied:
// - the target operating system and architecture, as spelled by
// runtime.GOOS and runtime.GOARCH respectively
// - the compiler being used, either "gc" or "gccgo"
// - "cgo", if the cgo command is supported
// (see CGO_ENABLED in 'go help environment')
// - a term for each Go major release, through the current version:
// "go1.1" from Go version 1.1 onward,
// "go1.2" from Go version 1.2 onward, and so on
// - and any additional tags given by the '-tags' flag (see 'go help build').
// A file may have multiple build constraints. The overall constraint is the AND
// of the individual constraints. That is, the build constraints:
//
// // +build linux darwin
// // +build amd64
//
// corresponds to the boolean formula:
//
// (linux OR darwin) AND amd64
//
// During a particular build, the following words are satisfied:
//
// - the target operating system, as spelled by runtime.GOOS, set with the
// GOOS environment variable.
// - the target architecture, as spelled by runtime.GOARCH, set with the
// GOARCH environment variable.
// - the compiler being used, either "gc" or "gccgo"
// - "cgo", if the cgo command is supported (see CGO_ENABLED in
// 'go help environment').
// - a term for each Go major release, through the current version:
// "go1.1" from Go version 1.1 onward, "go1.12" from Go 1.12, and so on.
// - any additional tags given by the -tags flag (see 'go help build').
//
// There are no separate build tags for beta or minor releases.
//
// An additional build constraint may be derived from the source file name.
// If a file's name, after stripping the extension and a possible _test suffix,
// matches the patterns *_GOOS, *_GOARCH, or *_GOOS_GOARCH for any known
// GOOS or GOARCH value, then the file is implicitly constrained to that
// specific GOOS and/or GOARCH, in addition to any other build constraints
// declared as comments within the file.
// matches any of the following patterns:
// *_GOOS
// *_GOARCH
// *_GOOS_GOARCH
// (example: source_windows_amd64.go) where GOOS and GOARCH represent
// any known operating system and architecture values respectively, then
// the file is considered to have an implicit build constraint requiring
// those terms (in addition to any explicit constraints in the file).
//
// For example, the file:
// Using GOOS=android matches build tags and files as for GOOS=linux
// in addition to android tags and files.
//
// source_windows_amd64.go
// Using GOOS=illumos matches build tags and files as for GOOS=solaris
// in addition to illumos tags and files.
//
// is implicitly constrained to windows / amd64.
// To keep a file from being considered for the build:
//
// See 'go doc go/build' for more details.
// // +build ignore
//
// (any other unsatisfied word will work as well, but "ignore" is conventional.)
//
// To build a file only when using cgo, and only on Linux and OS X:
//
// // +build linux,cgo darwin,cgo
//
// Such a file is usually paired with another file implementing the
// default functionality for other systems, which in this case would
// carry the constraint:
//
// // +build !linux,!darwin !cgo
//
// Naming a file dns_windows.go will cause it to be included only when
// building the package for Windows; similarly, math_386.s will be included
// only when building the package for 32-bit x86.
//
//
// Build modes
@ -1754,9 +1789,6 @@
// GO386
// For GOARCH=386, the floating point instruction set.
// Valid values are 387, sse2.
// GOAMD64
// For GOARCH=amd64, jumps can be optionally be aligned such that they do not end on
// or cross 32 byte boundaries. Valid values are alignedjumps (default), normaljumps.
// GOMIPS
// For GOARCH=mips{,le}, whether to use floating point instructions.
// Valid values are hardfloat (default), softfloat.

Some files were not shown because too many files have changed in this diff Show more