mirror of
https://github.com/golang/go
synced 2024-09-18 15:32:18 +00:00
[dev.boringcrypto] all: merge master into dev.boringcrypto
Change-Id: I948e086e11e1da571e2be23bb08a7bbd6618dc2f
This commit is contained in:
commit
a91ad4250c
20
.gitattributes
vendored
20
.gitattributes
vendored
|
@ -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
|
||||
|
|
5
AUTHORS
5
AUTHORS
|
@ -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>
|
||||
|
|
|
@ -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
132
api/go1.15.txt
Normal 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)
|
|
@ -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)
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 -->
|
||||
|
|
709
doc/go1.15.html
709
doc/go1.15.html
|
@ -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 -->
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>.
|
||||
|
|
|
@ -2200,3 +2200,7 @@ func test32579(t *testing.T) {
|
|||
// issue 38649
|
||||
|
||||
var issue38649 C.netbsd_gid = 42
|
||||
|
||||
// issue 39877
|
||||
|
||||
var issue39877 *C.void = nil
|
||||
|
|
1
misc/cgo/test/testdata/issue27054/egl.h
vendored
1
misc/cgo/test/testdata/issue27054/egl.h
vendored
|
@ -5,3 +5,4 @@
|
|||
// This is the relevant part of EGL/egl.h.
|
||||
|
||||
typedef void *EGLDisplay;
|
||||
typedef void *EGLConfig;
|
||||
|
|
|
@ -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
|
||||
)
|
||||
}
|
||||
|
|
12
misc/cgo/testgodefs/testdata/issue39534.go
vendored
Normal file
12
misc/cgo/testgodefs/testdata/issue39534.go
vendored
Normal 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
|
|
@ -24,6 +24,7 @@ var filePrefixes = []string{
|
|||
"issue37479",
|
||||
"issue37621",
|
||||
"issue38649",
|
||||
"issue39534",
|
||||
}
|
||||
|
||||
func TestGoDefs(t *testing.T) {
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
37
misc/cgo/testshared/testdata/gcdata/main/main.go
vendored
Normal file
37
misc/cgo/testshared/testdata/gcdata/main/main.go
vendored
Normal 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")
|
||||
}
|
||||
}
|
||||
}
|
7
misc/cgo/testshared/testdata/gcdata/p/p.go
vendored
Normal file
7
misc/cgo/testshared/testdata/gcdata/p/p.go
vendored
Normal 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
|
9
misc/cgo/testshared/testdata/issue39777/a/a.go
vendored
Normal file
9
misc/cgo/testshared/testdata/issue39777/a/a.go
vendored
Normal 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() }
|
7
misc/cgo/testshared/testdata/issue39777/b/b.go
vendored
Normal file
7
misc/cgo/testshared/testdata/issue39777/b/b.go
vendored
Normal 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() {}
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
3
src/cmd/asm/internal/asm/testdata/arm64.s
vendored
3
src/cmd/asm/internal/asm/testdata/arm64.s
vendored
|
@ -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
|
||||
|
|
1
src/cmd/asm/internal/asm/testdata/arm64enc.s
vendored
1
src/cmd/asm/internal/asm/testdata/arm64enc.s
vendored
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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": "",
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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, >Jumps)
|
||||
|
||||
default:
|
||||
b.Fatalf("branch not implemented: %s", b.LongString())
|
||||
}
|
||||
|
|
|
@ -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, >Jumps)
|
||||
default:
|
||||
b.Fatalf("branch not implemented: %s", b.LongString())
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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[:]
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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++
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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",
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
70
src/cmd/compile/internal/gc/testdata/reproducible/issue38068.go
vendored
Normal file
70
src/cmd/compile/internal/gc/testdata/reproducible/issue38068.go
vendored
Normal 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)
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
31
src/cmd/compile/internal/ssa/flags_amd64_test.s
Normal file
31
src/cmd/compile/internal/ssa/flags_amd64_test.s
Normal 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
|
32
src/cmd/compile/internal/ssa/flags_arm64_test.s
Normal file
32
src/cmd/compile/internal/ssa/flags_arm64_test.s
Normal 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
|
108
src/cmd/compile/internal/ssa/flags_test.go
Normal file
108
src/cmd/compile/internal/ssa/flags_test.go
Normal 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()
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
597
src/cmd/compile/internal/ssa/rewriteCond_test.go
Normal file
597
src/cmd/compile/internal/ssa/rewriteCond_test.go
Normal 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
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
59
src/cmd/compile/internal/ssa/tuple.go
Normal file
59
src/cmd/compile/internal/ssa/tuple.go
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 ""
|
||||
}
|
||||
|
|
|
@ -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
11
src/cmd/dist/build.go
vendored
|
@ -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)
|
||||
}
|
||||
|
|
2
src/cmd/dist/buildruntime.go
vendored
2
src/cmd/dist/buildruntime.go
vendored
|
@ -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)
|
||||
|
|
1
src/cmd/dist/buildtool.go
vendored
1
src/cmd/dist/buildtool.go
vendored
|
@ -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
21
src/cmd/dist/test.go
vendored
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -6,7 +6,6 @@ package main_test
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"debug/elf"
|
||||
"debug/macho"
|
||||
"debug/pe"
|
||||
|
@ -114,12 +113,6 @@ var testGo string
|
|||
var testTmpDir string
|
||||
var testBin string
|
||||
|
||||
// testCtx is canceled when the test binary is about to time out.
|
||||
//
|
||||
// If https://golang.org/issue/28135 is accepted, uses of this variable in test
|
||||
// functions should be replaced by t.Context().
|
||||
var testCtx = context.Background()
|
||||
|
||||
// The TestMain function creates a go command for testing purposes and
|
||||
// deletes it after the tests have been run.
|
||||
func TestMain(m *testing.M) {
|
||||
|
@ -131,23 +124,9 @@ func TestMain(m *testing.M) {
|
|||
fmt.Printf("SKIP\n")
|
||||
return
|
||||
}
|
||||
os.Unsetenv("GOROOT_FINAL")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
timeoutFlag := flag.Lookup("test.timeout")
|
||||
if timeoutFlag != nil {
|
||||
// TODO(golang.org/issue/28147): The go command does not pass the
|
||||
// test.timeout flag unless either -timeout or -test.timeout is explicitly
|
||||
// set on the command line.
|
||||
if d := timeoutFlag.Value.(flag.Getter).Get().(time.Duration); d != 0 {
|
||||
aBitShorter := d * 95 / 100
|
||||
var cancel context.CancelFunc
|
||||
testCtx, cancel = context.WithTimeout(testCtx, aBitShorter)
|
||||
defer cancel()
|
||||
}
|
||||
}
|
||||
|
||||
if *proxyAddr != "" {
|
||||
StartProxy()
|
||||
select {}
|
||||
|
@ -200,6 +179,11 @@ func TestMain(m *testing.M) {
|
|||
}
|
||||
testGOROOT = goEnv("GOROOT")
|
||||
os.Setenv("TESTGO_GOROOT", testGOROOT)
|
||||
// Ensure that GOROOT is set explicitly.
|
||||
// Otherwise, if the toolchain was built with GOROOT_FINAL set but has not
|
||||
// yet been moved to its final location, programs that invoke runtime.GOROOT
|
||||
// may accidentally use the wrong path.
|
||||
os.Setenv("GOROOT", testGOROOT)
|
||||
|
||||
// The whole GOROOT/pkg tree was installed using the GOHOSTOS/GOHOSTARCH
|
||||
// toolchain (installed in GOROOT/pkg/tool/GOHOSTOS_GOHOSTARCH).
|
||||
|
@ -236,8 +220,10 @@ func TestMain(m *testing.M) {
|
|||
}
|
||||
testCC = strings.TrimSpace(string(out))
|
||||
|
||||
if out, err := exec.Command(testGo, "env", "CGO_ENABLED").Output(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "running testgo failed: %v\n", err)
|
||||
cmd := exec.Command(testGo, "env", "CGO_ENABLED")
|
||||
cmd.Stderr = new(strings.Builder)
|
||||
if out, err := cmd.Output(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "running testgo failed: %v\n%s", err, cmd.Stderr)
|
||||
canRun = false
|
||||
} else {
|
||||
canCgo, err = strconv.ParseBool(strings.TrimSpace(string(out)))
|
||||
|
@ -829,10 +815,9 @@ func removeAll(dir string) error {
|
|||
// module cache has 0444 directories;
|
||||
// make them writable in order to remove content.
|
||||
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return nil // ignore errors walking in file system
|
||||
}
|
||||
if info.IsDir() {
|
||||
// chmod not only directories, but also things that we couldn't even stat
|
||||
// due to permission errors: they may also be unreadable directories.
|
||||
if err != nil || info.IsDir() {
|
||||
os.Chmod(path, 0777)
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -241,7 +241,6 @@ var (
|
|||
// Used in envcmd.MkEnv and build ID computations.
|
||||
GOARM = envOr("GOARM", fmt.Sprint(objabi.GOARM))
|
||||
GO386 = envOr("GO386", objabi.GO386)
|
||||
GOAMD64 = envOr("GOAMD64", objabi.GOAMD64)
|
||||
GOMIPS = envOr("GOMIPS", objabi.GOMIPS)
|
||||
GOMIPS64 = envOr("GOMIPS64", objabi.GOMIPS64)
|
||||
GOPPC64 = envOr("GOPPC64", fmt.Sprintf("%s%d", "power", objabi.GOPPC64))
|
||||
|
@ -267,8 +266,6 @@ func GetArchEnv() (key, val string) {
|
|||
return "GOARM", GOARM
|
||||
case "386":
|
||||
return "GO386", GO386
|
||||
case "amd64":
|
||||
return "GOAMD64", GOAMD64
|
||||
case "mips", "mipsle":
|
||||
return "GOMIPS", GOMIPS
|
||||
case "mips64", "mips64le":
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue