mirror of
https://github.com/golang/go
synced 2024-09-19 07:52:34 +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
|
# 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
|
# line endings. This produces predictable results in different environments.
|
||||||
# modern version of git and editors capable of LF line endings.
|
#
|
||||||
|
# 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
|
# 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
|
* -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>
|
Mayank Kumar <krmayankk@gmail.com>
|
||||||
MediaMath, Inc
|
MediaMath, Inc
|
||||||
Meir Fischer <meirfischer@gmail.com>
|
Meir Fischer <meirfischer@gmail.com>
|
||||||
Meng Zhuo <mengzhuo1203@gmail.com>
|
Meng Zhuo <mengzhuo1203@gmail.com> <mzh@golangcn.org>
|
||||||
Meteor Development Group
|
Meteor Development Group
|
||||||
Mhd Sulhan <m.shulhan@gmail.com>
|
Mhd Sulhan <m.shulhan@gmail.com>
|
||||||
Micah Stetson <micah.stetson@gmail.com>
|
Micah Stetson <micah.stetson@gmail.com>
|
||||||
|
@ -1044,6 +1044,7 @@ Niels Widger <niels.widger@gmail.com>
|
||||||
Nigel Kerr <nigel.kerr@gmail.com>
|
Nigel Kerr <nigel.kerr@gmail.com>
|
||||||
Nik Nyby <nnyby@columbia.edu>
|
Nik Nyby <nnyby@columbia.edu>
|
||||||
Nikhil Benesch <nikhil.benesch@gmail.com>
|
Nikhil Benesch <nikhil.benesch@gmail.com>
|
||||||
|
Nikita Gillmann <nikita@n0.is> <ng0@n0.is>
|
||||||
Niklas Schnelle <niklas.schnelle@gmail.com>
|
Niklas Schnelle <niklas.schnelle@gmail.com>
|
||||||
Niko Dziemba <niko@dziemba.com>
|
Niko Dziemba <niko@dziemba.com>
|
||||||
Nikolay Turpitko <nikolay@turpitko.com>
|
Nikolay Turpitko <nikolay@turpitko.com>
|
||||||
|
@ -1142,6 +1143,7 @@ Pietro Gagliardi <pietro10@mac.com>
|
||||||
Piyush Mishra <piyush@codeitout.com>
|
Piyush Mishra <piyush@codeitout.com>
|
||||||
Platform.sh
|
Platform.sh
|
||||||
Pontus Leitzler <leitzler@gmail.com>
|
Pontus Leitzler <leitzler@gmail.com>
|
||||||
|
Prasanga Siripala <pj@pjebs.com.au>
|
||||||
Prashant Varanasi <prashant@prashantv.com>
|
Prashant Varanasi <prashant@prashantv.com>
|
||||||
Pravendra Singh <hackpravj@gmail.com>
|
Pravendra Singh <hackpravj@gmail.com>
|
||||||
Preetam Jinka <pj@preet.am>
|
Preetam Jinka <pj@preet.am>
|
||||||
|
@ -1396,6 +1398,7 @@ Upthere, Inc.
|
||||||
Uriel Mangado <uriel@berlinblue.org>
|
Uriel Mangado <uriel@berlinblue.org>
|
||||||
Vadim Grek <vadimprog@gmail.com>
|
Vadim Grek <vadimprog@gmail.com>
|
||||||
Vadim Vygonets <unixdj@gmail.com>
|
Vadim Vygonets <unixdj@gmail.com>
|
||||||
|
Vee Zhang <veezhang@126.com> <vveezhang@gmail.com>
|
||||||
Vendasta
|
Vendasta
|
||||||
Veselkov Konstantin <kostozyb@gmail.com>
|
Veselkov Konstantin <kostozyb@gmail.com>
|
||||||
Victor Vrantchan <vrancean+github@gmail.com>
|
Victor Vrantchan <vrancean+github@gmail.com>
|
||||||
|
|
|
@ -958,7 +958,7 @@ Irfan Sharif <irfanmahmoudsharif@gmail.com>
|
||||||
Irieda Noboru <irieda@gmail.com>
|
Irieda Noboru <irieda@gmail.com>
|
||||||
Isaac Ardis <isaac.ardis@gmail.com>
|
Isaac Ardis <isaac.ardis@gmail.com>
|
||||||
Isaac Wagner <ibw@isaacwagner.me>
|
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>
|
Iskander Sharipov <iskander.sharipov@intel.com> <quasilyte@gmail.com>
|
||||||
Issac Trotts <issactrotts@google.com>
|
Issac Trotts <issactrotts@google.com>
|
||||||
Ivan Babrou <ivan@cloudflare.com>
|
Ivan Babrou <ivan@cloudflare.com>
|
||||||
|
@ -1501,7 +1501,7 @@ Maxwell Krohn <themax@gmail.com>
|
||||||
Maya Rashish <maya@NetBSD.org>
|
Maya Rashish <maya@NetBSD.org>
|
||||||
Mayank Kumar <krmayankk@gmail.com>
|
Mayank Kumar <krmayankk@gmail.com>
|
||||||
Meir Fischer <meirfischer@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>
|
Mhd Sulhan <m.shulhan@gmail.com>
|
||||||
Micah Stetson <micah.stetson@gmail.com>
|
Micah Stetson <micah.stetson@gmail.com>
|
||||||
Michael Anthony Knyszek <mknyszek@google.com>
|
Michael Anthony Knyszek <mknyszek@google.com>
|
||||||
|
@ -1654,6 +1654,7 @@ Nigel Kerr <nigel.kerr@gmail.com>
|
||||||
Nigel Tao <nigeltao@golang.org>
|
Nigel Tao <nigeltao@golang.org>
|
||||||
Nik Nyby <nnyby@columbia.edu>
|
Nik Nyby <nnyby@columbia.edu>
|
||||||
Nikhil Benesch <nikhil.benesch@gmail.com>
|
Nikhil Benesch <nikhil.benesch@gmail.com>
|
||||||
|
Nikita Gillmann <nikita@n0.is> <ng0@n0.is>
|
||||||
Nikita Kryuchkov <nkryuchkov10@gmail.com>
|
Nikita Kryuchkov <nkryuchkov10@gmail.com>
|
||||||
Nikita Vanyasin <nikita.vanyasin@gmail.com>
|
Nikita Vanyasin <nikita.vanyasin@gmail.com>
|
||||||
Niklas Schnelle <niklas.schnelle@gmail.com>
|
Niklas Schnelle <niklas.schnelle@gmail.com>
|
||||||
|
@ -1788,6 +1789,7 @@ Pietro Gagliardi <pietro10@mac.com>
|
||||||
Piyush Mishra <piyush@codeitout.com>
|
Piyush Mishra <piyush@codeitout.com>
|
||||||
Plekhanov Maxim <kishtatix@gmail.com>
|
Plekhanov Maxim <kishtatix@gmail.com>
|
||||||
Pontus Leitzler <leitzler@gmail.com>
|
Pontus Leitzler <leitzler@gmail.com>
|
||||||
|
Prasanga Siripala <pj@pjebs.com.au>
|
||||||
Prasanna Swaminathan <prasanna@mediamath.com>
|
Prasanna Swaminathan <prasanna@mediamath.com>
|
||||||
Prashant Agrawal <prashant.a.vjti@gmail.com>
|
Prashant Agrawal <prashant.a.vjti@gmail.com>
|
||||||
Prashant Varanasi <prashant@prashantv.com>
|
Prashant Varanasi <prashant@prashantv.com>
|
||||||
|
@ -2194,6 +2196,7 @@ Vadim Grek <vadimprog@gmail.com>
|
||||||
Vadim Vygonets <unixdj@gmail.com>
|
Vadim Vygonets <unixdj@gmail.com>
|
||||||
Val Polouchkine <vpolouch@justin.tv>
|
Val Polouchkine <vpolouch@justin.tv>
|
||||||
Valentin Vidic <vvidic@valentin-vidic.from.hr>
|
Valentin Vidic <vvidic@valentin-vidic.from.hr>
|
||||||
|
Vee Zhang <veezhang@126.com> <vveezhang@gmail.com>
|
||||||
Vega Garcia Luis Alfonso <vegacom@gmail.com>
|
Vega Garcia Luis Alfonso <vegacom@gmail.com>
|
||||||
Venil Noronha <veniln@vmware.com>
|
Venil Noronha <veniln@vmware.com>
|
||||||
Veselkov Konstantin <kostozyb@gmail.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.
|
a Git server hosted by Google.
|
||||||
Authentication on the web server is made through your Google account, but
|
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.
|
you also need to configure <code>git</code> on your computer to access it.
|
||||||
Follow this steps:
|
Follow these steps:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<ol>
|
<ol>
|
||||||
|
@ -263,6 +263,24 @@ a new issue</a> or by claiming
|
||||||
an <a href="https://golang.org/issues">existing one</a>.
|
an <a href="https://golang.org/issues">existing one</a>.
|
||||||
</p>
|
</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>
|
<h3 id="check_tracker">Check the issue tracker</h3>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
@ -272,6 +290,13 @@ always the first place to go.
|
||||||
Issues are triaged to categorize them and manage the workflow.
|
Issues are triaged to categorize them and manage the workflow.
|
||||||
</p>
|
</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>
|
<p>
|
||||||
Most issues will be marked with one of the following workflow labels:
|
Most issues will be marked with one of the following workflow labels:
|
||||||
</p>
|
</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
|
<b>NeedsDecision</b>: the issue is relatively well understood, but the
|
||||||
Go team hasn't yet decided the best way to address it.
|
Go team hasn't yet decided the best way to address it.
|
||||||
It would be better to wait for a decision before writing code.
|
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
|
feel free to "ping" maintainers in the issue's comments
|
||||||
if some time has passed without a decision.
|
if some time has passed without a decision.
|
||||||
</li>
|
</li>
|
||||||
|
@ -329,11 +354,16 @@ the code review tool is not the place for high-level discussions.
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
When planning work, please note that the Go project follows a <a
|
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>.
|
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
|
for the main Go repository. The latter half of each cycle is a three-month
|
||||||
which only bug fixes and documentation updates are accepted.
|
feature freeze during which only bug fixes and documentation updates are
|
||||||
New contributions can be sent during a feature freeze, but they will
|
accepted. New contributions can be sent during a feature freeze, but they will
|
||||||
not be merged until the freeze is over.
|
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>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
@ -408,13 +438,29 @@ This is an overview of the overall process:
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<b>Step 1:</b> Clone the Go source code from <code>go.googlesource.com</code>
|
<b>Step 1:</b> Clone the source code from <code>go.googlesource.com</code> and
|
||||||
and make sure it's stable by compiling and testing it once:
|
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>
|
<pre>
|
||||||
$ git clone https://go.googlesource.com/go
|
$ git clone https://go.googlesource.com/go
|
||||||
$ cd go/src
|
$ cd go/src
|
||||||
$ ./all.bash # compile and test
|
$ ./all.bash # compile and test
|
||||||
</pre>
|
</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>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
|
@ -434,10 +480,18 @@ $ [etc.]
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<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>
|
<pre>
|
||||||
$ ./all.bash # recompile and test
|
$ ./all.bash # recompile and test
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
<p>In a golang.org/x/... repository:</p>
|
||||||
|
<pre>
|
||||||
|
$ go test ./... # recompile and test
|
||||||
|
</pre>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
|
@ -465,7 +519,7 @@ The rest of this section describes these steps in more detail.
|
||||||
</p>
|
</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>
|
<p>
|
||||||
In addition to a recent Go installation, you need to have a local copy of the source
|
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):
|
Clone from <code>go.googlesource.com</code> (not GitHub):
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p>Main Go repository:</p>
|
||||||
<pre>
|
<pre>
|
||||||
$ git clone https://go.googlesource.com/go
|
$ git clone https://go.googlesource.com/go
|
||||||
$ cd go
|
$ cd go
|
||||||
</pre>
|
</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>
|
<h3 id="make_branch">Step 2: Prepare changes in a new branch</h3>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
@ -543,9 +605,13 @@ into a single one.
|
||||||
<p>
|
<p>
|
||||||
You've <a href="code.html">written and tested your code</a>, but
|
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
|
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>
|
</p>
|
||||||
|
|
||||||
|
<h4 id="test-gorepo">In the main Go repository</h4>
|
||||||
|
|
||||||
|
<p>This can be done by running <code>all.bash</code>:</p>
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
$ cd go/src
|
$ cd go/src
|
||||||
$ ./all.bash
|
$ ./all.bash
|
||||||
|
@ -574,6 +640,33 @@ See also
|
||||||
the section on how to <a href="#quick_test">test your changes quickly</a>.
|
the section on how to <a href="#quick_test">test your changes quickly</a>.
|
||||||
</p>
|
</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>
|
<h3 id="mail">Step 4: Send changes for review</h3>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
@ -720,10 +813,10 @@ when the change is applied.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<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
|
the fully-qualified syntax supported by GitHub to make sure the change is
|
||||||
linked to the issue in the main repository, not the subrepository.
|
linked to the issue in the main repository, not the x/ repository.
|
||||||
All issues are tracked in the main repository's issue tracker.
|
Most issues are tracked in the main repository's issue tracker.
|
||||||
The correct form is "Fixes golang/go#159".
|
The correct form is "Fixes golang/go#159".
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
@ -1070,25 +1163,6 @@ $ $GODIR/bin/go run run.go
|
||||||
</pre>
|
</pre>
|
||||||
</ul>
|
</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>
|
<h3 id="cc">Specifying a reviewer / CCing others</h3>
|
||||||
|
|
||||||
|
@ -1209,5 +1283,5 @@ $ git codereview mail HEAD
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Make sure to explicitly specify <code>HEAD</code>, which is usually not required when sending
|
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>
|
</p>
|
||||||
|
|
|
@ -20,7 +20,7 @@ editing, navigation, testing, and debugging experience.
|
||||||
|
|
||||||
<ul>
|
<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://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>
|
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
|
<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>
|
or as a plugin for IntelliJ IDEA Ultimate</li>
|
||||||
|
|
|
@ -2336,10 +2336,9 @@ of the request from the client.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
For brevity, let's ignore POSTs and assume HTTP requests are always
|
For brevity, let's ignore POSTs and assume HTTP requests are always
|
||||||
GETs; that simplification does not affect the way the handlers are
|
GETs; that simplification does not affect the way the handlers are set up.
|
||||||
set up. Here's a trivial but complete implementation of a handler to
|
Here's a trivial implementation of a handler to count the number of times
|
||||||
count the number of times the
|
the page is visited.
|
||||||
page is visited.
|
|
||||||
</p>
|
</p>
|
||||||
<pre>
|
<pre>
|
||||||
// Simple counter server.
|
// Simple counter server.
|
||||||
|
@ -2355,6 +2354,11 @@ func (ctr *Counter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
<p>
|
<p>
|
||||||
(Keeping with our theme, note how <code>Fprintf</code> can print to an
|
(Keeping with our theme, note how <code>Fprintf</code> can print to an
|
||||||
<code>http.ResponseWriter</code>.)
|
<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.
|
For reference, here's how to attach such a server to a node on the URL tree.
|
||||||
</p>
|
</p>
|
||||||
<pre>
|
<pre>
|
||||||
|
|
|
@ -79,15 +79,13 @@ release.
|
||||||
<h2 id="Source_code">Source code</h2>
|
<h2 id="Source_code">Source code</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
If you cannot use a release, or prefer to build gccgo for
|
If you cannot use a release, or prefer to build gccgo for yourself, the
|
||||||
yourself,
|
gccgo source code is accessible via Git. The GCC web site has
|
||||||
the gccgo source code is accessible via Subversion. The
|
<a href="https://gcc.gnu.org/git.html">instructions for getting the GCC
|
||||||
GCC web site
|
source code</a>. The gccgo source code is included. As a convenience, a
|
||||||
has <a href="https://gcc.gnu.org/svn.html">instructions for getting the
|
stable version of the Go support is available in the
|
||||||
GCC source code</a>. The gccgo source code is included. As a
|
<code>devel/gccgo</code> branch of the main GCC code repository:
|
||||||
convenience, a stable version of the Go support is available in
|
<code>git://gcc.gnu.org/git/gcc.git</code>.
|
||||||
a branch of the main GCC code
|
|
||||||
repository: <code>svn://gcc.gnu.org/svn/gcc/branches/gccgo</code>.
|
|
||||||
This branch is periodically updated with stable Go compiler sources.
|
This branch is periodically updated with stable Go compiler sources.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
@ -139,13 +137,10 @@ which you have write access):
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
cvs -z 9 -d :pserver:anoncvs@sourceware.org:/cvs/src login
|
git clone git://sourceware.org/git/binutils-gdb.git
|
||||||
[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
|
|
||||||
mkdir binutils-objdir
|
mkdir binutils-objdir
|
||||||
cd binutils-objdir
|
cd binutils-objdir
|
||||||
../src/configure --enable-gold=default --prefix=/opt/gold
|
../binutils-gdb/configure --enable-gold=default --prefix=/opt/gold
|
||||||
make
|
make
|
||||||
make install
|
make install
|
||||||
</pre>
|
</pre>
|
||||||
|
@ -176,7 +171,7 @@ described above):
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre>
|
<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
|
mkdir objdir
|
||||||
cd objdir
|
cd objdir
|
||||||
../gccgo/configure --prefix=/opt/gccgo --enable-languages=c,c++,go --with-ld=/opt/gold/bin/ld
|
../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>,
|
runs <a href="#test-vet">vet automatically during tests</a>,
|
||||||
and
|
and
|
||||||
permits <a href="#cgo">passing string values directly between Go and C using cgo</a>.
|
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
|
unexpected <a href="https://golang.org/s/invalidflag"><code>invalid
|
||||||
flag</code></a> errors in code that built successfully with older
|
flag</code></a> errors in code that built successfully with older
|
||||||
releases.
|
releases.
|
||||||
|
@ -267,7 +267,7 @@ and the <a href="/cmd/test2json/">test2json documentation</a>.
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Options specified by cgo using <code>#cgo CFLAGS</code> and the like
|
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
|
This closes a security hole in which a downloaded package uses
|
||||||
compiler options like
|
compiler options like
|
||||||
<span style="white-space: nowrap"><code>-fplugin</code></span>
|
<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.
|
certificate, and letting the package automatically select the best one.
|
||||||
Note that the performance of this selection is going to be poor unless the
|
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>
|
<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>
|
||||||
|
|
||||||
<p><!-- CL 175517 -->
|
<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>
|
<h2 id="language">Changes to the language</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
TODO
|
There are no changes to the language.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2 id="ports">Ports</h2>
|
<h2 id="ports">Ports</h2>
|
||||||
|
|
||||||
<h3 id="darwin">Darwin</h3>
|
<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
|
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,
|
notes, Go 1.15 drops support for 32-bit binaries on macOS, iOS,
|
||||||
iPadOS, watchOS, and tvOS (the <code>darwin/386</code>
|
iPadOS, watchOS, and tvOS (the <code>darwin/386</code>
|
||||||
|
@ -44,21 +50,52 @@ TODO
|
||||||
<h3 id="windows">Windows</h3>
|
<h3 id="windows">Windows</h3>
|
||||||
|
|
||||||
<p> <!-- CL 214397 and CL 230217 -->
|
<p> <!-- CL 214397 and CL 230217 -->
|
||||||
Go 1.15 now generates Windows ASLR executables when -buildmode=pie
|
Go now generates Windows ASLR executables when <code>-buildmode=pie</code>
|
||||||
cmd/link flag is provided. Go command uses -buildmode=pie by default
|
cmd/link flag is provided. Go command uses <code>-buildmode=pie</code>
|
||||||
on Windows.
|
by default on Windows.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p><!-- CL 227003 -->
|
||||||
TODO
|
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>
|
</p>
|
||||||
|
|
||||||
<h2 id="tools">Tools</h2>
|
<h2 id="tools">Tools</h2>
|
||||||
|
|
||||||
<p>
|
|
||||||
TODO
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="go-command">Go command</h3>
|
<h3 id="go-command">Go command</h3>
|
||||||
|
|
||||||
<p><!-- golang.org/issue/37367 -->
|
<p><!-- golang.org/issue/37367 -->
|
||||||
|
@ -73,10 +110,6 @@ TODO
|
||||||
back to <code>direct</code> in case of errors.
|
back to <code>direct</code> in case of errors.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
|
||||||
TODO
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h4 id="go-test"><code>go</code> <code>test</code></h4>
|
<h4 id="go-test"><code>go</code> <code>test</code></h4>
|
||||||
|
|
||||||
<p><!-- https://golang.org/issue/36134 -->
|
<p><!-- https://golang.org/issue/36134 -->
|
||||||
|
@ -112,27 +145,207 @@ TODO
|
||||||
<a href="https://golang.org/issue/36568">issue #36568</a>). The workaround is
|
<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
|
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.
|
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>.
|
<code>GODEBUG=modcacheunzipinplace=1</code>.
|
||||||
</p>
|
</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>
|
<h2 id="runtime">Runtime</h2>
|
||||||
|
|
||||||
<p>
|
<p><!-- CL 221779 -->
|
||||||
TODO
|
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>
|
</p>
|
||||||
|
|
||||||
<h2 id="compiler">Compiler</h2>
|
<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
|
Package <code>unsafe</code>'s <a href="/pkg/unsafe/#Pointer">safety
|
||||||
rules</a> allow converting an <code>unsafe.Pointer</code>
|
rules</a> allow converting an <code>unsafe.Pointer</code>
|
||||||
into <code>uintptr</code> when calling certain
|
into <code>uintptr</code> when calling certain
|
||||||
functions. Previously, in some cases, the compiler allowed multiple
|
functions. Previously, in some cases, the compiler allowed multiple
|
||||||
chained conversions (for example, <code>syscall.Syscall(…,
|
chained conversions (for example, <code>syscall.Syscall(…,</code>
|
||||||
uintptr(uintptr(ptr)), …)</code>). The compiler now requires exactly
|
<code>uintptr(uintptr(ptr)),</code> <code>…)</code>). The compiler
|
||||||
one conversion. Code that used multiple conversions should be
|
now requires exactly one conversion. Code that used multiple
|
||||||
updated to satisfy the safety rules.
|
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>
|
</p>
|
||||||
|
|
||||||
<h2 id="library">Core library</h2>
|
<h2 id="library">Core library</h2>
|
||||||
|
@ -151,25 +364,15 @@ TODO
|
||||||
Either approach increases the size of the program by about 800 KB.
|
Either approach increases the size of the program by about 800 KB.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<h3 id="cgo">Cgo</h3>
|
||||||
TODO
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<dl id="testing"><dt><a href="/pkg/testing/">testing</a></dt>
|
<p><!-- CL 235817 -->
|
||||||
<dd>
|
Go 1.15 will translate the C type <code>EGLConfig</code> to the
|
||||||
<p><!-- golang.org/issue/28135 -->
|
Go type <code>uintptr</code>. This change is similar to how Go
|
||||||
The <code>testing.T</code> type now has a <code>Deadline</code> method
|
1.12 and newer treats <code>EGLDisplay</code>, Darwin's CoreFoundation and
|
||||||
that reports the time at which the test binary will have exceeded its
|
Java's JNI types. See the <a href="/cmd/cgo/#hdr-Special_cases">cgo
|
||||||
timeout.
|
documentation</a> for more information.
|
||||||
</p>
|
</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 -->
|
|
||||||
|
|
||||||
<h3 id="minor_library_changes">Minor changes to the library</h3>
|
<h3 id="minor_library_changes">Minor changes to the library</h3>
|
||||||
|
|
||||||
|
@ -179,27 +382,261 @@ TODO
|
||||||
in mind.
|
in mind.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<dl id="bufio"><dt><a href="/pkg/bufio/">bufio</a></dt>
|
||||||
TODO
|
<dd>
|
||||||
</p>
|
<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>
|
<dd>
|
||||||
<p><!-- CL 214977 -->
|
<p><!-- CL 214977 -->
|
||||||
The new
|
The new
|
||||||
<a href="/pkg/crypto/tls/#Dialer"><code>Dialer</code></a>
|
<a href="/pkg/crypto/tls/#Dialer"><code>Dialer</code></a>
|
||||||
type and its
|
type and its
|
||||||
<a href="/pkg/crypto/tls/#Dialer.DialContext"><code>DialContext</code></a>
|
<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>
|
</p>
|
||||||
</dd>
|
</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>
|
<dl id="flag"><dt><a href="/pkg/flag/">flag</a></dt>
|
||||||
<dd>
|
<dd>
|
||||||
<p><!-- CL 221427 -->
|
<p><!-- CL 221427 -->
|
||||||
When the flag package sees <code>-h</code> or <code>-help</code>, and
|
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
|
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/#ExitOnError"><code>ExitOnError</code></a>,
|
||||||
<a href="/pkg/flag/#FlagSet.Parse"><code>FlagSet.Parse</code></a> would then
|
<a href="/pkg/flag/#FlagSet.Parse"><code>FlagSet.Parse</code></a> would then
|
||||||
|
@ -210,6 +647,46 @@ TODO
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</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>
|
<dl id="net"><dt><a href="/pkg/net/">net</a></dt>
|
||||||
<dd>
|
<dd>
|
||||||
<p><!-- CL 228645 -->
|
<p><!-- CL 228645 -->
|
||||||
|
@ -218,7 +695,7 @@ TODO
|
||||||
<code>Conn.SetReadDeadline</code>,
|
<code>Conn.SetReadDeadline</code>,
|
||||||
or <code>Conn.SetWriteDeadline</code> methods, it will now
|
or <code>Conn.SetWriteDeadline</code> methods, it will now
|
||||||
return an error that is or wraps
|
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
|
This may be used to reliably detect whether an error is due to
|
||||||
an exceeded deadline.
|
an exceeded deadline.
|
||||||
Earlier releases recommended calling the <code>Timeout</code>
|
Earlier releases recommended calling the <code>Timeout</code>
|
||||||
|
@ -234,6 +711,16 @@ TODO
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</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>
|
<dl id="net/http/httputil"><dt><a href="/pkg/net/http/httputil/">net/http/httputil</a></dt>
|
||||||
<dd>
|
<dd>
|
||||||
<p><!-- CL 230937 -->
|
<p><!-- CL 230937 -->
|
||||||
|
@ -242,6 +729,12 @@ TODO
|
||||||
header when the incoming <code>Request.Header</code> map entry
|
header when the incoming <code>Request.Header</code> map entry
|
||||||
for that field is <code>nil</code>.
|
for that field is <code>nil</code>.
|
||||||
</p>
|
</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>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
|
@ -281,7 +774,7 @@ TODO
|
||||||
<a href="/pkg/os/#File.SetReadDeadline"><code>File.SetReadDeadline</code></a>,
|
<a href="/pkg/os/#File.SetReadDeadline"><code>File.SetReadDeadline</code></a>,
|
||||||
or <a href="/pkg/os/#File.SetWriteDeadline"><code>File.SetWriteDeadline</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
|
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
|
This may be used to reliably detect whether an error is due to
|
||||||
an exceeded deadline.
|
an exceeded deadline.
|
||||||
Earlier releases recommended calling the <code>Timeout</code>
|
Earlier releases recommended calling the <code>Timeout</code>
|
||||||
|
@ -289,13 +782,48 @@ TODO
|
||||||
which <code>Timeout</code> returns <code>true</code> although a
|
which <code>Timeout</code> returns <code>true</code> although a
|
||||||
deadline has not been exceeded.
|
deadline has not been exceeded.
|
||||||
</p>
|
</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>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<dl id="reflect"><dt><a href="/pkg/reflect/">reflect</a></dt>
|
<dl id="reflect"><dt><a href="/pkg/reflect/">reflect</a></dt>
|
||||||
<dd>
|
<dd>
|
||||||
<p><!-- CL 228902 -->
|
<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
|
non-exported fields, whereas previously it allowed accessing
|
||||||
those of non-exported, embedded fields. Code that relies on the
|
those of non-exported, embedded fields. Code that relies on the
|
||||||
previous behavior should be updated to instead access the
|
previous behavior should be updated to instead access the
|
||||||
|
@ -304,30 +832,29 @@ TODO
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</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>
|
<dl id="pkg-runtime"><dt><a href="/pkg/runtime/">runtime</a></dt>
|
||||||
<dd>
|
<dd>
|
||||||
<p><!-- CL 221779 -->
|
<p><!-- CL 216557 -->
|
||||||
If <code>panic</code> is invoked with a value whose type is derived from any
|
Several functions, including
|
||||||
of: <code>bool</code>, <code>complex64</code>, <code>complex128</code>, <code>float32</code>, <code>float64</code>,
|
<a href="/pkg/runtime/#ReadMemStats"><code>ReadMemStats</code></a>
|
||||||
<code>int</code>, <code>int8</code>, <code>int16</code>, <code>int32</code>, <code>int64</code>, <code>string</code>,
|
and
|
||||||
<code>uint</code>, <code>uint8</code>, <code>uint16</code>, <code>uint32</code>, <code>uint64</code>, <code>uintptr</code>,
|
<a href="/pkg/runtime/#GoroutineProfile"><code>GoroutineProfile</code></a>,
|
||||||
then the value will be printed, instead of just its address.
|
no longer block if a garbage collection is in progress.
|
||||||
</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>
|
</p>
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</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>
|
<dd>
|
||||||
<p><!-- CL 189318 -->
|
<p><!-- CL 189318 -->
|
||||||
The goroutine profile includes the profile labels associated with each goroutine
|
The goroutine profile includes the profile labels associated with each goroutine
|
||||||
|
@ -337,6 +864,20 @@ TODO
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</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>
|
<dl id="sync"><dt><a href="/pkg/sync/">sync</a></dt>
|
||||||
<dd>
|
<dd>
|
||||||
<p><!-- CL 205899, golang.org/issue/33762 -->
|
<p><!-- CL 205899, golang.org/issue/33762 -->
|
||||||
|
@ -370,18 +911,42 @@ TODO
|
||||||
Some programs that set <code>Setctty</code> will need to change
|
Some programs that set <code>Setctty</code> will need to change
|
||||||
the value of <code>Ctty</code> to use a child descriptor number.
|
the value of <code>Ctty</code> to use a child descriptor number.
|
||||||
</p>
|
</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>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<dl id="testing"><dt><a href="/pkg/testing/">testing</a></dt>
|
<dl id="testing"><dt><a href="/pkg/testing/">testing</a></dt>
|
||||||
<dd>
|
<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 -->
|
<p><!-- CL 226877, golang.org/issue/35998 -->
|
||||||
The new methods
|
The new methods
|
||||||
<a href="/pkg/testing/#T.TempDir"><code>T.TempDir</code></a> and
|
<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
|
return temporary directories that are automatically cleaned up
|
||||||
at the end of the test.
|
at the end of the test.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p><!-- CL 229085 -->
|
||||||
|
TODO: <a href="https://golang.org/cl/229085">https://golang.org/cl/229085</a>: reformat test chatty output
|
||||||
|
</p>
|
||||||
</dd>
|
</dd>
|
||||||
</dl><!-- testing -->
|
</dl><!-- testing -->
|
||||||
|
|
||||||
|
@ -392,5 +957,9 @@ TODO
|
||||||
<a href="/pkg/time/#Ticker.Reset"><code>Ticker.Reset</code></a>
|
<a href="/pkg/time/#Ticker.Reset"><code>Ticker.Reset</code></a>
|
||||||
supports changing the duration of a ticker.
|
supports changing the duration of a ticker.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p><!-- CL 227878 -->
|
||||||
|
When returning an error, <a href="/pkg/time/#ParseDuration"><code>ParseDuration</code></a> now quotes the original value.
|
||||||
|
</p>
|
||||||
</dd>
|
</dd>
|
||||||
</dl><!-- time -->
|
</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.
|
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
|
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,
|
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>
|
</p>
|
||||||
|
|
||||||
<h3 id="assertions">
|
<h3 id="assertions">
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
<h2 id="help">Get help</h2>
|
<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}}
|
{{if not $.GoogleCN}}
|
||||||
<h3 id="mailinglist"><a href="https://groups.google.com/group/golang-nuts">Go Nuts Mailing List</a></h3>
|
<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>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The Go compilers support twelve instruction sets:
|
The Go compilers support the following instruction sets:
|
||||||
|
|
||||||
<dl>
|
<dl>
|
||||||
<dt>
|
<dt>
|
||||||
|
@ -48,24 +48,30 @@ The Go compilers support twelve instruction sets:
|
||||||
<dd>
|
<dd>
|
||||||
The <code>ARM</code> instruction set, 64-bit (<code>AArch64</code>) and 32-bit.
|
The <code>ARM</code> instruction set, 64-bit (<code>AArch64</code>) and 32-bit.
|
||||||
</dd>
|
</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>
|
<dt>
|
||||||
<code>ppc64</code>, <code>ppc64le</code>
|
<code>ppc64</code>, <code>ppc64le</code>
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
The 64-bit PowerPC instruction set, big- and little-endian.
|
The 64-bit PowerPC instruction set, big- and little-endian.
|
||||||
</dd>
|
</dd>
|
||||||
|
<dt>
|
||||||
|
<code>riscv64</code>
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
The 64-bit RISC-V instruction set.
|
||||||
|
</dd>
|
||||||
<dt>
|
<dt>
|
||||||
<code>s390x</code>
|
<code>s390x</code>
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
The IBM z/Architecture.
|
The IBM z/Architecture.
|
||||||
</dd>
|
</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>
|
<dt>
|
||||||
<code>wasm</code>
|
<code>wasm</code>
|
||||||
</dt>
|
</dt>
|
||||||
|
@ -501,7 +507,7 @@ These default to the values of <code>$GOHOSTOS</code> and
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Choices for <code>$GOOS</code> are
|
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>dragonfly</code>, <code>freebsd</code>, <code>illumos</code>, <code>js</code>,
|
||||||
<code>linux</code>, <code>netbsd</code>, <code>openbsd</code>,
|
<code>linux</code>, <code>netbsd</code>, <code>openbsd</code>,
|
||||||
<code>plan9</code>, <code>solaris</code> and <code>windows</code>.
|
<code>plan9</code>, <code>solaris</code> and <code>windows</code>.
|
||||||
|
|
|
@ -2200,3 +2200,7 @@ func test32579(t *testing.T) {
|
||||||
// issue 38649
|
// issue 38649
|
||||||
|
|
||||||
var issue38649 C.netbsd_gid = 42
|
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.
|
// This is the relevant part of EGL/egl.h.
|
||||||
|
|
||||||
typedef void *EGLDisplay;
|
typedef void *EGLDisplay;
|
||||||
|
typedef void *EGLConfig;
|
||||||
|
|
|
@ -13,5 +13,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test27054(t *testing.T) {
|
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",
|
"issue37479",
|
||||||
"issue37621",
|
"issue37621",
|
||||||
"issue38649",
|
"issue38649",
|
||||||
|
"issue39534",
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGoDefs(t *testing.T) {
|
func TestGoDefs(t *testing.T) {
|
||||||
|
|
|
@ -32,7 +32,7 @@ func TestMain(m *testing.M) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testMain(m *testing.M) int {
|
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.
|
// declaring the same path.
|
||||||
|
|
||||||
GOPATH, err := ioutil.TempDir("", "plugin_test")
|
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.
|
// run runs a command and calls t.Errorf if it fails.
|
||||||
func run(t *testing.T, msg string, args ...string) {
|
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:]...)
|
c := exec.Command(args[0], args[1:]...)
|
||||||
|
if len(env) != 0 {
|
||||||
|
c.Env = append(os.Environ(), env...)
|
||||||
|
}
|
||||||
if output, err := c.CombinedOutput(); err != nil {
|
if output, err := c.CombinedOutput(); err != nil {
|
||||||
t.Errorf("executing %s (%s) failed %s:\n%s", strings.Join(args, " "), msg, err, output)
|
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, "install", "-buildmode=shared", "-linkshared", "./issue30768/issue30768lib")
|
||||||
goCmd(nil, "test", "-linkshared", "./issue30768")
|
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 storeValue = (addr, v) => {
|
||||||
const nanHead = 0x7FF80000;
|
const nanHead = 0x7FF80000;
|
||||||
|
|
||||||
if (typeof v === "number") {
|
if (typeof v === "number" && v !== 0) {
|
||||||
if (isNaN(v)) {
|
if (isNaN(v)) {
|
||||||
this.mem.setUint32(addr + 4, nanHead, true);
|
this.mem.setUint32(addr + 4, nanHead, true);
|
||||||
this.mem.setUint32(addr, 0, true);
|
this.mem.setUint32(addr, 0, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (v === 0) {
|
|
||||||
this.mem.setUint32(addr + 4, nanHead, true);
|
|
||||||
this.mem.setUint32(addr, 1, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.mem.setFloat64(addr, v, true);
|
this.mem.setFloat64(addr, v, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (v) {
|
if (v === undefined) {
|
||||||
case undefined:
|
this.mem.setFloat64(addr, 0, true);
|
||||||
this.mem.setFloat64(addr, 0, true);
|
return;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let id = this._ids.get(v);
|
let id = this._ids.get(v);
|
||||||
|
@ -219,8 +201,13 @@
|
||||||
this._ids.set(v, id);
|
this._ids.set(v, id);
|
||||||
}
|
}
|
||||||
this._goRefCounts[id]++;
|
this._goRefCounts[id]++;
|
||||||
let typeFlag = 1;
|
let typeFlag = 0;
|
||||||
switch (typeof v) {
|
switch (typeof v) {
|
||||||
|
case "object":
|
||||||
|
if (v !== null) {
|
||||||
|
typeFlag = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case "string":
|
case "string":
|
||||||
typeFlag = 2;
|
typeFlag = 2;
|
||||||
break;
|
break;
|
||||||
|
@ -493,10 +480,17 @@
|
||||||
global,
|
global,
|
||||||
this,
|
this,
|
||||||
];
|
];
|
||||||
this._goRefCounts = []; // number of references that Go has to a JS value, indexed by reference id
|
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
|
this._ids = new Map([ // mapping from JS values to reference ids
|
||||||
this._idPool = []; // unused ids that have been garbage collected
|
[0, 1],
|
||||||
this.exited = false; // whether the Go program has exited
|
[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.
|
// Pass command line arguments and environment variables to WebAssembly by writing them to the linear memory.
|
||||||
let offset = 4096;
|
let offset = 4096;
|
||||||
|
|
|
@ -558,8 +558,8 @@ func (r *negativeEOFReader) Read(p []byte) (int, error) {
|
||||||
return -1, io.EOF
|
return -1, io.EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that the scanner doesn't panic on a reader that returns a
|
// Test that the scanner doesn't panic and returns ErrBadReadCount
|
||||||
// negative count of bytes read (issue 38053).
|
// on a reader that returns a negative count of bytes read (issue 38053).
|
||||||
func TestNegativeEOFReader(t *testing.T) {
|
func TestNegativeEOFReader(t *testing.T) {
|
||||||
r := negativeEOFReader(10)
|
r := negativeEOFReader(10)
|
||||||
scanner := NewScanner(&r)
|
scanner := NewScanner(&r)
|
||||||
|
@ -571,8 +571,8 @@ func TestNegativeEOFReader(t *testing.T) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if scanner.Err() == nil {
|
if got, want := scanner.Err(), ErrBadReadCount; got != want {
|
||||||
t.Error("scanner.Err returned nil, expected an error")
|
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
|
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) {
|
func TestLargeReader(t *testing.T) {
|
||||||
scanner := NewScanner(largeReader{})
|
scanner := NewScanner(largeReader{})
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
}
|
}
|
||||||
if scanner.Err() == nil {
|
if got, want := scanner.Err(), ErrBadReadCount; got != want {
|
||||||
t.Error("scanner.Err returned nil, expected an error")
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Stat failed: %v", err)
|
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)
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("Stat failed: %v", err)
|
t.Fatalf("Stat failed: %v", err)
|
||||||
}
|
}
|
||||||
if !os.SameFile(fi1, fi2) {
|
if !os.SameFile(fi1, fi2) {
|
||||||
t.Fatalf("addr2line_test.go and %s are not same file", srcPath)
|
t.Fatalf("addr2line_test.go and %s are not same file", srcPath)
|
||||||
}
|
}
|
||||||
if srcLineNo != "89" {
|
if srcLineNo != "99" {
|
||||||
t.Fatalf("line number = %v; want 89", srcLineNo)
|
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) {
|
func TestAddr2Line(t *testing.T) {
|
||||||
testenv.MustHaveGoBuild(t)
|
testenv.MustHaveGoBuild(t)
|
||||||
|
|
||||||
|
|
|
@ -33,14 +33,17 @@ Flags:
|
||||||
Dump instructions as they are parsed.
|
Dump instructions as they are parsed.
|
||||||
-dynlink
|
-dynlink
|
||||||
Support references to Go symbols defined in other shared libraries.
|
Support references to Go symbols defined in other shared libraries.
|
||||||
|
-gensymabis
|
||||||
|
Write symbol ABI information to output file. Don't assemble.
|
||||||
-o file
|
-o file
|
||||||
Write output to file. The default is foo.o for /a/b/c/foo.s.
|
Write output to file. The default is foo.o for /a/b/c/foo.s.
|
||||||
-shared
|
-shared
|
||||||
Generate code that can be linked into a shared library.
|
Generate code that can be linked into a shared library.
|
||||||
|
-spectre list
|
||||||
|
Enable spectre mitigations in list (all, ret).
|
||||||
-trimpath prefix
|
-trimpath prefix
|
||||||
Remove prefix from recorded source file paths.
|
Remove prefix from recorded source file paths.
|
||||||
-gensymabis
|
|
||||||
Write symbol ABI information to output file. Don't assemble.
|
|
||||||
Input language:
|
Input language:
|
||||||
|
|
||||||
The assembler uses mostly the same syntax for all architectures,
|
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
|
ADDW $0x60060, R2 // ADDW $393312, R2 // 4280011142804111
|
||||||
CMPW $0x60060, R2 // CMPW $393312, R2 // 1b0c8052db00a0725f001b6b
|
CMPW $0x60060, R2 // CMPW $393312, R2 // 1b0c8052db00a0725f001b6b
|
||||||
|
|
||||||
|
// TODO: this could have better encoding
|
||||||
|
ANDW $-1, R10 // 1b0080124a011b0a
|
||||||
|
|
||||||
AND $8, R0, RSP // 1f007d92
|
AND $8, R0, RSP // 1f007d92
|
||||||
ORR $8, R0, RSP // 1f007db2
|
ORR $8, R0, RSP // 1f007db2
|
||||||
EOR $8, R0, RSP // 1f007dd2
|
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
|
UXTBW R2, R6 // 461c0053
|
||||||
UXTHW R7, R20 // f43c0053
|
UXTHW R7, R20 // f43c0053
|
||||||
VCNT V0.B8, V0.B8 // 0058200e
|
VCNT V0.B8, V0.B8 // 0058200e
|
||||||
|
VCNT V0.B16, V0.B16 // 0058204e
|
||||||
WFE // 5f2003d5
|
WFE // 5f2003d5
|
||||||
WFI // 7f2003d5
|
WFI // 7f2003d5
|
||||||
YIELD // 3f2003d5
|
YIELD // 3f2003d5
|
||||||
|
|
|
@ -413,7 +413,7 @@ type in Go are instead represented by a uintptr. Those include:
|
||||||
jobjectArray
|
jobjectArray
|
||||||
jweak
|
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
|
These types are uintptr on the Go side because they would otherwise
|
||||||
confuse the Go garbage collector; they are sometimes not really
|
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.
|
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:
|
to auto-update code from Go 1.11 and earlier:
|
||||||
|
|
||||||
go tool fix -r egl <pkg>
|
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
|
Using cgo directly
|
||||||
|
|
||||||
Usage:
|
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.
|
linker in external linking mode.
|
||||||
|
|
||||||
By default, cmd/link will decide the linking mode as follows: if the only
|
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
|
packages (net, os/user, runtime/cgo), cmd/link will use internal linking
|
||||||
mode. Otherwise, there are non-standard cgo packages involved, and cmd/link
|
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
|
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 {
|
if *godefs {
|
||||||
// Substitute definition for mangled type name.
|
// 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
|
expr = r.Name.Type.Go
|
||||||
}
|
}
|
||||||
if id, ok := expr.(*ast.Ident); ok {
|
if id, ok := expr.(*ast.Ident); ok {
|
||||||
|
@ -3029,7 +3029,7 @@ func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool {
|
||||||
if c.badJNI(dt) {
|
if c.badJNI(dt) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if c.badEGLDisplay(dt) {
|
if c.badEGLType(dt) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -3168,11 +3168,11 @@ func (c *typeConv) badJNI(dt *dwarf.TypedefType) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *typeConv) badEGLDisplay(dt *dwarf.TypedefType) bool {
|
func (c *typeConv) badEGLType(dt *dwarf.TypedefType) bool {
|
||||||
if dt.Name != "EGLDisplay" {
|
if dt.Name != "EGLDisplay" && dt.Name != "EGLConfig" {
|
||||||
return false
|
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 ptr, ok := dt.Type.(*dwarf.PtrType); ok {
|
||||||
if _, ok := ptr.Type.(*dwarf.VoidType); ok {
|
if _, ok := ptr.Type.(*dwarf.VoidType); ok {
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -98,6 +98,11 @@ func (p *Package) writeDefs() {
|
||||||
|
|
||||||
typedefNames := make([]string, 0, len(typedef))
|
typedefNames := make([]string, 0, len(typedef))
|
||||||
for name := range typedef {
|
for name := range typedef {
|
||||||
|
if name == "_Ctype_void" {
|
||||||
|
// We provide an appropriate declaration for
|
||||||
|
// _Ctype_void below (#39877).
|
||||||
|
continue
|
||||||
|
}
|
||||||
typedefNames = append(typedefNames, name)
|
typedefNames = append(typedefNames, name)
|
||||||
}
|
}
|
||||||
sort.Strings(typedefNames)
|
sort.Strings(typedefNames)
|
||||||
|
|
|
@ -107,6 +107,8 @@ Flags:
|
||||||
Warn about composite literals that can be simplified.
|
Warn about composite literals that can be simplified.
|
||||||
-shared
|
-shared
|
||||||
Generate code that can be linked into a shared library.
|
Generate code that can be linked into a shared library.
|
||||||
|
-spectre list
|
||||||
|
Enable spectre mitigations in list (all, index, ret).
|
||||||
-traceprofile file
|
-traceprofile file
|
||||||
Write an execution trace to file.
|
Write an execution trace to file.
|
||||||
-trimpath prefix
|
-trimpath prefix
|
||||||
|
|
|
@ -96,7 +96,7 @@ func TestFormats(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
importPath := filepath.Join("cmd/compile", path)
|
importPath := filepath.Join("cmd/compile", path)
|
||||||
if blacklistedPackages[filepath.ToSlash(importPath)] {
|
if ignoredPackages[filepath.ToSlash(importPath)] {
|
||||||
return filepath.SkipDir
|
return filepath.SkipDir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,8 +344,7 @@ func collectPkgFormats(t *testing.T, pkg *build.Package) {
|
||||||
for index, file := range files {
|
for index, file := range files {
|
||||||
ast.Inspect(file, func(n ast.Node) bool {
|
ast.Inspect(file, func(n ast.Node) bool {
|
||||||
if call, ok := n.(*ast.CallExpr); ok {
|
if call, ok := n.(*ast.CallExpr); ok {
|
||||||
// ignore blacklisted functions
|
if ignoredFunctions[nodeString(call.Fun)] {
|
||||||
if blacklistedFunctions[nodeString(call.Fun)] {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// look for an arguments that might be a format string
|
// 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
|
// make sure we have enough arguments
|
||||||
n := numFormatArgs(s)
|
n := numFormatArgs(s)
|
||||||
if i+1+n > len(call.Args) {
|
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
|
break // ignore this call
|
||||||
}
|
}
|
||||||
// assume last n arguments are to be formatted;
|
// 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:]...))
|
return string(append(buf, in[i0:]...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// blacklistedPackages is the set of packages which can
|
// ignoredPackages is the set of packages which can
|
||||||
// be ignored.
|
// 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
|
// format-like arguments but which don't do any formatting and
|
||||||
// thus may be ignored.
|
// thus may be ignored.
|
||||||
var blacklistedFunctions = map[string]bool{}
|
var ignoredFunctions = map[string]bool{}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// verify that knownFormats entries are correctly formatted
|
// 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.Sym %v": "",
|
||||||
"cmd/compile/internal/ssa.ValAndOff %s": "",
|
"cmd/compile/internal/ssa.ValAndOff %s": "",
|
||||||
"cmd/compile/internal/ssa.domain %v": "",
|
"cmd/compile/internal/ssa.domain %v": "",
|
||||||
|
"cmd/compile/internal/ssa.flagConstant %s": "",
|
||||||
"cmd/compile/internal/ssa.posetNode %v": "",
|
"cmd/compile/internal/ssa.posetNode %v": "",
|
||||||
"cmd/compile/internal/ssa.posetTestOp %v": "",
|
"cmd/compile/internal/ssa.posetTestOp %v": "",
|
||||||
"cmd/compile/internal/ssa.rbrank %d": "",
|
"cmd/compile/internal/ssa.rbrank %d": "",
|
||||||
|
@ -140,6 +141,7 @@ var knownFormats = map[string]string{
|
||||||
"float64 %.3f": "",
|
"float64 %.3f": "",
|
||||||
"float64 %.6g": "",
|
"float64 %.6g": "",
|
||||||
"float64 %g": "",
|
"float64 %g": "",
|
||||||
|
"int %#x": "",
|
||||||
"int %-12d": "",
|
"int %-12d": "",
|
||||||
"int %-6d": "",
|
"int %-6d": "",
|
||||||
"int %-8o": "",
|
"int %-8o": "",
|
||||||
|
@ -151,9 +153,11 @@ var knownFormats = map[string]string{
|
||||||
"int %x": "",
|
"int %x": "",
|
||||||
"int16 %d": "",
|
"int16 %d": "",
|
||||||
"int16 %x": "",
|
"int16 %x": "",
|
||||||
|
"int32 %#x": "",
|
||||||
"int32 %d": "",
|
"int32 %d": "",
|
||||||
"int32 %v": "",
|
"int32 %v": "",
|
||||||
"int32 %x": "",
|
"int32 %x": "",
|
||||||
|
"int64 %#x": "",
|
||||||
"int64 %+d": "",
|
"int64 %+d": "",
|
||||||
"int64 %-10d": "",
|
"int64 %-10d": "",
|
||||||
"int64 %.5d": "",
|
"int64 %.5d": "",
|
||||||
|
@ -201,6 +205,7 @@ var knownFormats = map[string]string{
|
||||||
"uint64 %b": "",
|
"uint64 %b": "",
|
||||||
"uint64 %d": "",
|
"uint64 %d": "",
|
||||||
"uint64 %x": "",
|
"uint64 %x": "",
|
||||||
|
"uint8 %#x": "",
|
||||||
"uint8 %d": "",
|
"uint8 %d": "",
|
||||||
"uint8 %v": "",
|
"uint8 %v": "",
|
||||||
"uint8 %x": "",
|
"uint8 %x": "",
|
||||||
|
|
|
@ -1252,11 +1252,11 @@ var blockJump = [...]struct {
|
||||||
ssa.BlockAMD64NAN: {x86.AJPS, x86.AJPC},
|
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.AJPS, Index: 1}}, // next == b.Succs[0]
|
||||||
{{Jump: x86.AJNE, Index: 1}, {Jump: x86.AJPC, Index: 0}}, // next == b.Succs[1]
|
{{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.AJPC, Index: 1}}, // next == b.Succs[0]
|
||||||
{{Jump: x86.AJNE, Index: 0}, {Jump: x86.AJPS, Index: 0}}, // next == b.Succs[1]
|
{{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)
|
p.To.Sym = b.Aux.(*obj.LSym)
|
||||||
|
|
||||||
case ssa.BlockAMD64EQF:
|
case ssa.BlockAMD64EQF:
|
||||||
s.FPJump(b, next, &eqfJumps)
|
s.CombJump(b, next, &eqfJumps)
|
||||||
|
|
||||||
case ssa.BlockAMD64NEF:
|
case ssa.BlockAMD64NEF:
|
||||||
s.FPJump(b, next, &nefJumps)
|
s.CombJump(b, next, &nefJumps)
|
||||||
|
|
||||||
case ssa.BlockAMD64EQ, ssa.BlockAMD64NE,
|
case ssa.BlockAMD64EQ, ssa.BlockAMD64NE,
|
||||||
ssa.BlockAMD64LT, ssa.BlockAMD64GE,
|
ssa.BlockAMD64LT, ssa.BlockAMD64GE,
|
||||||
|
|
|
@ -857,12 +857,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||||
p := s.Prog(obj.AGETCALLERPC)
|
p := s.Prog(obj.AGETCALLERPC)
|
||||||
p.To.Type = obj.TYPE_REG
|
p.To.Type = obj.TYPE_REG
|
||||||
p.To.Reg = v.Reg()
|
p.To.Reg = v.Reg()
|
||||||
case ssa.OpARMFlagEQ,
|
case ssa.OpARMFlagConstant:
|
||||||
ssa.OpARMFlagLT_ULT,
|
v.Fatalf("FlagConstant op should never make it to codegen %v", v.LongString())
|
||||||
ssa.OpARMFlagLT_UGT,
|
|
||||||
ssa.OpARMFlagGT_ULT,
|
|
||||||
ssa.OpARMFlagGT_UGT:
|
|
||||||
v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString())
|
|
||||||
case ssa.OpARMInvertFlags:
|
case ssa.OpARMInvertFlags:
|
||||||
v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
|
v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
|
||||||
case ssa.OpClobber:
|
case ssa.OpClobber:
|
||||||
|
@ -888,16 +884,30 @@ var condBits = map[ssa.Op]uint8{
|
||||||
var blockJump = map[ssa.BlockKind]struct {
|
var blockJump = map[ssa.BlockKind]struct {
|
||||||
asm, invasm obj.As
|
asm, invasm obj.As
|
||||||
}{
|
}{
|
||||||
ssa.BlockARMEQ: {arm.ABEQ, arm.ABNE},
|
ssa.BlockARMEQ: {arm.ABEQ, arm.ABNE},
|
||||||
ssa.BlockARMNE: {arm.ABNE, arm.ABEQ},
|
ssa.BlockARMNE: {arm.ABNE, arm.ABEQ},
|
||||||
ssa.BlockARMLT: {arm.ABLT, arm.ABGE},
|
ssa.BlockARMLT: {arm.ABLT, arm.ABGE},
|
||||||
ssa.BlockARMGE: {arm.ABGE, arm.ABLT},
|
ssa.BlockARMGE: {arm.ABGE, arm.ABLT},
|
||||||
ssa.BlockARMLE: {arm.ABLE, arm.ABGT},
|
ssa.BlockARMLE: {arm.ABLE, arm.ABGT},
|
||||||
ssa.BlockARMGT: {arm.ABGT, arm.ABLE},
|
ssa.BlockARMGT: {arm.ABGT, arm.ABLE},
|
||||||
ssa.BlockARMULT: {arm.ABLO, arm.ABHS},
|
ssa.BlockARMULT: {arm.ABLO, arm.ABHS},
|
||||||
ssa.BlockARMUGE: {arm.ABHS, arm.ABLO},
|
ssa.BlockARMUGE: {arm.ABHS, arm.ABLO},
|
||||||
ssa.BlockARMUGT: {arm.ABHI, arm.ABLS},
|
ssa.BlockARMUGT: {arm.ABHI, arm.ABLS},
|
||||||
ssa.BlockARMULE: {arm.ABLS, arm.ABHI},
|
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) {
|
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.BlockARMLT, ssa.BlockARMGE,
|
||||||
ssa.BlockARMLE, ssa.BlockARMGT,
|
ssa.BlockARMLE, ssa.BlockARMGT,
|
||||||
ssa.BlockARMULT, ssa.BlockARMUGT,
|
ssa.BlockARMULT, ssa.BlockARMUGT,
|
||||||
ssa.BlockARMULE, ssa.BlockARMUGE:
|
ssa.BlockARMULE, ssa.BlockARMUGE,
|
||||||
|
ssa.BlockARMLTnoov, ssa.BlockARMGEnoov:
|
||||||
jmp := blockJump[b.Kind]
|
jmp := blockJump[b.Kind]
|
||||||
switch next {
|
switch next {
|
||||||
case b.Succs[0].Block():
|
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:
|
default:
|
||||||
b.Fatalf("branch not implemented: %s", b.LongString())
|
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 := s.Prog(obj.AGETCALLERPC)
|
||||||
p.To.Type = obj.TYPE_REG
|
p.To.Type = obj.TYPE_REG
|
||||||
p.To.Reg = v.Reg()
|
p.To.Reg = v.Reg()
|
||||||
case ssa.OpARM64FlagEQ,
|
case ssa.OpARM64FlagConstant:
|
||||||
ssa.OpARM64FlagLT_ULT,
|
v.Fatalf("FlagConstant op should never make it to codegen %v", v.LongString())
|
||||||
ssa.OpARM64FlagLT_UGT,
|
|
||||||
ssa.OpARM64FlagGT_ULT,
|
|
||||||
ssa.OpARM64FlagGT_UGT:
|
|
||||||
v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString())
|
|
||||||
case ssa.OpARM64InvertFlags:
|
case ssa.OpARM64InvertFlags:
|
||||||
v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
|
v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
|
||||||
case ssa.OpClobber:
|
case ssa.OpClobber:
|
||||||
|
@ -978,26 +974,40 @@ var condBits = map[ssa.Op]int16{
|
||||||
var blockJump = map[ssa.BlockKind]struct {
|
var blockJump = map[ssa.BlockKind]struct {
|
||||||
asm, invasm obj.As
|
asm, invasm obj.As
|
||||||
}{
|
}{
|
||||||
ssa.BlockARM64EQ: {arm64.ABEQ, arm64.ABNE},
|
ssa.BlockARM64EQ: {arm64.ABEQ, arm64.ABNE},
|
||||||
ssa.BlockARM64NE: {arm64.ABNE, arm64.ABEQ},
|
ssa.BlockARM64NE: {arm64.ABNE, arm64.ABEQ},
|
||||||
ssa.BlockARM64LT: {arm64.ABLT, arm64.ABGE},
|
ssa.BlockARM64LT: {arm64.ABLT, arm64.ABGE},
|
||||||
ssa.BlockARM64GE: {arm64.ABGE, arm64.ABLT},
|
ssa.BlockARM64GE: {arm64.ABGE, arm64.ABLT},
|
||||||
ssa.BlockARM64LE: {arm64.ABLE, arm64.ABGT},
|
ssa.BlockARM64LE: {arm64.ABLE, arm64.ABGT},
|
||||||
ssa.BlockARM64GT: {arm64.ABGT, arm64.ABLE},
|
ssa.BlockARM64GT: {arm64.ABGT, arm64.ABLE},
|
||||||
ssa.BlockARM64ULT: {arm64.ABLO, arm64.ABHS},
|
ssa.BlockARM64ULT: {arm64.ABLO, arm64.ABHS},
|
||||||
ssa.BlockARM64UGE: {arm64.ABHS, arm64.ABLO},
|
ssa.BlockARM64UGE: {arm64.ABHS, arm64.ABLO},
|
||||||
ssa.BlockARM64UGT: {arm64.ABHI, arm64.ABLS},
|
ssa.BlockARM64UGT: {arm64.ABHI, arm64.ABLS},
|
||||||
ssa.BlockARM64ULE: {arm64.ABLS, arm64.ABHI},
|
ssa.BlockARM64ULE: {arm64.ABLS, arm64.ABHI},
|
||||||
ssa.BlockARM64Z: {arm64.ACBZ, arm64.ACBNZ},
|
ssa.BlockARM64Z: {arm64.ACBZ, arm64.ACBNZ},
|
||||||
ssa.BlockARM64NZ: {arm64.ACBNZ, arm64.ACBZ},
|
ssa.BlockARM64NZ: {arm64.ACBNZ, arm64.ACBZ},
|
||||||
ssa.BlockARM64ZW: {arm64.ACBZW, arm64.ACBNZW},
|
ssa.BlockARM64ZW: {arm64.ACBZW, arm64.ACBNZW},
|
||||||
ssa.BlockARM64NZW: {arm64.ACBNZW, arm64.ACBZW},
|
ssa.BlockARM64NZW: {arm64.ACBNZW, arm64.ACBZW},
|
||||||
ssa.BlockARM64TBZ: {arm64.ATBZ, arm64.ATBNZ},
|
ssa.BlockARM64TBZ: {arm64.ATBZ, arm64.ATBNZ},
|
||||||
ssa.BlockARM64TBNZ: {arm64.ATBNZ, arm64.ATBZ},
|
ssa.BlockARM64TBNZ: {arm64.ATBNZ, arm64.ATBZ},
|
||||||
ssa.BlockARM64FLT: {arm64.ABMI, arm64.ABPL},
|
ssa.BlockARM64FLT: {arm64.ABMI, arm64.ABPL},
|
||||||
ssa.BlockARM64FGE: {arm64.ABGE, arm64.ABLT},
|
ssa.BlockARM64FGE: {arm64.ABGE, arm64.ABLT},
|
||||||
ssa.BlockARM64FLE: {arm64.ABLS, arm64.ABHI},
|
ssa.BlockARM64FLE: {arm64.ABLS, arm64.ABHI},
|
||||||
ssa.BlockARM64FGT: {arm64.ABGT, arm64.ABLE},
|
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) {
|
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.BlockARM64Z, ssa.BlockARM64NZ,
|
||||||
ssa.BlockARM64ZW, ssa.BlockARM64NZW,
|
ssa.BlockARM64ZW, ssa.BlockARM64NZW,
|
||||||
ssa.BlockARM64FLT, ssa.BlockARM64FGE,
|
ssa.BlockARM64FLT, ssa.BlockARM64FGE,
|
||||||
ssa.BlockARM64FLE, ssa.BlockARM64FGT:
|
ssa.BlockARM64FLE, ssa.BlockARM64FGT,
|
||||||
|
ssa.BlockARM64LTnoov, ssa.BlockARM64GEnoov:
|
||||||
jmp := blockJump[b.Kind]
|
jmp := blockJump[b.Kind]
|
||||||
var p *obj.Prog
|
var p *obj.Prog
|
||||||
switch next {
|
switch next {
|
||||||
|
@ -1087,6 +1098,10 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
|
||||||
p.From.Type = obj.TYPE_CONST
|
p.From.Type = obj.TYPE_CONST
|
||||||
p.Reg = b.Controls[0].Reg()
|
p.Reg = b.Controls[0].Reg()
|
||||||
|
|
||||||
|
case ssa.BlockARM64LEnoov:
|
||||||
|
s.CombJump(b, next, &leJumps)
|
||||||
|
case ssa.BlockARM64GTnoov:
|
||||||
|
s.CombJump(b, next, >Jumps)
|
||||||
default:
|
default:
|
||||||
b.Fatalf("branch not implemented: %s", b.LongString())
|
b.Fatalf("branch not implemented: %s", b.LongString())
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,26 @@ func IncomparableField(t *types.Type) *types.Field {
|
||||||
return nil
|
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
|
// algtype is like algtype1, except it returns the fixed-width AMEMxx variants
|
||||||
// instead of the general AMEM kind when possible.
|
// instead of the general AMEM kind when possible.
|
||||||
func algtype(t *types.Type) AlgKind {
|
func algtype(t *types.Type) AlgKind {
|
||||||
|
@ -591,24 +611,6 @@ func geneq(t *types.Type) *obj.LSym {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch t.Elem().Etype {
|
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:
|
case TSTRING:
|
||||||
// Do two loops. First, check that all the lengths match (cheap).
|
// Do two loops. First, check that all the lengths match (cheap).
|
||||||
// Second, check that all the contents match (expensive).
|
// Second, check that all the contents match (expensive).
|
||||||
|
@ -642,14 +644,19 @@ func geneq(t *types.Type) *obj.LSym {
|
||||||
|
|
||||||
case TSTRUCT:
|
case TSTRUCT:
|
||||||
// Build a list of conditions to satisfy.
|
// 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 {
|
type nodeIdx struct {
|
||||||
n *Node
|
n *Node
|
||||||
idx int
|
idx int
|
||||||
}
|
}
|
||||||
var conds []nodeIdx
|
var conds [][]nodeIdx
|
||||||
|
conds = append(conds, []nodeIdx{})
|
||||||
and := func(n *Node) {
|
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
|
// 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.
|
// Compare non-memory fields with field equality.
|
||||||
if !IsRegularMemory(f.Type) {
|
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)
|
p := nodSym(OXDOT, np, f.Sym)
|
||||||
q := nodSym(OXDOT, nq, f.Sym)
|
q := nodSym(OXDOT, nq, f.Sym)
|
||||||
switch {
|
switch {
|
||||||
|
@ -672,17 +683,13 @@ func geneq(t *types.Type) *obj.LSym {
|
||||||
eqlen, eqmem := eqstring(p, q)
|
eqlen, eqmem := eqstring(p, q)
|
||||||
and(eqlen)
|
and(eqlen)
|
||||||
and(eqmem)
|
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:
|
default:
|
||||||
and(nod(OEQ, p, q))
|
and(nod(OEQ, p, q))
|
||||||
}
|
}
|
||||||
|
if EqCanPanic(f.Type) {
|
||||||
|
// Also enforce ordering after something that can panic.
|
||||||
|
conds = append(conds, []nodeIdx{})
|
||||||
|
}
|
||||||
i++
|
i++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -706,20 +713,24 @@ func geneq(t *types.Type) *obj.LSym {
|
||||||
|
|
||||||
// Sort conditions to put runtime calls last.
|
// Sort conditions to put runtime calls last.
|
||||||
// Preserve the rest of the ordering.
|
// Preserve the rest of the ordering.
|
||||||
sort.SliceStable(conds, func(i, j int) bool {
|
var flatConds []nodeIdx
|
||||||
x, y := conds[i], conds[j]
|
for _, c := range conds {
|
||||||
if (x.n.Op != OCALL) == (y.n.Op != OCALL) {
|
sort.SliceStable(c, func(i, j int) bool {
|
||||||
return x.idx < y.idx
|
x, y := c[i], c[j]
|
||||||
}
|
if (x.n.Op != OCALL) == (y.n.Op != OCALL) {
|
||||||
return x.n.Op != OCALL
|
return x.idx < y.idx
|
||||||
})
|
}
|
||||||
|
return x.n.Op != OCALL
|
||||||
|
})
|
||||||
|
flatConds = append(flatConds, c...)
|
||||||
|
}
|
||||||
|
|
||||||
var cond *Node
|
var cond *Node
|
||||||
if len(conds) == 0 {
|
if len(flatConds) == 0 {
|
||||||
cond = nodbool(true)
|
cond = nodbool(true)
|
||||||
} else {
|
} else {
|
||||||
cond = conds[0].n
|
cond = flatConds[0].n
|
||||||
for _, c := range conds[1:] {
|
for _, c := range flatConds[1:] {
|
||||||
cond = nod(OANDAND, cond, c.n)
|
cond = nod(OANDAND, cond, c.n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,325 +10,329 @@ var runtimeDecls = [...]struct {
|
||||||
typ int
|
typ int
|
||||||
}{
|
}{
|
||||||
{"newobject", funcTag, 4},
|
{"newobject", funcTag, 4},
|
||||||
{"panicdivide", funcTag, 5},
|
{"mallocgc", funcTag, 8},
|
||||||
{"panicshift", funcTag, 5},
|
{"panicdivide", funcTag, 9},
|
||||||
{"panicmakeslicelen", funcTag, 5},
|
{"panicshift", funcTag, 9},
|
||||||
{"panicmakeslicecap", funcTag, 5},
|
{"panicmakeslicelen", funcTag, 9},
|
||||||
{"throwinit", funcTag, 5},
|
{"panicmakeslicecap", funcTag, 9},
|
||||||
{"panicwrap", funcTag, 5},
|
{"throwinit", funcTag, 9},
|
||||||
{"gopanic", funcTag, 7},
|
{"panicwrap", funcTag, 9},
|
||||||
{"gorecover", funcTag, 10},
|
{"gopanic", funcTag, 11},
|
||||||
{"goschedguarded", funcTag, 5},
|
{"gorecover", funcTag, 14},
|
||||||
{"goPanicIndex", funcTag, 12},
|
{"goschedguarded", funcTag, 9},
|
||||||
{"goPanicIndexU", funcTag, 14},
|
{"goPanicIndex", funcTag, 16},
|
||||||
{"goPanicSliceAlen", funcTag, 12},
|
{"goPanicIndexU", funcTag, 18},
|
||||||
{"goPanicSliceAlenU", funcTag, 14},
|
{"goPanicSliceAlen", funcTag, 16},
|
||||||
{"goPanicSliceAcap", funcTag, 12},
|
{"goPanicSliceAlenU", funcTag, 18},
|
||||||
{"goPanicSliceAcapU", funcTag, 14},
|
{"goPanicSliceAcap", funcTag, 16},
|
||||||
{"goPanicSliceB", funcTag, 12},
|
{"goPanicSliceAcapU", funcTag, 18},
|
||||||
{"goPanicSliceBU", funcTag, 14},
|
{"goPanicSliceB", funcTag, 16},
|
||||||
{"goPanicSlice3Alen", funcTag, 12},
|
{"goPanicSliceBU", funcTag, 18},
|
||||||
{"goPanicSlice3AlenU", funcTag, 14},
|
{"goPanicSlice3Alen", funcTag, 16},
|
||||||
{"goPanicSlice3Acap", funcTag, 12},
|
{"goPanicSlice3AlenU", funcTag, 18},
|
||||||
{"goPanicSlice3AcapU", funcTag, 14},
|
{"goPanicSlice3Acap", funcTag, 16},
|
||||||
{"goPanicSlice3B", funcTag, 12},
|
{"goPanicSlice3AcapU", funcTag, 18},
|
||||||
{"goPanicSlice3BU", funcTag, 14},
|
{"goPanicSlice3B", funcTag, 16},
|
||||||
{"goPanicSlice3C", funcTag, 12},
|
{"goPanicSlice3BU", funcTag, 18},
|
||||||
{"goPanicSlice3CU", funcTag, 14},
|
{"goPanicSlice3C", funcTag, 16},
|
||||||
{"printbool", funcTag, 16},
|
{"goPanicSlice3CU", funcTag, 18},
|
||||||
{"printfloat", funcTag, 18},
|
{"printbool", funcTag, 19},
|
||||||
{"printint", funcTag, 20},
|
{"printfloat", funcTag, 21},
|
||||||
{"printhex", funcTag, 22},
|
{"printint", funcTag, 23},
|
||||||
{"printuint", funcTag, 22},
|
{"printhex", funcTag, 25},
|
||||||
{"printcomplex", funcTag, 24},
|
{"printuint", funcTag, 25},
|
||||||
{"printstring", funcTag, 26},
|
{"printcomplex", funcTag, 27},
|
||||||
{"printpointer", funcTag, 27},
|
{"printstring", funcTag, 29},
|
||||||
{"printiface", funcTag, 27},
|
{"printpointer", funcTag, 30},
|
||||||
{"printeface", funcTag, 27},
|
{"printiface", funcTag, 30},
|
||||||
{"printslice", funcTag, 27},
|
{"printeface", funcTag, 30},
|
||||||
{"printnl", funcTag, 5},
|
{"printslice", funcTag, 30},
|
||||||
{"printsp", funcTag, 5},
|
{"printnl", funcTag, 9},
|
||||||
{"printlock", funcTag, 5},
|
{"printsp", funcTag, 9},
|
||||||
{"printunlock", funcTag, 5},
|
{"printlock", funcTag, 9},
|
||||||
{"concatstring2", funcTag, 30},
|
{"printunlock", funcTag, 9},
|
||||||
{"concatstring3", funcTag, 31},
|
{"concatstring2", funcTag, 33},
|
||||||
{"concatstring4", funcTag, 32},
|
{"concatstring3", funcTag, 34},
|
||||||
{"concatstring5", funcTag, 33},
|
{"concatstring4", funcTag, 35},
|
||||||
{"concatstrings", funcTag, 35},
|
{"concatstring5", funcTag, 36},
|
||||||
{"cmpstring", funcTag, 36},
|
{"concatstrings", funcTag, 38},
|
||||||
{"intstring", funcTag, 39},
|
{"cmpstring", funcTag, 39},
|
||||||
{"slicebytetostring", funcTag, 40},
|
{"intstring", funcTag, 42},
|
||||||
{"slicebytetostringtmp", funcTag, 41},
|
{"slicebytetostring", funcTag, 43},
|
||||||
{"slicerunetostring", funcTag, 44},
|
{"slicebytetostringtmp", funcTag, 44},
|
||||||
{"stringtoslicebyte", funcTag, 46},
|
{"slicerunetostring", funcTag, 47},
|
||||||
{"stringtoslicerune", funcTag, 49},
|
{"stringtoslicebyte", funcTag, 49},
|
||||||
{"slicecopy", funcTag, 51},
|
{"stringtoslicerune", funcTag, 52},
|
||||||
{"slicestringcopy", funcTag, 52},
|
{"slicecopy", funcTag, 53},
|
||||||
{"decoderune", funcTag, 53},
|
{"slicestringcopy", funcTag, 54},
|
||||||
{"countrunes", funcTag, 54},
|
{"decoderune", funcTag, 55},
|
||||||
{"convI2I", funcTag, 55},
|
{"countrunes", funcTag, 56},
|
||||||
{"convT16", funcTag, 57},
|
{"convI2I", funcTag, 57},
|
||||||
{"convT32", funcTag, 57},
|
{"convT16", funcTag, 58},
|
||||||
{"convT64", funcTag, 57},
|
{"convT32", funcTag, 58},
|
||||||
{"convTstring", funcTag, 57},
|
{"convT64", funcTag, 58},
|
||||||
{"convTslice", funcTag, 57},
|
{"convTstring", funcTag, 58},
|
||||||
{"convT2E", funcTag, 58},
|
{"convTslice", funcTag, 58},
|
||||||
{"convT2Enoptr", funcTag, 58},
|
{"convT2E", funcTag, 59},
|
||||||
{"convT2I", funcTag, 58},
|
{"convT2Enoptr", funcTag, 59},
|
||||||
{"convT2Inoptr", funcTag, 58},
|
{"convT2I", funcTag, 59},
|
||||||
{"assertE2I", funcTag, 55},
|
{"convT2Inoptr", funcTag, 59},
|
||||||
{"assertE2I2", funcTag, 59},
|
{"assertE2I", funcTag, 57},
|
||||||
{"assertI2I", funcTag, 55},
|
{"assertE2I2", funcTag, 60},
|
||||||
{"assertI2I2", funcTag, 59},
|
{"assertI2I", funcTag, 57},
|
||||||
{"panicdottypeE", funcTag, 60},
|
{"assertI2I2", funcTag, 60},
|
||||||
{"panicdottypeI", funcTag, 60},
|
{"panicdottypeE", funcTag, 61},
|
||||||
{"panicnildottype", funcTag, 61},
|
{"panicdottypeI", funcTag, 61},
|
||||||
{"ifaceeq", funcTag, 63},
|
{"panicnildottype", funcTag, 62},
|
||||||
{"efaceeq", funcTag, 63},
|
{"ifaceeq", funcTag, 64},
|
||||||
{"fastrand", funcTag, 65},
|
{"efaceeq", funcTag, 64},
|
||||||
{"makemap64", funcTag, 67},
|
{"fastrand", funcTag, 66},
|
||||||
{"makemap", funcTag, 68},
|
{"makemap64", funcTag, 68},
|
||||||
{"makemap_small", funcTag, 69},
|
{"makemap", funcTag, 69},
|
||||||
{"mapaccess1", funcTag, 70},
|
{"makemap_small", funcTag, 70},
|
||||||
{"mapaccess1_fast32", funcTag, 71},
|
{"mapaccess1", funcTag, 71},
|
||||||
{"mapaccess1_fast64", funcTag, 71},
|
{"mapaccess1_fast32", funcTag, 72},
|
||||||
{"mapaccess1_faststr", funcTag, 71},
|
{"mapaccess1_fast64", funcTag, 72},
|
||||||
{"mapaccess1_fat", funcTag, 72},
|
{"mapaccess1_faststr", funcTag, 72},
|
||||||
{"mapaccess2", funcTag, 73},
|
{"mapaccess1_fat", funcTag, 73},
|
||||||
{"mapaccess2_fast32", funcTag, 74},
|
{"mapaccess2", funcTag, 74},
|
||||||
{"mapaccess2_fast64", funcTag, 74},
|
{"mapaccess2_fast32", funcTag, 75},
|
||||||
{"mapaccess2_faststr", funcTag, 74},
|
{"mapaccess2_fast64", funcTag, 75},
|
||||||
{"mapaccess2_fat", funcTag, 75},
|
{"mapaccess2_faststr", funcTag, 75},
|
||||||
{"mapassign", funcTag, 70},
|
{"mapaccess2_fat", funcTag, 76},
|
||||||
{"mapassign_fast32", funcTag, 71},
|
{"mapassign", funcTag, 71},
|
||||||
{"mapassign_fast32ptr", funcTag, 71},
|
{"mapassign_fast32", funcTag, 72},
|
||||||
{"mapassign_fast64", funcTag, 71},
|
{"mapassign_fast32ptr", funcTag, 72},
|
||||||
{"mapassign_fast64ptr", funcTag, 71},
|
{"mapassign_fast64", funcTag, 72},
|
||||||
{"mapassign_faststr", funcTag, 71},
|
{"mapassign_fast64ptr", funcTag, 72},
|
||||||
{"mapiterinit", funcTag, 76},
|
{"mapassign_faststr", funcTag, 72},
|
||||||
{"mapdelete", funcTag, 76},
|
{"mapiterinit", funcTag, 77},
|
||||||
{"mapdelete_fast32", funcTag, 77},
|
{"mapdelete", funcTag, 77},
|
||||||
{"mapdelete_fast64", funcTag, 77},
|
{"mapdelete_fast32", funcTag, 78},
|
||||||
{"mapdelete_faststr", funcTag, 77},
|
{"mapdelete_fast64", funcTag, 78},
|
||||||
{"mapiternext", funcTag, 78},
|
{"mapdelete_faststr", funcTag, 78},
|
||||||
{"mapclear", funcTag, 79},
|
{"mapiternext", funcTag, 79},
|
||||||
{"makechan64", funcTag, 81},
|
{"mapclear", funcTag, 80},
|
||||||
{"makechan", funcTag, 82},
|
{"makechan64", funcTag, 82},
|
||||||
{"chanrecv1", funcTag, 84},
|
{"makechan", funcTag, 83},
|
||||||
{"chanrecv2", funcTag, 85},
|
{"chanrecv1", funcTag, 85},
|
||||||
{"chansend1", funcTag, 87},
|
{"chanrecv2", funcTag, 86},
|
||||||
{"closechan", funcTag, 27},
|
{"chansend1", funcTag, 88},
|
||||||
{"writeBarrier", varTag, 89},
|
{"closechan", funcTag, 30},
|
||||||
{"typedmemmove", funcTag, 90},
|
{"writeBarrier", varTag, 90},
|
||||||
{"typedmemclr", funcTag, 91},
|
{"typedmemmove", funcTag, 91},
|
||||||
{"typedslicecopy", funcTag, 92},
|
{"typedmemclr", funcTag, 92},
|
||||||
{"selectnbsend", funcTag, 93},
|
{"typedslicecopy", funcTag, 93},
|
||||||
{"selectnbrecv", funcTag, 94},
|
{"selectnbsend", funcTag, 94},
|
||||||
{"selectnbrecv2", funcTag, 96},
|
{"selectnbrecv", funcTag, 95},
|
||||||
{"selectsetpc", funcTag, 61},
|
{"selectnbrecv2", funcTag, 97},
|
||||||
{"selectgo", funcTag, 97},
|
{"selectsetpc", funcTag, 62},
|
||||||
{"block", funcTag, 5},
|
{"selectgo", funcTag, 98},
|
||||||
{"makeslice", funcTag, 98},
|
{"block", funcTag, 9},
|
||||||
{"makeslice64", funcTag, 99},
|
{"makeslice", funcTag, 99},
|
||||||
{"growslice", funcTag, 101},
|
{"makeslice64", funcTag, 100},
|
||||||
{"memmove", funcTag, 102},
|
{"makeslicecopy", funcTag, 101},
|
||||||
{"memclrNoHeapPointers", funcTag, 103},
|
{"growslice", funcTag, 103},
|
||||||
{"memclrHasPointers", funcTag, 103},
|
{"memmove", funcTag, 104},
|
||||||
{"memequal", funcTag, 104},
|
{"memclrNoHeapPointers", funcTag, 105},
|
||||||
{"memequal0", funcTag, 105},
|
{"memclrHasPointers", funcTag, 105},
|
||||||
{"memequal8", funcTag, 105},
|
{"memequal", funcTag, 106},
|
||||||
{"memequal16", funcTag, 105},
|
{"memequal0", funcTag, 107},
|
||||||
{"memequal32", funcTag, 105},
|
{"memequal8", funcTag, 107},
|
||||||
{"memequal64", funcTag, 105},
|
{"memequal16", funcTag, 107},
|
||||||
{"memequal128", funcTag, 105},
|
{"memequal32", funcTag, 107},
|
||||||
{"f32equal", funcTag, 106},
|
{"memequal64", funcTag, 107},
|
||||||
{"f64equal", funcTag, 106},
|
{"memequal128", funcTag, 107},
|
||||||
{"c64equal", funcTag, 106},
|
{"f32equal", funcTag, 108},
|
||||||
{"c128equal", funcTag, 106},
|
{"f64equal", funcTag, 108},
|
||||||
{"strequal", funcTag, 106},
|
{"c64equal", funcTag, 108},
|
||||||
{"interequal", funcTag, 106},
|
{"c128equal", funcTag, 108},
|
||||||
{"nilinterequal", funcTag, 106},
|
{"strequal", funcTag, 108},
|
||||||
{"memhash", funcTag, 107},
|
{"interequal", funcTag, 108},
|
||||||
{"memhash0", funcTag, 108},
|
{"nilinterequal", funcTag, 108},
|
||||||
{"memhash8", funcTag, 108},
|
{"memhash", funcTag, 109},
|
||||||
{"memhash16", funcTag, 108},
|
{"memhash0", funcTag, 110},
|
||||||
{"memhash32", funcTag, 108},
|
{"memhash8", funcTag, 110},
|
||||||
{"memhash64", funcTag, 108},
|
{"memhash16", funcTag, 110},
|
||||||
{"memhash128", funcTag, 108},
|
{"memhash32", funcTag, 110},
|
||||||
{"f32hash", funcTag, 108},
|
{"memhash64", funcTag, 110},
|
||||||
{"f64hash", funcTag, 108},
|
{"memhash128", funcTag, 110},
|
||||||
{"c64hash", funcTag, 108},
|
{"f32hash", funcTag, 110},
|
||||||
{"c128hash", funcTag, 108},
|
{"f64hash", funcTag, 110},
|
||||||
{"strhash", funcTag, 108},
|
{"c64hash", funcTag, 110},
|
||||||
{"interhash", funcTag, 108},
|
{"c128hash", funcTag, 110},
|
||||||
{"nilinterhash", funcTag, 108},
|
{"strhash", funcTag, 110},
|
||||||
{"int64div", funcTag, 109},
|
{"interhash", funcTag, 110},
|
||||||
{"uint64div", funcTag, 110},
|
{"nilinterhash", funcTag, 110},
|
||||||
{"int64mod", funcTag, 109},
|
{"int64div", funcTag, 111},
|
||||||
{"uint64mod", funcTag, 110},
|
{"uint64div", funcTag, 112},
|
||||||
{"float64toint64", funcTag, 111},
|
{"int64mod", funcTag, 111},
|
||||||
{"float64touint64", funcTag, 112},
|
{"uint64mod", funcTag, 112},
|
||||||
{"float64touint32", funcTag, 113},
|
{"float64toint64", funcTag, 113},
|
||||||
{"int64tofloat64", funcTag, 114},
|
{"float64touint64", funcTag, 114},
|
||||||
{"uint64tofloat64", funcTag, 115},
|
{"float64touint32", funcTag, 115},
|
||||||
{"uint32tofloat64", funcTag, 116},
|
{"int64tofloat64", funcTag, 116},
|
||||||
{"complex128div", funcTag, 117},
|
{"uint64tofloat64", funcTag, 117},
|
||||||
{"racefuncenter", funcTag, 118},
|
{"uint32tofloat64", funcTag, 118},
|
||||||
{"racefuncenterfp", funcTag, 5},
|
{"complex128div", funcTag, 119},
|
||||||
{"racefuncexit", funcTag, 5},
|
{"racefuncenter", funcTag, 120},
|
||||||
{"raceread", funcTag, 118},
|
{"racefuncenterfp", funcTag, 9},
|
||||||
{"racewrite", funcTag, 118},
|
{"racefuncexit", funcTag, 9},
|
||||||
{"racereadrange", funcTag, 119},
|
{"raceread", funcTag, 120},
|
||||||
{"racewriterange", funcTag, 119},
|
{"racewrite", funcTag, 120},
|
||||||
{"msanread", funcTag, 119},
|
{"racereadrange", funcTag, 121},
|
||||||
{"msanwrite", funcTag, 119},
|
{"racewriterange", funcTag, 121},
|
||||||
{"checkptrAlignment", funcTag, 120},
|
{"msanread", funcTag, 121},
|
||||||
{"checkptrArithmetic", funcTag, 122},
|
{"msanwrite", funcTag, 121},
|
||||||
{"libfuzzerTraceCmp1", funcTag, 124},
|
{"checkptrAlignment", funcTag, 122},
|
||||||
{"libfuzzerTraceCmp2", funcTag, 126},
|
{"checkptrArithmetic", funcTag, 124},
|
||||||
{"libfuzzerTraceCmp4", funcTag, 127},
|
{"libfuzzerTraceCmp1", funcTag, 126},
|
||||||
{"libfuzzerTraceCmp8", funcTag, 128},
|
{"libfuzzerTraceCmp2", funcTag, 128},
|
||||||
{"libfuzzerTraceConstCmp1", funcTag, 124},
|
{"libfuzzerTraceCmp4", funcTag, 129},
|
||||||
{"libfuzzerTraceConstCmp2", funcTag, 126},
|
{"libfuzzerTraceCmp8", funcTag, 130},
|
||||||
{"libfuzzerTraceConstCmp4", funcTag, 127},
|
{"libfuzzerTraceConstCmp1", funcTag, 126},
|
||||||
{"libfuzzerTraceConstCmp8", funcTag, 128},
|
{"libfuzzerTraceConstCmp2", funcTag, 128},
|
||||||
{"x86HasPOPCNT", varTag, 15},
|
{"libfuzzerTraceConstCmp4", funcTag, 129},
|
||||||
{"x86HasSSE41", varTag, 15},
|
{"libfuzzerTraceConstCmp8", funcTag, 130},
|
||||||
{"x86HasFMA", varTag, 15},
|
{"x86HasPOPCNT", varTag, 6},
|
||||||
{"armHasVFPv4", varTag, 15},
|
{"x86HasSSE41", varTag, 6},
|
||||||
{"arm64HasATOMICS", varTag, 15},
|
{"x86HasFMA", varTag, 6},
|
||||||
|
{"armHasVFPv4", varTag, 6},
|
||||||
|
{"arm64HasATOMICS", varTag, 6},
|
||||||
}
|
}
|
||||||
|
|
||||||
func runtimeTypes() []*types.Type {
|
func runtimeTypes() []*types.Type {
|
||||||
var typs [129]*types.Type
|
var typs [131]*types.Type
|
||||||
typs[0] = types.Bytetype
|
typs[0] = types.Bytetype
|
||||||
typs[1] = types.NewPtr(typs[0])
|
typs[1] = types.NewPtr(typs[0])
|
||||||
typs[2] = types.Types[TANY]
|
typs[2] = types.Types[TANY]
|
||||||
typs[3] = types.NewPtr(typs[2])
|
typs[3] = types.NewPtr(typs[2])
|
||||||
typs[4] = functype(nil, []*Node{anonfield(typs[1])}, []*Node{anonfield(typs[3])})
|
typs[4] = functype(nil, []*Node{anonfield(typs[1])}, []*Node{anonfield(typs[3])})
|
||||||
typs[5] = functype(nil, nil, nil)
|
typs[5] = types.Types[TUINTPTR]
|
||||||
typs[6] = types.Types[TINTER]
|
typs[6] = types.Types[TBOOL]
|
||||||
typs[7] = functype(nil, []*Node{anonfield(typs[6])}, nil)
|
typs[7] = types.Types[TUNSAFEPTR]
|
||||||
typs[8] = types.Types[TINT32]
|
typs[8] = functype(nil, []*Node{anonfield(typs[5]), anonfield(typs[1]), anonfield(typs[6])}, []*Node{anonfield(typs[7])})
|
||||||
typs[9] = types.NewPtr(typs[8])
|
typs[9] = functype(nil, nil, nil)
|
||||||
typs[10] = functype(nil, []*Node{anonfield(typs[9])}, []*Node{anonfield(typs[6])})
|
typs[10] = types.Types[TINTER]
|
||||||
typs[11] = types.Types[TINT]
|
typs[11] = functype(nil, []*Node{anonfield(typs[10])}, nil)
|
||||||
typs[12] = functype(nil, []*Node{anonfield(typs[11]), anonfield(typs[11])}, nil)
|
typs[12] = types.Types[TINT32]
|
||||||
typs[13] = types.Types[TUINT]
|
typs[13] = types.NewPtr(typs[12])
|
||||||
typs[14] = functype(nil, []*Node{anonfield(typs[13]), anonfield(typs[11])}, nil)
|
typs[14] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[10])})
|
||||||
typs[15] = types.Types[TBOOL]
|
typs[15] = types.Types[TINT]
|
||||||
typs[16] = functype(nil, []*Node{anonfield(typs[15])}, nil)
|
typs[16] = functype(nil, []*Node{anonfield(typs[15]), anonfield(typs[15])}, nil)
|
||||||
typs[17] = types.Types[TFLOAT64]
|
typs[17] = types.Types[TUINT]
|
||||||
typs[18] = functype(nil, []*Node{anonfield(typs[17])}, nil)
|
typs[18] = functype(nil, []*Node{anonfield(typs[17]), anonfield(typs[15])}, nil)
|
||||||
typs[19] = types.Types[TINT64]
|
typs[19] = functype(nil, []*Node{anonfield(typs[6])}, nil)
|
||||||
typs[20] = functype(nil, []*Node{anonfield(typs[19])}, nil)
|
typs[20] = types.Types[TFLOAT64]
|
||||||
typs[21] = types.Types[TUINT64]
|
typs[21] = functype(nil, []*Node{anonfield(typs[20])}, nil)
|
||||||
typs[22] = functype(nil, []*Node{anonfield(typs[21])}, nil)
|
typs[22] = types.Types[TINT64]
|
||||||
typs[23] = types.Types[TCOMPLEX128]
|
typs[23] = functype(nil, []*Node{anonfield(typs[22])}, nil)
|
||||||
typs[24] = functype(nil, []*Node{anonfield(typs[23])}, nil)
|
typs[24] = types.Types[TUINT64]
|
||||||
typs[25] = types.Types[TSTRING]
|
typs[25] = functype(nil, []*Node{anonfield(typs[24])}, nil)
|
||||||
typs[26] = functype(nil, []*Node{anonfield(typs[25])}, nil)
|
typs[26] = types.Types[TCOMPLEX128]
|
||||||
typs[27] = functype(nil, []*Node{anonfield(typs[2])}, nil)
|
typs[27] = functype(nil, []*Node{anonfield(typs[26])}, nil)
|
||||||
typs[28] = types.NewArray(typs[0], 32)
|
typs[28] = types.Types[TSTRING]
|
||||||
typs[29] = types.NewPtr(typs[28])
|
typs[29] = functype(nil, []*Node{anonfield(typs[28])}, nil)
|
||||||
typs[30] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[25]), anonfield(typs[25])}, []*Node{anonfield(typs[25])})
|
typs[30] = functype(nil, []*Node{anonfield(typs[2])}, nil)
|
||||||
typs[31] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[25]), anonfield(typs[25]), anonfield(typs[25])}, []*Node{anonfield(typs[25])})
|
typs[31] = types.NewArray(typs[0], 32)
|
||||||
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[32] = types.NewPtr(typs[31])
|
||||||
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[33] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
|
||||||
typs[34] = types.NewSlice(typs[25])
|
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[29]), anonfield(typs[34])}, []*Node{anonfield(typs[25])})
|
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[25]), anonfield(typs[25])}, []*Node{anonfield(typs[11])})
|
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.NewArray(typs[0], 4)
|
typs[37] = types.NewSlice(typs[28])
|
||||||
typs[38] = types.NewPtr(typs[37])
|
typs[38] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[37])}, []*Node{anonfield(typs[28])})
|
||||||
typs[39] = functype(nil, []*Node{anonfield(typs[38]), anonfield(typs[19])}, []*Node{anonfield(typs[25])})
|
typs[39] = functype(nil, []*Node{anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[15])})
|
||||||
typs[40] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[1]), anonfield(typs[11])}, []*Node{anonfield(typs[25])})
|
typs[40] = types.NewArray(typs[0], 4)
|
||||||
typs[41] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[11])}, []*Node{anonfield(typs[25])})
|
typs[41] = types.NewPtr(typs[40])
|
||||||
typs[42] = types.Runetype
|
typs[42] = functype(nil, []*Node{anonfield(typs[41]), anonfield(typs[22])}, []*Node{anonfield(typs[28])})
|
||||||
typs[43] = types.NewSlice(typs[42])
|
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[29]), anonfield(typs[43])}, []*Node{anonfield(typs[25])})
|
typs[44] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[28])})
|
||||||
typs[45] = types.NewSlice(typs[0])
|
typs[45] = types.Runetype
|
||||||
typs[46] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[25])}, []*Node{anonfield(typs[45])})
|
typs[46] = types.NewSlice(typs[45])
|
||||||
typs[47] = types.NewArray(typs[42], 32)
|
typs[47] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[46])}, []*Node{anonfield(typs[28])})
|
||||||
typs[48] = types.NewPtr(typs[47])
|
typs[48] = types.NewSlice(typs[0])
|
||||||
typs[49] = functype(nil, []*Node{anonfield(typs[48]), anonfield(typs[25])}, []*Node{anonfield(typs[43])})
|
typs[49] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28])}, []*Node{anonfield(typs[48])})
|
||||||
typs[50] = types.Types[TUINTPTR]
|
typs[50] = types.NewArray(typs[45], 32)
|
||||||
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[51] = types.NewPtr(typs[50])
|
||||||
typs[52] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[11]), anonfield(typs[25])}, []*Node{anonfield(typs[11])})
|
typs[52] = functype(nil, []*Node{anonfield(typs[51]), anonfield(typs[28])}, []*Node{anonfield(typs[46])})
|
||||||
typs[53] = functype(nil, []*Node{anonfield(typs[25]), anonfield(typs[11])}, []*Node{anonfield(typs[42]), anonfield(typs[11])})
|
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[25])}, []*Node{anonfield(typs[11])})
|
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[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2])})
|
typs[55] = functype(nil, []*Node{anonfield(typs[28]), anonfield(typs[15])}, []*Node{anonfield(typs[45]), anonfield(typs[15])})
|
||||||
typs[56] = types.Types[TUNSAFEPTR]
|
typs[56] = functype(nil, []*Node{anonfield(typs[28])}, []*Node{anonfield(typs[15])})
|
||||||
typs[57] = functype(nil, []*Node{anonfield(typs[2])}, []*Node{anonfield(typs[56])})
|
typs[57] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2])})
|
||||||
typs[58] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, []*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[2])}, []*Node{anonfield(typs[2]), anonfield(typs[15])})
|
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[1]), anonfield(typs[1])}, nil)
|
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])}, nil)
|
typs[61] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil)
|
||||||
typs[62] = types.NewPtr(typs[50])
|
typs[62] = functype(nil, []*Node{anonfield(typs[1])}, nil)
|
||||||
typs[63] = functype(nil, []*Node{anonfield(typs[62]), anonfield(typs[56]), anonfield(typs[56])}, []*Node{anonfield(typs[15])})
|
typs[63] = types.NewPtr(typs[5])
|
||||||
typs[64] = types.Types[TUINT32]
|
typs[64] = functype(nil, []*Node{anonfield(typs[63]), anonfield(typs[7]), anonfield(typs[7])}, []*Node{anonfield(typs[6])})
|
||||||
typs[65] = functype(nil, nil, []*Node{anonfield(typs[64])})
|
typs[65] = types.Types[TUINT32]
|
||||||
typs[66] = types.NewMap(typs[2], typs[2])
|
typs[66] = functype(nil, nil, []*Node{anonfield(typs[65])})
|
||||||
typs[67] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[19]), anonfield(typs[3])}, []*Node{anonfield(typs[66])})
|
typs[67] = types.NewMap(typs[2], typs[2])
|
||||||
typs[68] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[11]), anonfield(typs[3])}, []*Node{anonfield(typs[66])})
|
typs[68] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[3])}, []*Node{anonfield(typs[67])})
|
||||||
typs[69] = functype(nil, nil, []*Node{anonfield(typs[66])})
|
typs[69] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[3])}, []*Node{anonfield(typs[67])})
|
||||||
typs[70] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3])}, []*Node{anonfield(typs[3])})
|
typs[70] = functype(nil, nil, []*Node{anonfield(typs[67])})
|
||||||
typs[71] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[2])}, []*Node{anonfield(typs[3])})
|
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[66]), anonfield(typs[3]), anonfield(typs[1])}, []*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[66]), anonfield(typs[3])}, []*Node{anonfield(typs[3]), anonfield(typs[15])})
|
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[66]), anonfield(typs[2])}, []*Node{anonfield(typs[3]), anonfield(typs[15])})
|
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[66]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3]), anonfield(typs[15])})
|
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[66]), anonfield(typs[3])}, nil)
|
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[66]), anonfield(typs[2])}, nil)
|
typs[77] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, nil)
|
||||||
typs[78] = functype(nil, []*Node{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[1]), anonfield(typs[66])}, nil)
|
typs[79] = functype(nil, []*Node{anonfield(typs[3])}, nil)
|
||||||
typs[80] = types.NewChan(typs[2], types.Cboth)
|
typs[80] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67])}, nil)
|
||||||
typs[81] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[19])}, []*Node{anonfield(typs[80])})
|
typs[81] = types.NewChan(typs[2], types.Cboth)
|
||||||
typs[82] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[11])}, []*Node{anonfield(typs[80])})
|
typs[82] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22])}, []*Node{anonfield(typs[81])})
|
||||||
typs[83] = types.NewChan(typs[2], types.Crecv)
|
typs[83] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[81])})
|
||||||
typs[84] = functype(nil, []*Node{anonfield(typs[83]), anonfield(typs[3])}, nil)
|
typs[84] = types.NewChan(typs[2], types.Crecv)
|
||||||
typs[85] = functype(nil, []*Node{anonfield(typs[83]), anonfield(typs[3])}, []*Node{anonfield(typs[15])})
|
typs[85] = functype(nil, []*Node{anonfield(typs[84]), anonfield(typs[3])}, nil)
|
||||||
typs[86] = types.NewChan(typs[2], types.Csend)
|
typs[86] = functype(nil, []*Node{anonfield(typs[84]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
|
||||||
typs[87] = functype(nil, []*Node{anonfield(typs[86]), anonfield(typs[3])}, nil)
|
typs[87] = types.NewChan(typs[2], types.Csend)
|
||||||
typs[88] = types.NewArray(typs[0], 3)
|
typs[88] = functype(nil, []*Node{anonfield(typs[87]), anonfield(typs[3])}, nil)
|
||||||
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[89] = types.NewArray(typs[0], 3)
|
||||||
typs[90] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil)
|
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])}, nil)
|
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]), anonfield(typs[11]), anonfield(typs[3]), anonfield(typs[11])}, []*Node{anonfield(typs[11])})
|
typs[92] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, nil)
|
||||||
typs[93] = functype(nil, []*Node{anonfield(typs[86]), anonfield(typs[3])}, []*Node{anonfield(typs[15])})
|
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[3]), anonfield(typs[83])}, []*Node{anonfield(typs[15])})
|
typs[94] = functype(nil, []*Node{anonfield(typs[87]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
|
||||||
typs[95] = types.NewPtr(typs[15])
|
typs[95] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[84])}, []*Node{anonfield(typs[6])})
|
||||||
typs[96] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[95]), anonfield(typs[83])}, []*Node{anonfield(typs[15])})
|
typs[96] = types.NewPtr(typs[6])
|
||||||
typs[97] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[11])}, []*Node{anonfield(typs[11]), anonfield(typs[15])})
|
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[11]), anonfield(typs[11])}, []*Node{anonfield(typs[56])})
|
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[19]), anonfield(typs[19])}, []*Node{anonfield(typs[56])})
|
typs[99] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[7])})
|
||||||
typs[100] = types.NewSlice(typs[2])
|
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[100]), anonfield(typs[11])}, []*Node{anonfield(typs[100])})
|
typs[101] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15]), anonfield(typs[7])}, []*Node{anonfield(typs[7])})
|
||||||
typs[102] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[50])}, nil)
|
typs[102] = types.NewSlice(typs[2])
|
||||||
typs[103] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[50])}, nil)
|
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[50])}, []*Node{anonfield(typs[15])})
|
typs[104] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, nil)
|
||||||
typs[105] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[15])})
|
typs[105] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5])}, nil)
|
||||||
typs[106] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[56])}, []*Node{anonfield(typs[15])})
|
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[56]), anonfield(typs[50]), anonfield(typs[50])}, []*Node{anonfield(typs[50])})
|
typs[107] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
|
||||||
typs[108] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[50])}, []*Node{anonfield(typs[50])})
|
typs[108] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[7])}, []*Node{anonfield(typs[6])})
|
||||||
typs[109] = functype(nil, []*Node{anonfield(typs[19]), anonfield(typs[19])}, []*Node{anonfield(typs[19])})
|
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[21]), anonfield(typs[21])}, []*Node{anonfield(typs[21])})
|
typs[110] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5])}, []*Node{anonfield(typs[5])})
|
||||||
typs[111] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[19])})
|
typs[111] = functype(nil, []*Node{anonfield(typs[22]), anonfield(typs[22])}, []*Node{anonfield(typs[22])})
|
||||||
typs[112] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[21])})
|
typs[112] = functype(nil, []*Node{anonfield(typs[24]), anonfield(typs[24])}, []*Node{anonfield(typs[24])})
|
||||||
typs[113] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[64])})
|
typs[113] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[22])})
|
||||||
typs[114] = functype(nil, []*Node{anonfield(typs[19])}, []*Node{anonfield(typs[17])})
|
typs[114] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[24])})
|
||||||
typs[115] = functype(nil, []*Node{anonfield(typs[21])}, []*Node{anonfield(typs[17])})
|
typs[115] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[65])})
|
||||||
typs[116] = functype(nil, []*Node{anonfield(typs[64])}, []*Node{anonfield(typs[17])})
|
typs[116] = functype(nil, []*Node{anonfield(typs[22])}, []*Node{anonfield(typs[20])})
|
||||||
typs[117] = functype(nil, []*Node{anonfield(typs[23]), anonfield(typs[23])}, []*Node{anonfield(typs[23])})
|
typs[117] = functype(nil, []*Node{anonfield(typs[24])}, []*Node{anonfield(typs[20])})
|
||||||
typs[118] = functype(nil, []*Node{anonfield(typs[50])}, nil)
|
typs[118] = functype(nil, []*Node{anonfield(typs[65])}, []*Node{anonfield(typs[20])})
|
||||||
typs[119] = functype(nil, []*Node{anonfield(typs[50]), anonfield(typs[50])}, nil)
|
typs[119] = functype(nil, []*Node{anonfield(typs[26]), anonfield(typs[26])}, []*Node{anonfield(typs[26])})
|
||||||
typs[120] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[1]), anonfield(typs[50])}, nil)
|
typs[120] = functype(nil, []*Node{anonfield(typs[5])}, nil)
|
||||||
typs[121] = types.NewSlice(typs[56])
|
typs[121] = functype(nil, []*Node{anonfield(typs[5]), anonfield(typs[5])}, nil)
|
||||||
typs[122] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[121])}, nil)
|
typs[122] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[1]), anonfield(typs[5])}, nil)
|
||||||
typs[123] = types.Types[TUINT8]
|
typs[123] = types.NewSlice(typs[7])
|
||||||
typs[124] = functype(nil, []*Node{anonfield(typs[123]), anonfield(typs[123])}, nil)
|
typs[124] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[123])}, nil)
|
||||||
typs[125] = types.Types[TUINT16]
|
typs[125] = types.Types[TUINT8]
|
||||||
typs[126] = functype(nil, []*Node{anonfield(typs[125]), anonfield(typs[125])}, nil)
|
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[127] = types.Types[TUINT16]
|
||||||
typs[128] = functype(nil, []*Node{anonfield(typs[21]), anonfield(typs[21])}, nil)
|
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[:]
|
return typs[:]
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ package runtime
|
||||||
import "unsafe"
|
import "unsafe"
|
||||||
|
|
||||||
func newobject(typ *byte) *any
|
func newobject(typ *byte) *any
|
||||||
|
func mallocgc(size uintptr, typ *byte, needszero bool) unsafe.Pointer
|
||||||
func panicdivide()
|
func panicdivide()
|
||||||
func panicshift()
|
func panicshift()
|
||||||
func panicmakeslicelen()
|
func panicmakeslicelen()
|
||||||
|
@ -174,6 +175,7 @@ func block()
|
||||||
|
|
||||||
func makeslice(typ *byte, len int, cap int) unsafe.Pointer
|
func makeslice(typ *byte, len int, cap int) unsafe.Pointer
|
||||||
func makeslice64(typ *byte, len int64, cap int64) 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 growslice(typ *byte, old []any, cap int) (ary []any)
|
||||||
func memmove(to *any, frm *any, length uintptr)
|
func memmove(to *any, frm *any, length uintptr)
|
||||||
func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)
|
func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)
|
||||||
|
|
|
@ -141,13 +141,13 @@ func isSelfAssign(dst, src *Node) bool {
|
||||||
return samesafeexpr(dst.Left, src.Left)
|
return samesafeexpr(dst.Left, src.Left)
|
||||||
}
|
}
|
||||||
|
|
||||||
// mayAffectMemory reports whether n evaluation may affect program memory state.
|
// mayAffectMemory reports whether evaluation of n may affect the program's
|
||||||
// If expression can't affect it, then it can be safely ignored by the escape analysis.
|
// 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 {
|
func mayAffectMemory(n *Node) bool {
|
||||||
// We may want to use "memory safe" black list instead of general
|
// We may want to use a list of "memory safe" ops instead of generally
|
||||||
// "side-effect free", which can include all calls and other ops
|
// "side-effect free", which would include all calls and other ops that can
|
||||||
// that can affect allocate or change global state.
|
// allocate or change global state. For now, it's safer to start with the latter.
|
||||||
// It's safer to start from a whitelist for now.
|
|
||||||
//
|
//
|
||||||
// We're ignoring things like division by zero, index out of range,
|
// We're ignoring things like division by zero, index out of range,
|
||||||
// and nil pointer dereference here.
|
// and nil pointer dereference here.
|
||||||
|
|
|
@ -1165,92 +1165,93 @@ func (n *Node) stmtfmt(s fmt.State, mode fmtMode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var opprec = []int{
|
var opprec = []int{
|
||||||
OALIGNOF: 8,
|
OALIGNOF: 8,
|
||||||
OAPPEND: 8,
|
OAPPEND: 8,
|
||||||
OBYTES2STR: 8,
|
OBYTES2STR: 8,
|
||||||
OARRAYLIT: 8,
|
OARRAYLIT: 8,
|
||||||
OSLICELIT: 8,
|
OSLICELIT: 8,
|
||||||
ORUNES2STR: 8,
|
ORUNES2STR: 8,
|
||||||
OCALLFUNC: 8,
|
OCALLFUNC: 8,
|
||||||
OCALLINTER: 8,
|
OCALLINTER: 8,
|
||||||
OCALLMETH: 8,
|
OCALLMETH: 8,
|
||||||
OCALL: 8,
|
OCALL: 8,
|
||||||
OCAP: 8,
|
OCAP: 8,
|
||||||
OCLOSE: 8,
|
OCLOSE: 8,
|
||||||
OCONVIFACE: 8,
|
OCONVIFACE: 8,
|
||||||
OCONVNOP: 8,
|
OCONVNOP: 8,
|
||||||
OCONV: 8,
|
OCONV: 8,
|
||||||
OCOPY: 8,
|
OCOPY: 8,
|
||||||
ODELETE: 8,
|
ODELETE: 8,
|
||||||
OGETG: 8,
|
OGETG: 8,
|
||||||
OLEN: 8,
|
OLEN: 8,
|
||||||
OLITERAL: 8,
|
OLITERAL: 8,
|
||||||
OMAKESLICE: 8,
|
OMAKESLICE: 8,
|
||||||
OMAKE: 8,
|
OMAKESLICECOPY: 8,
|
||||||
OMAPLIT: 8,
|
OMAKE: 8,
|
||||||
ONAME: 8,
|
OMAPLIT: 8,
|
||||||
ONEW: 8,
|
ONAME: 8,
|
||||||
ONONAME: 8,
|
ONEW: 8,
|
||||||
OOFFSETOF: 8,
|
ONONAME: 8,
|
||||||
OPACK: 8,
|
OOFFSETOF: 8,
|
||||||
OPANIC: 8,
|
OPACK: 8,
|
||||||
OPAREN: 8,
|
OPANIC: 8,
|
||||||
OPRINTN: 8,
|
OPAREN: 8,
|
||||||
OPRINT: 8,
|
OPRINTN: 8,
|
||||||
ORUNESTR: 8,
|
OPRINT: 8,
|
||||||
OSIZEOF: 8,
|
ORUNESTR: 8,
|
||||||
OSTR2BYTES: 8,
|
OSIZEOF: 8,
|
||||||
OSTR2RUNES: 8,
|
OSTR2BYTES: 8,
|
||||||
OSTRUCTLIT: 8,
|
OSTR2RUNES: 8,
|
||||||
OTARRAY: 8,
|
OSTRUCTLIT: 8,
|
||||||
OTCHAN: 8,
|
OTARRAY: 8,
|
||||||
OTFUNC: 8,
|
OTCHAN: 8,
|
||||||
OTINTER: 8,
|
OTFUNC: 8,
|
||||||
OTMAP: 8,
|
OTINTER: 8,
|
||||||
OTSTRUCT: 8,
|
OTMAP: 8,
|
||||||
OINDEXMAP: 8,
|
OTSTRUCT: 8,
|
||||||
OINDEX: 8,
|
OINDEXMAP: 8,
|
||||||
OSLICE: 8,
|
OINDEX: 8,
|
||||||
OSLICESTR: 8,
|
OSLICE: 8,
|
||||||
OSLICEARR: 8,
|
OSLICESTR: 8,
|
||||||
OSLICE3: 8,
|
OSLICEARR: 8,
|
||||||
OSLICE3ARR: 8,
|
OSLICE3: 8,
|
||||||
OSLICEHEADER: 8,
|
OSLICE3ARR: 8,
|
||||||
ODOTINTER: 8,
|
OSLICEHEADER: 8,
|
||||||
ODOTMETH: 8,
|
ODOTINTER: 8,
|
||||||
ODOTPTR: 8,
|
ODOTMETH: 8,
|
||||||
ODOTTYPE2: 8,
|
ODOTPTR: 8,
|
||||||
ODOTTYPE: 8,
|
ODOTTYPE2: 8,
|
||||||
ODOT: 8,
|
ODOTTYPE: 8,
|
||||||
OXDOT: 8,
|
ODOT: 8,
|
||||||
OCALLPART: 8,
|
OXDOT: 8,
|
||||||
OPLUS: 7,
|
OCALLPART: 8,
|
||||||
ONOT: 7,
|
OPLUS: 7,
|
||||||
OBITNOT: 7,
|
ONOT: 7,
|
||||||
ONEG: 7,
|
OBITNOT: 7,
|
||||||
OADDR: 7,
|
ONEG: 7,
|
||||||
ODEREF: 7,
|
OADDR: 7,
|
||||||
ORECV: 7,
|
ODEREF: 7,
|
||||||
OMUL: 6,
|
ORECV: 7,
|
||||||
ODIV: 6,
|
OMUL: 6,
|
||||||
OMOD: 6,
|
ODIV: 6,
|
||||||
OLSH: 6,
|
OMOD: 6,
|
||||||
ORSH: 6,
|
OLSH: 6,
|
||||||
OAND: 6,
|
ORSH: 6,
|
||||||
OANDNOT: 6,
|
OAND: 6,
|
||||||
OADD: 5,
|
OANDNOT: 6,
|
||||||
OSUB: 5,
|
OADD: 5,
|
||||||
OOR: 5,
|
OSUB: 5,
|
||||||
OXOR: 5,
|
OOR: 5,
|
||||||
OEQ: 4,
|
OXOR: 5,
|
||||||
OLT: 4,
|
OEQ: 4,
|
||||||
OLE: 4,
|
OLT: 4,
|
||||||
OGE: 4,
|
OLE: 4,
|
||||||
OGT: 4,
|
OGE: 4,
|
||||||
ONE: 4,
|
OGT: 4,
|
||||||
OSEND: 3,
|
ONE: 4,
|
||||||
OANDAND: 2,
|
OSEND: 3,
|
||||||
OOROR: 1,
|
OANDAND: 2,
|
||||||
|
OOROR: 1,
|
||||||
|
|
||||||
// Statements handled by stmtfmt
|
// Statements handled by stmtfmt
|
||||||
OAS: -1,
|
OAS: -1,
|
||||||
|
@ -1572,6 +1573,9 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
|
||||||
}
|
}
|
||||||
mode.Fprintf(s, "make(%v)", n.Type)
|
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:
|
case OPLUS, ONEG, OADDR, OBITNOT, ODEREF, ONOT, ORECV:
|
||||||
// Unary
|
// Unary
|
||||||
mode.Fprintf(s, "%#v", n.Op)
|
mode.Fprintf(s, "%#v", n.Op)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Derived from Inferno utils/6c/txt.c
|
// 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.
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||||
|
|
|
@ -44,7 +44,7 @@ func parseFiles(filenames []string) uint {
|
||||||
|
|
||||||
f, err := os.Open(filename)
|
f, err := os.Open(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.error(syntax.Error{Pos: syntax.MakePos(base, 0, 0), Msg: err.Error()})
|
p.error(syntax.Error{Msg: err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
|
@ -82,89 +82,90 @@ func _() {
|
||||||
_ = x[OMAKECHAN-71]
|
_ = x[OMAKECHAN-71]
|
||||||
_ = x[OMAKEMAP-72]
|
_ = x[OMAKEMAP-72]
|
||||||
_ = x[OMAKESLICE-73]
|
_ = x[OMAKESLICE-73]
|
||||||
_ = x[OMUL-74]
|
_ = x[OMAKESLICECOPY-74]
|
||||||
_ = x[ODIV-75]
|
_ = x[OMUL-75]
|
||||||
_ = x[OMOD-76]
|
_ = x[ODIV-76]
|
||||||
_ = x[OLSH-77]
|
_ = x[OMOD-77]
|
||||||
_ = x[ORSH-78]
|
_ = x[OLSH-78]
|
||||||
_ = x[OAND-79]
|
_ = x[ORSH-79]
|
||||||
_ = x[OANDNOT-80]
|
_ = x[OAND-80]
|
||||||
_ = x[ONEW-81]
|
_ = x[OANDNOT-81]
|
||||||
_ = x[ONEWOBJ-82]
|
_ = x[ONEW-82]
|
||||||
_ = x[ONOT-83]
|
_ = x[ONEWOBJ-83]
|
||||||
_ = x[OBITNOT-84]
|
_ = x[ONOT-84]
|
||||||
_ = x[OPLUS-85]
|
_ = x[OBITNOT-85]
|
||||||
_ = x[ONEG-86]
|
_ = x[OPLUS-86]
|
||||||
_ = x[OOROR-87]
|
_ = x[ONEG-87]
|
||||||
_ = x[OPANIC-88]
|
_ = x[OOROR-88]
|
||||||
_ = x[OPRINT-89]
|
_ = x[OPANIC-89]
|
||||||
_ = x[OPRINTN-90]
|
_ = x[OPRINT-90]
|
||||||
_ = x[OPAREN-91]
|
_ = x[OPRINTN-91]
|
||||||
_ = x[OSEND-92]
|
_ = x[OPAREN-92]
|
||||||
_ = x[OSLICE-93]
|
_ = x[OSEND-93]
|
||||||
_ = x[OSLICEARR-94]
|
_ = x[OSLICE-94]
|
||||||
_ = x[OSLICESTR-95]
|
_ = x[OSLICEARR-95]
|
||||||
_ = x[OSLICE3-96]
|
_ = x[OSLICESTR-96]
|
||||||
_ = x[OSLICE3ARR-97]
|
_ = x[OSLICE3-97]
|
||||||
_ = x[OSLICEHEADER-98]
|
_ = x[OSLICE3ARR-98]
|
||||||
_ = x[ORECOVER-99]
|
_ = x[OSLICEHEADER-99]
|
||||||
_ = x[ORECV-100]
|
_ = x[ORECOVER-100]
|
||||||
_ = x[ORUNESTR-101]
|
_ = x[ORECV-101]
|
||||||
_ = x[OSELRECV-102]
|
_ = x[ORUNESTR-102]
|
||||||
_ = x[OSELRECV2-103]
|
_ = x[OSELRECV-103]
|
||||||
_ = x[OIOTA-104]
|
_ = x[OSELRECV2-104]
|
||||||
_ = x[OREAL-105]
|
_ = x[OIOTA-105]
|
||||||
_ = x[OIMAG-106]
|
_ = x[OREAL-106]
|
||||||
_ = x[OCOMPLEX-107]
|
_ = x[OIMAG-107]
|
||||||
_ = x[OALIGNOF-108]
|
_ = x[OCOMPLEX-108]
|
||||||
_ = x[OOFFSETOF-109]
|
_ = x[OALIGNOF-109]
|
||||||
_ = x[OSIZEOF-110]
|
_ = x[OOFFSETOF-110]
|
||||||
_ = x[OBLOCK-111]
|
_ = x[OSIZEOF-111]
|
||||||
_ = x[OBREAK-112]
|
_ = x[OBLOCK-112]
|
||||||
_ = x[OCASE-113]
|
_ = x[OBREAK-113]
|
||||||
_ = x[OCONTINUE-114]
|
_ = x[OCASE-114]
|
||||||
_ = x[ODEFER-115]
|
_ = x[OCONTINUE-115]
|
||||||
_ = x[OEMPTY-116]
|
_ = x[ODEFER-116]
|
||||||
_ = x[OFALL-117]
|
_ = x[OEMPTY-117]
|
||||||
_ = x[OFOR-118]
|
_ = x[OFALL-118]
|
||||||
_ = x[OFORUNTIL-119]
|
_ = x[OFOR-119]
|
||||||
_ = x[OGOTO-120]
|
_ = x[OFORUNTIL-120]
|
||||||
_ = x[OIF-121]
|
_ = x[OGOTO-121]
|
||||||
_ = x[OLABEL-122]
|
_ = x[OIF-122]
|
||||||
_ = x[OGO-123]
|
_ = x[OLABEL-123]
|
||||||
_ = x[ORANGE-124]
|
_ = x[OGO-124]
|
||||||
_ = x[ORETURN-125]
|
_ = x[ORANGE-125]
|
||||||
_ = x[OSELECT-126]
|
_ = x[ORETURN-126]
|
||||||
_ = x[OSWITCH-127]
|
_ = x[OSELECT-127]
|
||||||
_ = x[OTYPESW-128]
|
_ = x[OSWITCH-128]
|
||||||
_ = x[OTCHAN-129]
|
_ = x[OTYPESW-129]
|
||||||
_ = x[OTMAP-130]
|
_ = x[OTCHAN-130]
|
||||||
_ = x[OTSTRUCT-131]
|
_ = x[OTMAP-131]
|
||||||
_ = x[OTINTER-132]
|
_ = x[OTSTRUCT-132]
|
||||||
_ = x[OTFUNC-133]
|
_ = x[OTINTER-133]
|
||||||
_ = x[OTARRAY-134]
|
_ = x[OTFUNC-134]
|
||||||
_ = x[ODDD-135]
|
_ = x[OTARRAY-135]
|
||||||
_ = x[OINLCALL-136]
|
_ = x[ODDD-136]
|
||||||
_ = x[OEFACE-137]
|
_ = x[OINLCALL-137]
|
||||||
_ = x[OITAB-138]
|
_ = x[OEFACE-138]
|
||||||
_ = x[OIDATA-139]
|
_ = x[OITAB-139]
|
||||||
_ = x[OSPTR-140]
|
_ = x[OIDATA-140]
|
||||||
_ = x[OCLOSUREVAR-141]
|
_ = x[OSPTR-141]
|
||||||
_ = x[OCFUNC-142]
|
_ = x[OCLOSUREVAR-142]
|
||||||
_ = x[OCHECKNIL-143]
|
_ = x[OCFUNC-143]
|
||||||
_ = x[OVARDEF-144]
|
_ = x[OCHECKNIL-144]
|
||||||
_ = x[OVARKILL-145]
|
_ = x[OVARDEF-145]
|
||||||
_ = x[OVARLIVE-146]
|
_ = x[OVARKILL-146]
|
||||||
_ = x[ORESULT-147]
|
_ = x[OVARLIVE-147]
|
||||||
_ = x[OINLMARK-148]
|
_ = x[ORESULT-148]
|
||||||
_ = x[ORETJMP-149]
|
_ = x[OINLMARK-149]
|
||||||
_ = x[OGETG-150]
|
_ = x[ORETJMP-150]
|
||||||
_ = x[OEND-151]
|
_ = 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 {
|
func (i Op) String() string {
|
||||||
if i >= Op(len(_Op_index)-1) {
|
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.
|
// stmtList orders each of the statements in the list.
|
||||||
func (o *Order) stmtList(l Nodes) {
|
func (o *Order) stmtList(l Nodes) {
|
||||||
for _, n := range l.Slice() {
|
s := l.Slice()
|
||||||
o.stmt(n)
|
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.
|
// edge inserts coverage instrumentation for libfuzzer.
|
||||||
func (o *Order) edge() {
|
func (o *Order) edge() {
|
||||||
if Debug_libfuzzer == 0 {
|
if Debug_libfuzzer == 0 {
|
||||||
|
@ -1150,6 +1221,7 @@ func (o *Order) expr(n, lhs *Node) *Node {
|
||||||
OMAKECHAN,
|
OMAKECHAN,
|
||||||
OMAKEMAP,
|
OMAKEMAP,
|
||||||
OMAKESLICE,
|
OMAKESLICE,
|
||||||
|
OMAKESLICECOPY,
|
||||||
ONEW,
|
ONEW,
|
||||||
OREAL,
|
OREAL,
|
||||||
ORECOVER,
|
ORECOVER,
|
||||||
|
|
|
@ -271,7 +271,7 @@ func compile(fn *Node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if compilenow() {
|
if compilenow(fn) {
|
||||||
compileSSA(fn, 0)
|
compileSSA(fn, 0)
|
||||||
} else {
|
} else {
|
||||||
compilequeue = append(compilequeue, fn)
|
compilequeue = append(compilequeue, fn)
|
||||||
|
@ -282,10 +282,31 @@ func compile(fn *Node) {
|
||||||
// If functions are not compiled immediately,
|
// If functions are not compiled immediately,
|
||||||
// they are enqueued in compilequeue,
|
// they are enqueued in compilequeue,
|
||||||
// which is drained by compileFunctions.
|
// 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
|
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
|
const maxStackSize = 1 << 30
|
||||||
|
|
||||||
// compileSSA builds an SSA backend function,
|
// 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.
|
// allUnsafe indicates that all points in this function are
|
||||||
func (lv *Liveness) markUnsafePoints() {
|
// unsafe-points.
|
||||||
|
func allUnsafe(f *ssa.Func) bool {
|
||||||
// The runtime assumes the only safe-points are function
|
// The runtime assumes the only safe-points are function
|
||||||
// prologues (because that's how it used to be). We could and
|
// prologues (because that's how it used to be). We could and
|
||||||
// should improve that, but for now keep consider all points
|
// 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
|
// go:nosplit functions are similar. Since safe points used to
|
||||||
// be coupled with stack checks, go:nosplit often actually
|
// be coupled with stack checks, go:nosplit often actually
|
||||||
// means "no safe points in this function".
|
// 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.
|
// No complex analysis necessary.
|
||||||
lv.allUnsafe = true
|
lv.allUnsafe = true
|
||||||
return
|
return
|
||||||
|
@ -1249,7 +1255,7 @@ func (lv *Liveness) compact(b *ssa.Block) {
|
||||||
if go115ReduceLiveness {
|
if go115ReduceLiveness {
|
||||||
hasStackMap := lv.hasStackMap(v)
|
hasStackMap := lv.hasStackMap(v)
|
||||||
isUnsafePoint := lv.allUnsafe || lv.unsafePoints.Get(int32(v.ID))
|
isUnsafePoint := lv.allUnsafe || lv.unsafePoints.Get(int32(v.ID))
|
||||||
idx := LivenessIndex{StackMapDontCare, 0, isUnsafePoint}
|
idx := LivenessIndex{StackMapDontCare, StackMapDontCare, isUnsafePoint}
|
||||||
if hasStackMap {
|
if hasStackMap {
|
||||||
idx.stackMapIndex = lv.stackMapSet.add(lv.livevars[pos].vars)
|
idx.stackMapIndex = lv.stackMapSet.add(lv.livevars[pos].vars)
|
||||||
pos++
|
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
|
// for an empty block this will be used for its control
|
||||||
// instruction. We won't use the actual liveness map on a
|
// instruction. We won't use the actual liveness map on a
|
||||||
// control instruction. Just mark it something that is
|
// control instruction. Just mark it something that is
|
||||||
// preemptible.
|
// preemptible, unless this function is "all unsafe".
|
||||||
s.pp.nextLive = LivenessIndex{-1, -1, false}
|
s.pp.nextLive = LivenessIndex{-1, -1, allUnsafe(f)}
|
||||||
|
|
||||||
// Emit values in block
|
// Emit values in block
|
||||||
thearch.SSAMarkMoves(&s, b)
|
thearch.SSAMarkMoves(&s, b)
|
||||||
|
@ -6313,34 +6313,39 @@ func defframe(s *SSAGenState, e *ssafn) {
|
||||||
thearch.ZeroRange(pp, p, frame+lo, hi-lo, &state)
|
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
|
Jump obj.As
|
||||||
Index int
|
Index int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SSAGenState) oneFPJump(b *ssa.Block, jumps *FloatingEQNEJump) {
|
func (s *SSAGenState) oneJump(b *ssa.Block, jump *IndexJump) {
|
||||||
p := s.Prog(jumps.Jump)
|
p := s.Br(jump.Jump, b.Succs[jump.Index].Block())
|
||||||
p.To.Type = obj.TYPE_BRANCH
|
|
||||||
p.Pos = b.Pos
|
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 {
|
switch next {
|
||||||
case b.Succs[0].Block():
|
case b.Succs[0].Block():
|
||||||
s.oneFPJump(b, &jumps[0][0])
|
s.oneJump(b, &jumps[0][0])
|
||||||
s.oneFPJump(b, &jumps[0][1])
|
s.oneJump(b, &jumps[0][1])
|
||||||
case b.Succs[1].Block():
|
case b.Succs[1].Block():
|
||||||
s.oneFPJump(b, &jumps[1][0])
|
s.oneJump(b, &jumps[1][0])
|
||||||
s.oneFPJump(b, &jumps[1][1])
|
s.oneJump(b, &jumps[1][1])
|
||||||
default:
|
default:
|
||||||
s.oneFPJump(b, &jumps[1][0])
|
var q *obj.Prog
|
||||||
s.oneFPJump(b, &jumps[1][1])
|
if b.Likely != ssa.BranchUnlikely {
|
||||||
q := s.Prog(obj.AJMP)
|
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.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{}) {
|
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{
|
errors = append(errors, Error{
|
||||||
pos: pos,
|
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.
|
// 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 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 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) {
|
func (n *Node) SetBounded(b bool) {
|
||||||
switch n.Op {
|
switch n.Op {
|
||||||
case OINDEX, OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR:
|
case OINDEX, OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR:
|
||||||
// No bounds checks needed.
|
// No bounds checks needed.
|
||||||
case ODOTPTR, ODEREF:
|
case ODOTPTR, ODEREF:
|
||||||
// No nil check needed.
|
// No nil check needed.
|
||||||
|
case OMAKESLICECOPY:
|
||||||
|
// No length and cap checks needed
|
||||||
|
// since new slice and copied over slice data have same length.
|
||||||
default:
|
default:
|
||||||
Fatalf("SetBounded(%v)", n)
|
Fatalf("SetBounded(%v)", n)
|
||||||
}
|
}
|
||||||
|
@ -714,30 +718,38 @@ const (
|
||||||
ODCLCONST // const pi = 3.14
|
ODCLCONST // const pi = 3.14
|
||||||
ODCLTYPE // type Int int or type Int = int
|
ODCLTYPE // type Int int or type Int = int
|
||||||
|
|
||||||
ODELETE // delete(Left, Right)
|
ODELETE // delete(Left, Right)
|
||||||
ODOT // Left.Sym (Left is of struct type)
|
ODOT // Left.Sym (Left is of struct type)
|
||||||
ODOTPTR // Left.Sym (Left is of pointer to struct type)
|
ODOTPTR // Left.Sym (Left is of pointer to struct type)
|
||||||
ODOTMETH // Left.Sym (Left is non-interface, Right is method name)
|
ODOTMETH // Left.Sym (Left is non-interface, Right is method name)
|
||||||
ODOTINTER // Left.Sym (Left is 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)
|
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
|
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
|
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
|
OEQ // Left == Right
|
||||||
ONE // Left != Right
|
ONE // Left != Right
|
||||||
OLT // Left < Right
|
OLT // Left < Right
|
||||||
OLE // Left <= Right
|
OLE // Left <= Right
|
||||||
OGE // Left >= Right
|
OGE // Left >= Right
|
||||||
OGT // Left > Right
|
OGT // Left > Right
|
||||||
ODEREF // *Left
|
ODEREF // *Left
|
||||||
OINDEX // Left[Right] (index of array or slice)
|
OINDEX // Left[Right] (index of array or slice)
|
||||||
OINDEXMAP // Left[Right] (index of map)
|
OINDEXMAP // Left[Right] (index of map)
|
||||||
OKEY // Left:Right (key:value in struct/array/map literal)
|
OKEY // Left:Right (key:value in struct/array/map literal)
|
||||||
OSTRUCTKEY // Sym:Left (key:value in struct literal, after type checking)
|
OSTRUCTKEY // Sym:Left (key:value in struct literal, after type checking)
|
||||||
OLEN // len(Left)
|
OLEN // len(Left)
|
||||||
OMAKE // make(List) (before type checking converts to one of the following)
|
OMAKE // make(List) (before type checking converts to one of the following)
|
||||||
OMAKECHAN // make(Type, Left) (type is chan)
|
OMAKECHAN // make(Type, Left) (type is chan)
|
||||||
OMAKEMAP // make(Type, Left) (type is map)
|
OMAKEMAP // make(Type, Left) (type is map)
|
||||||
OMAKESLICE // make(Type, Left, Right) (type is slice)
|
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
|
OMUL // Left * Right
|
||||||
ODIV // Left / Right
|
ODIV // Left / Right
|
||||||
OMOD // 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.SetFirst(l)
|
||||||
n.List.SetSecond(c)
|
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:
|
case OSLICE, OSLICE3:
|
||||||
ok |= ctxExpr
|
ok |= ctxExpr
|
||||||
n.Left = typecheck(n.Left, 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 ci := lookdot1(nil, l.Sym, t, t.Fields(), 2); ci != nil { // Case-insensitive lookup.
|
||||||
if visible(ci.Sym) {
|
if visible(ci.Sym) {
|
||||||
yyerror("unknown field '%v' in struct literal of type %v (but does have %v)", l.Sym, t, 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 {
|
} else {
|
||||||
yyerror("unknown field '%v' in struct literal of type %v", l.Sym, t)
|
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)
|
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
|
// lvalue etc
|
||||||
func islvalue(n *Node) bool {
|
func islvalue(n *Node) bool {
|
||||||
switch n.Op {
|
switch n.Op {
|
||||||
|
|
|
@ -1390,6 +1390,63 @@ opswitch:
|
||||||
n = m
|
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:
|
case ORUNESTR:
|
||||||
a := nodnil()
|
a := nodnil()
|
||||||
if n.Esc == EscNone {
|
if n.Esc == EscNone {
|
||||||
|
@ -3772,6 +3829,9 @@ func candiscard(n *Node) bool {
|
||||||
// Difficult to tell what sizes are okay.
|
// Difficult to tell what sizes are okay.
|
||||||
case OMAKESLICE:
|
case OMAKESLICE:
|
||||||
return false
|
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) {
|
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)
|
f.Fatalf("bad type %T for S390XRotateParams in %v", v.Aux, v)
|
||||||
}
|
}
|
||||||
canHaveAux = true
|
canHaveAux = true
|
||||||
|
case auxFlagConstant:
|
||||||
|
if v.AuxInt < 0 || v.AuxInt > 15 {
|
||||||
|
f.Fatalf("bad FlagConstant AuxInt value for %v", v)
|
||||||
|
}
|
||||||
|
canHaveAuxInt = true
|
||||||
default:
|
default:
|
||||||
f.Fatalf("unknown aux type for %s", v.Op)
|
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 deadcode for cse", fn: deadcode}, // deadcode immediately before CSE avoids CSE making dead values live again
|
||||||
{name: "lowered cse", fn: cse},
|
{name: "lowered cse", fn: cse},
|
||||||
{name: "elim unread autos", fn: elimUnreadAutos},
|
{name: "elim unread autos", fn: elimUnreadAutos},
|
||||||
|
{name: "tighten tuple selectors", fn: tightenTupleSelectors, required: true},
|
||||||
{name: "lowered deadcode", fn: deadcode, required: true},
|
{name: "lowered deadcode", fn: deadcode, required: true},
|
||||||
{name: "checkLower", fn: checkLower, required: true},
|
{name: "checkLower", fn: checkLower, required: true},
|
||||||
{name: "late phielim", fn: phielim},
|
{name: "late phielim", fn: phielim},
|
||||||
|
@ -509,6 +510,8 @@ var passOrder = [...]constraint{
|
||||||
{"decompose builtin", "late opt"},
|
{"decompose builtin", "late opt"},
|
||||||
// decompose builtin is the last pass that may introduce new float ops, so run softfloat after it
|
// decompose builtin is the last pass that may introduce new float ops, so run softfloat after it
|
||||||
{"decompose builtin", "softfloat"},
|
{"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
|
// remove critical edges before phi tighten, so that phi args get better placement
|
||||||
{"critical", "phi tighten"},
|
{"critical", "phi tighten"},
|
||||||
// don't layout blocks until critical edges have been removed
|
// 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)
|
rewrites := int64(0)
|
||||||
|
|
||||||
// Apply substitutions
|
// Apply substitutions
|
||||||
|
@ -259,6 +222,7 @@ func cse(f *Func) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.pass.stats > 0 {
|
if f.pass.stats > 0 {
|
||||||
f.LogStat("CSE REWRITES", rewrites)
|
f.LogStat("CSE REWRITES", rewrites)
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,9 +73,11 @@ func dse(f *Func) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Walk backwards looking for dead stores. Keep track of shadowed addresses.
|
// 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
|
// A "shadowed address" is a pointer and a size describing a memory region that
|
||||||
// the write. This code will not remove dead stores to the same address
|
// is known to be written. We keep track of shadowed addresses in the shadowed
|
||||||
// of different types.
|
// 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()
|
shadowed.clear()
|
||||||
v := last
|
v := last
|
||||||
|
|
||||||
|
@ -93,17 +95,13 @@ func dse(f *Func) {
|
||||||
sz = v.AuxInt
|
sz = v.AuxInt
|
||||||
}
|
}
|
||||||
if shadowedSize := int64(shadowed.get(v.Args[0].ID)); shadowedSize != -1 && shadowedSize >= sz {
|
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 {
|
if v.Op == OpStore {
|
||||||
// store addr value mem
|
// store addr value mem
|
||||||
v.SetArgs1(v.Args[2])
|
v.SetArgs1(v.Args[2])
|
||||||
} else {
|
} else {
|
||||||
// zero addr mem
|
// 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.SetArgs1(v.Args[1])
|
||||||
}
|
}
|
||||||
v.Aux = nil
|
v.Aux = nil
|
||||||
|
|
|
@ -49,11 +49,11 @@ var gogcflags = os.Getenv("GO_GCFLAGS")
|
||||||
// optimizedLibs usually means "not running in a noopt test builder".
|
// optimizedLibs usually means "not running in a noopt test builder".
|
||||||
var optimizedLibs = (!strings.Contains(gogcflags, "-N") && !strings.Contains(gogcflags, "-l"))
|
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
|
// to next through the generated executable, recording each line landed at, and
|
||||||
// then compares those lines with reference file(s).
|
// then compares those lines with reference file(s).
|
||||||
// Flag -u updates the 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 -v is ever-so-slightly verbose.
|
||||||
// Flag -n is for dry-run, and prints the shell and first debug commands.
|
// 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.
|
// to indicate normalization of Strings, (hex) addresses, and numbers.
|
||||||
// "O" is an explicit indication that we expect it to be optimized out.
|
// "O" is an explicit indication that we expect it to be optimized out.
|
||||||
// For example:
|
// 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
|
// TODO: not implemented for Delve yet, but this is the plan
|
||||||
//
|
//
|
||||||
// After a compiler change that causes a difference in the debug behavior, check
|
// 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
|
// go test debug_test.go -args -u
|
||||||
// (for Delve)
|
// (for Delve)
|
||||||
// go test debug_test.go -args -u -d
|
// go test debug_test.go -args -u -d
|
||||||
|
//
|
||||||
func TestNexting(t *testing.T) {
|
func TestNexting(t *testing.T) {
|
||||||
testenv.SkipFlaky(t, 37404)
|
testenv.SkipFlaky(t, 37404)
|
||||||
|
|
||||||
|
@ -110,7 +110,13 @@ func TestNexting(t *testing.T) {
|
||||||
// Various architectures tend to differ slightly sometimes, and keeping them
|
// 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,
|
// all in sync is a pain for people who don't have them all at hand,
|
||||||
// so limit testing to amd64 (for now)
|
// 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 {
|
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)
|
(Select1 (CALLudiv x (MOVWconst [c]))) && isPowerOfTwo(c) -> (ANDconst [c-1] x)
|
||||||
|
|
||||||
// constant comparisons
|
// constant comparisons
|
||||||
(CMPconst (MOVWconst [x]) [y]) && int32(x)==int32(y) -> (FlagEQ)
|
(CMPconst (MOVWconst [x]) [y]) => (FlagConstant [subFlags32(x,y)])
|
||||||
(CMPconst (MOVWconst [x]) [y]) && int32(x)<int32(y) && uint32(x)<uint32(y) -> (FlagLT_ULT)
|
(CMNconst (MOVWconst [x]) [y]) => (FlagConstant [addFlags32(x,y)])
|
||||||
(CMPconst (MOVWconst [x]) [y]) && int32(x)<int32(y) && uint32(x)>uint32(y) -> (FlagLT_UGT)
|
(TSTconst (MOVWconst [x]) [y]) => (FlagConstant [logicFlags32(x&y)])
|
||||||
(CMPconst (MOVWconst [x]) [y]) && int32(x)>int32(y) && uint32(x)<uint32(y) -> (FlagGT_ULT)
|
(TEQconst (MOVWconst [x]) [y]) => (FlagConstant [logicFlags32(x^y)])
|
||||||
(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)
|
|
||||||
|
|
||||||
// other known comparisons
|
// other known comparisons
|
||||||
(CMPconst (MOVBUreg _) [c]) && 0xff < c -> (FlagLT_ULT)
|
(CMPconst (MOVBUreg _) [c]) && 0xff < c => (FlagConstant [subFlags32(0, 1)])
|
||||||
(CMPconst (MOVHUreg _) [c]) && 0xffff < c -> (FlagLT_ULT)
|
(CMPconst (MOVHUreg _) [c]) && 0xffff < c => (FlagConstant [subFlags32(0, 1)])
|
||||||
(CMPconst (ANDconst _ [m]) [n]) && 0 <= int32(m) && int32(m) < int32(n) -> (FlagLT_ULT)
|
(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) -> (FlagLT_ULT)
|
(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
|
// absorb flag constants into branches
|
||||||
(EQ (FlagEQ) yes no) -> (First yes no)
|
(EQ (FlagConstant [fc]) yes no) && fc.eq() => (First yes no)
|
||||||
(EQ (FlagLT_ULT) yes no) -> (First no yes)
|
(EQ (FlagConstant [fc]) yes no) && !fc.eq() => (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)
|
|
||||||
|
|
||||||
(NE (FlagEQ) yes no) -> (First no yes)
|
(NE (FlagConstant [fc]) yes no) && fc.ne() => (First yes no)
|
||||||
(NE (FlagLT_ULT) yes no) -> (First yes no)
|
(NE (FlagConstant [fc]) yes no) && !fc.ne() => (First no yes)
|
||||||
(NE (FlagLT_UGT) yes no) -> (First yes no)
|
|
||||||
(NE (FlagGT_ULT) yes no) -> (First yes no)
|
|
||||||
(NE (FlagGT_UGT) yes no) -> (First yes no)
|
|
||||||
|
|
||||||
(LT (FlagEQ) yes no) -> (First no yes)
|
(LT (FlagConstant [fc]) yes no) && fc.lt() => (First yes no)
|
||||||
(LT (FlagLT_ULT) yes no) -> (First yes no)
|
(LT (FlagConstant [fc]) yes no) && !fc.lt() => (First no yes)
|
||||||
(LT (FlagLT_UGT) yes no) -> (First yes no)
|
|
||||||
(LT (FlagGT_ULT) yes no) -> (First no yes)
|
|
||||||
(LT (FlagGT_UGT) yes no) -> (First no yes)
|
|
||||||
|
|
||||||
(LE (FlagEQ) yes no) -> (First yes no)
|
(LE (FlagConstant [fc]) yes no) && fc.le() => (First yes no)
|
||||||
(LE (FlagLT_ULT) yes no) -> (First yes no)
|
(LE (FlagConstant [fc]) yes no) && !fc.le() => (First no yes)
|
||||||
(LE (FlagLT_UGT) yes no) -> (First yes no)
|
|
||||||
(LE (FlagGT_ULT) yes no) -> (First no yes)
|
|
||||||
(LE (FlagGT_UGT) yes no) -> (First no yes)
|
|
||||||
|
|
||||||
(GT (FlagEQ) yes no) -> (First no yes)
|
(GT (FlagConstant [fc]) yes no) && fc.gt() => (First yes no)
|
||||||
(GT (FlagLT_ULT) yes no) -> (First no yes)
|
(GT (FlagConstant [fc]) yes no) && !fc.gt() => (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)
|
|
||||||
|
|
||||||
(GE (FlagEQ) yes no) -> (First yes no)
|
(GE (FlagConstant [fc]) yes no) && fc.ge() => (First yes no)
|
||||||
(GE (FlagLT_ULT) yes no) -> (First no yes)
|
(GE (FlagConstant [fc]) yes no) && !fc.ge() => (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)
|
|
||||||
|
|
||||||
(ULT (FlagEQ) yes no) -> (First no yes)
|
(ULT (FlagConstant [fc]) yes no) && fc.ult() => (First yes no)
|
||||||
(ULT (FlagLT_ULT) yes no) -> (First yes no)
|
(ULT (FlagConstant [fc]) yes no) && !fc.ult() => (First no yes)
|
||||||
(ULT (FlagLT_UGT) yes no) -> (First no yes)
|
|
||||||
(ULT (FlagGT_ULT) yes no) -> (First yes no)
|
|
||||||
(ULT (FlagGT_UGT) yes no) -> (First no yes)
|
|
||||||
|
|
||||||
(ULE (FlagEQ) yes no) -> (First yes no)
|
(ULE (FlagConstant [fc]) yes no) && fc.ule() => (First yes no)
|
||||||
(ULE (FlagLT_ULT) yes no) -> (First yes no)
|
(ULE (FlagConstant [fc]) yes no) && !fc.ule() => (First no yes)
|
||||||
(ULE (FlagLT_UGT) yes no) -> (First no yes)
|
|
||||||
(ULE (FlagGT_ULT) yes no) -> (First yes no)
|
|
||||||
(ULE (FlagGT_UGT) yes no) -> (First no yes)
|
|
||||||
|
|
||||||
(UGT (FlagEQ) yes no) -> (First no yes)
|
(UGT (FlagConstant [fc]) yes no) && fc.ugt() => (First yes no)
|
||||||
(UGT (FlagLT_ULT) yes no) -> (First no yes)
|
(UGT (FlagConstant [fc]) yes no) && !fc.ugt() => (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)
|
|
||||||
|
|
||||||
(UGE (FlagEQ) yes no) -> (First yes no)
|
(UGE (FlagConstant [fc]) yes no) && fc.uge() => (First yes no)
|
||||||
(UGE (FlagLT_ULT) yes no) -> (First no yes)
|
(UGE (FlagConstant [fc]) yes no) && !fc.uge() => (First no yes)
|
||||||
(UGE (FlagLT_UGT) yes no) -> (First yes no)
|
|
||||||
(UGE (FlagGT_ULT) yes no) -> (First no yes)
|
(LTnoov (FlagConstant [fc]) yes no) && fc.ltNoov() => (First yes no)
|
||||||
(UGE (FlagGT_UGT) yes no) -> (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
|
// absorb InvertFlags into branches
|
||||||
(LT (InvertFlags cmp) yes no) -> (GT cmp yes no)
|
(LT (InvertFlags cmp) yes no) -> (GT cmp yes no)
|
||||||
|
@ -704,67 +674,22 @@
|
||||||
(UGE (InvertFlags cmp) yes no) -> (ULE cmp yes no)
|
(UGE (InvertFlags cmp) yes no) -> (ULE cmp yes no)
|
||||||
(EQ (InvertFlags cmp) yes no) -> (EQ cmp yes no)
|
(EQ (InvertFlags cmp) yes no) -> (EQ cmp yes no)
|
||||||
(NE (InvertFlags cmp) yes no) -> (NE 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
|
// absorb flag constants into boolean values
|
||||||
(Equal (FlagEQ)) -> (MOVWconst [1])
|
(Equal (FlagConstant [fc])) => (MOVWconst [b2i32(fc.eq())])
|
||||||
(Equal (FlagLT_ULT)) -> (MOVWconst [0])
|
(NotEqual (FlagConstant [fc])) => (MOVWconst [b2i32(fc.ne())])
|
||||||
(Equal (FlagLT_UGT)) -> (MOVWconst [0])
|
(LessThan (FlagConstant [fc])) => (MOVWconst [b2i32(fc.lt())])
|
||||||
(Equal (FlagGT_ULT)) -> (MOVWconst [0])
|
(LessThanU (FlagConstant [fc])) => (MOVWconst [b2i32(fc.ult())])
|
||||||
(Equal (FlagGT_UGT)) -> (MOVWconst [0])
|
(LessEqual (FlagConstant [fc])) => (MOVWconst [b2i32(fc.le())])
|
||||||
|
(LessEqualU (FlagConstant [fc])) => (MOVWconst [b2i32(fc.ule())])
|
||||||
(NotEqual (FlagEQ)) -> (MOVWconst [0])
|
(GreaterThan (FlagConstant [fc])) => (MOVWconst [b2i32(fc.gt())])
|
||||||
(NotEqual (FlagLT_ULT)) -> (MOVWconst [1])
|
(GreaterThanU (FlagConstant [fc])) => (MOVWconst [b2i32(fc.ugt())])
|
||||||
(NotEqual (FlagLT_UGT)) -> (MOVWconst [1])
|
(GreaterEqual (FlagConstant [fc])) => (MOVWconst [b2i32(fc.ge())])
|
||||||
(NotEqual (FlagGT_ULT)) -> (MOVWconst [1])
|
(GreaterEqualU (FlagConstant [fc])) => (MOVWconst [b2i32(fc.uge())])
|
||||||
(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])
|
|
||||||
|
|
||||||
// absorb InvertFlags into boolean values
|
// absorb InvertFlags into boolean values
|
||||||
(Equal (InvertFlags x)) -> (Equal x)
|
(Equal (InvertFlags x)) -> (Equal x)
|
||||||
|
@ -779,26 +704,17 @@
|
||||||
(GreaterEqualU (InvertFlags x)) -> (LessEqualU x)
|
(GreaterEqualU (InvertFlags x)) -> (LessEqualU x)
|
||||||
|
|
||||||
// absorb flag constants into conditional instructions
|
// absorb flag constants into conditional instructions
|
||||||
(CMOVWLSconst _ (FlagEQ) [c]) -> (MOVWconst [c])
|
(CMOVWLSconst _ (FlagConstant [fc]) [c]) && fc.ule() => (MOVWconst [c])
|
||||||
(CMOVWLSconst _ (FlagLT_ULT) [c]) -> (MOVWconst [c])
|
(CMOVWLSconst x (FlagConstant [fc]) [c]) && fc.ugt() => x
|
||||||
(CMOVWLSconst x (FlagLT_UGT)) -> x
|
|
||||||
(CMOVWLSconst _ (FlagGT_ULT) [c]) -> (MOVWconst [c])
|
|
||||||
(CMOVWLSconst x (FlagGT_UGT)) -> x
|
|
||||||
|
|
||||||
(CMOVWHSconst _ (FlagEQ) [c]) -> (MOVWconst [c])
|
(CMOVWHSconst _ (FlagConstant [fc]) [c]) && fc.uge() => (MOVWconst [c])
|
||||||
(CMOVWHSconst x (FlagLT_ULT)) -> x
|
(CMOVWHSconst x (FlagConstant [fc]) [c]) && fc.ult() => x
|
||||||
(CMOVWHSconst _ (FlagLT_UGT) [c]) -> (MOVWconst [c])
|
|
||||||
(CMOVWHSconst x (FlagGT_ULT)) -> x
|
|
||||||
(CMOVWHSconst _ (FlagGT_UGT) [c]) -> (MOVWconst [c])
|
|
||||||
|
|
||||||
(CMOVWLSconst x (InvertFlags flags) [c]) -> (CMOVWHSconst x flags [c])
|
(CMOVWLSconst x (InvertFlags flags) [c]) -> (CMOVWHSconst x flags [c])
|
||||||
(CMOVWHSconst x (InvertFlags flags) [c]) -> (CMOVWLSconst x flags [c])
|
(CMOVWHSconst x (InvertFlags flags) [c]) -> (CMOVWLSconst x flags [c])
|
||||||
|
|
||||||
(SRAcond x _ (FlagEQ)) -> (SRAconst x [31])
|
(SRAcond x _ (FlagConstant [fc])) && fc.uge() => (SRAconst x [31])
|
||||||
(SRAcond x y (FlagLT_ULT)) -> (SRA x y)
|
(SRAcond x y (FlagConstant [fc])) && fc.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])
|
|
||||||
|
|
||||||
// remove redundant *const ops
|
// remove redundant *const ops
|
||||||
(ADDconst [0] x) -> x
|
(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:(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:(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)
|
(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:(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 -> (LT (CMP a (MUL <x.Type> 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 -> (LT (CMPconst [c] x) 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 -> (LT (CMPshiftLL x y [c]) 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 -> (LT (CMPshiftRL 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 -> (LT (CMPshiftRA 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 -> (LT (CMPshiftLLreg x y z) 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 -> (LT (CMPshiftRLreg 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 -> (LT (CMPshiftRAreg 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 -> (LE (CMP x y) 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 -> (LE (CMP a (MUL <x.Type> 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 -> (LE (CMPconst [c] x) 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 -> (LE (CMPshiftLL x y [c]) 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 -> (LE (CMPshiftRL 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 -> (LE (CMPshiftRA 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 -> (LE (CMPshiftLLreg x y z) 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 -> (LE (CMPshiftRLreg 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 -> (LE (CMPshiftRAreg 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 -> (LT (CMN x y) 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 -> (LT (CMN a (MUL <x.Type> 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 -> (LT (CMNconst [c] x) 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 -> (LT (CMNshiftLL x y [c]) 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 -> (LT (CMNshiftRL 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 -> (LT (CMNshiftRA 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 -> (LT (CMNshiftLLreg x y z) 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 -> (LT (CMNshiftRLreg 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 -> (LT (CMNshiftRAreg 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 -> (LE (CMN x y) 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 -> (LE (CMN a (MUL <x.Type> 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 -> (LE (CMNconst [c] x) 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 -> (LE (CMNshiftLL x y [c]) 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 -> (LE (CMNshiftRL 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 -> (LE (CMNshiftRA 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 -> (LE (CMNshiftLLreg x y z) 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 -> (LE (CMNshiftRLreg 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 -> (LE (CMNshiftRAreg 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:(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:(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)
|
(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:(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:(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)
|
(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:(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 -> (GT (CMP a (MUL <x.Type> 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 -> (GT (CMPconst [c] x) 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 -> (GT (CMPshiftLL x y [c]) 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 -> (GT (CMPshiftRL 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 -> (GT (CMPshiftRA 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 -> (GT (CMPshiftLLreg x y z) 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 -> (GT (CMPshiftRLreg 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 -> (GT (CMPshiftRAreg 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 -> (GE (CMP x y) 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 -> (GE (CMP a (MUL <x.Type> 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 -> (GE (CMPconst [c] x) 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 -> (GE (CMPshiftLL x y [c]) 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 -> (GE (CMPshiftRL 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 -> (GE (CMPshiftRA 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 -> (GE (CMPshiftLLreg x y z) 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 -> (GE (CMPshiftRLreg 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 -> (GE (CMPshiftRAreg 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 -> (GT (CMN x y) 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 -> (GT (CMNconst [c] x) 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 -> (GT (CMNshiftLL x y [c]) 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 -> (GT (CMNshiftRL 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 -> (GT (CMNshiftRA 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 -> (GT (CMNshiftLLreg x y z) 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 -> (GT (CMNshiftRLreg 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 -> (GT (CMNshiftRAreg 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 -> (GE (CMN x y) 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 -> (GE (CMN a (MUL <x.Type> 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 -> (GE (CMNconst [c] x) 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 -> (GE (CMNshiftLL x y [c]) 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 -> (GE (CMNshiftRL 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 -> (GE (CMNshiftRA 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 -> (GE (CMNshiftLLreg x y z) 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 -> (GE (CMNshiftRLreg 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 -> (GE (CMNshiftRAreg 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:(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:(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:(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)
|
(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)
|
(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)
|
(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)
|
(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 => (LE (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 => (GT (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 => (GE (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)
|
(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)
|
(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)
|
(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 => (LE (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 => (GT (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 => (GE (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)
|
(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)
|
(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)
|
(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 => (LE (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 => (GT (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 => (GE (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)
|
(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)
|
(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)
|
(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 => (LE (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 => (GT (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 => (GE (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)
|
(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)
|
(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)
|
(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)
|
(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)
|
(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 => (LE (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 => (GT (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 => (GE (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)
|
(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)
|
(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)
|
(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 => (LT (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 => (GE (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 => (GT (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)
|
(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)
|
(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)
|
(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 => (LT (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 => (GE (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 => (GT (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)
|
(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)
|
(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)
|
(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 => (LT (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 => (GE (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 => (GT (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
|
// Absorb bit-tests into block
|
||||||
(Z (ANDconst [c] x) yes no) && oneBit(c) => (TBZ [int64(ntz64(c))] x yes no)
|
(Z (ANDconst [c] x) yes no) && oneBit(c) => (TBZ [int64(ntz64(c))] x yes no)
|
||||||
|
@ -1381,103 +1381,64 @@
|
||||||
(MOVDreg (MOVDconst [c])) -> (MOVDconst [c])
|
(MOVDreg (MOVDconst [c])) -> (MOVDconst [c])
|
||||||
|
|
||||||
// constant comparisons
|
// constant comparisons
|
||||||
(CMPconst (MOVDconst [x]) [y]) && x==y -> (FlagEQ)
|
(CMPconst (MOVDconst [x]) [y]) => (FlagConstant [subFlags64(x,y)])
|
||||||
(CMPconst (MOVDconst [x]) [y]) && x<y && uint64(x)<uint64(y) -> (FlagLT_ULT)
|
(CMPWconst (MOVDconst [x]) [y]) => (FlagConstant [subFlags32(int32(x),y)])
|
||||||
(CMPconst (MOVDconst [x]) [y]) && x<y && uint64(x)>uint64(y) -> (FlagLT_UGT)
|
(TSTconst (MOVDconst [x]) [y]) => (FlagConstant [logicFlags64(x&y)])
|
||||||
(CMPconst (MOVDconst [x]) [y]) && x>y && uint64(x)<uint64(y) -> (FlagGT_ULT)
|
(TSTWconst (MOVDconst [x]) [y]) => (FlagConstant [logicFlags32(int32(x)&y)])
|
||||||
(CMPconst (MOVDconst [x]) [y]) && x>y && uint64(x)>uint64(y) -> (FlagGT_UGT)
|
(CMNconst (MOVDconst [x]) [y]) => (FlagConstant [addFlags64(x,y)])
|
||||||
(CMPWconst (MOVDconst [x]) [y]) && int32(x)==int32(y) -> (FlagEQ)
|
(CMNWconst (MOVDconst [x]) [y]) => (FlagConstant [addFlags32(int32(x),y)])
|
||||||
(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)
|
|
||||||
|
|
||||||
|
|
||||||
// other known comparisons
|
// other known comparisons
|
||||||
(CMPconst (MOVBUreg _) [c]) && 0xff < c -> (FlagLT_ULT)
|
(CMPconst (MOVBUreg _) [c]) && 0xff < c => (FlagConstant [subFlags64(0,1)])
|
||||||
(CMPconst (MOVHUreg _) [c]) && 0xffff < c -> (FlagLT_ULT)
|
(CMPconst (MOVHUreg _) [c]) && 0xffff < c => (FlagConstant [subFlags64(0,1)])
|
||||||
(CMPconst (MOVWUreg _) [c]) && 0xffffffff < c -> (FlagLT_ULT)
|
(CMPconst (MOVWUreg _) [c]) && 0xffffffff < c => (FlagConstant [subFlags64(0,1)])
|
||||||
(CMPconst (ANDconst _ [m]) [n]) && 0 <= m && m < n -> (FlagLT_ULT)
|
(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) -> (FlagLT_ULT)
|
(CMPconst (SRLconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 63 && (1<<uint64(64-c)) <= uint64(n) => (FlagConstant [subFlags64(0,1)])
|
||||||
(CMPWconst (MOVBUreg _) [c]) && 0xff < int32(c) -> (FlagLT_ULT)
|
(CMPWconst (MOVBUreg _) [c]) && 0xff < c => (FlagConstant [subFlags64(0,1)])
|
||||||
(CMPWconst (MOVHUreg _) [c]) && 0xffff < int32(c) -> (FlagLT_ULT)
|
(CMPWconst (MOVHUreg _) [c]) && 0xffff < c => (FlagConstant [subFlags64(0,1)])
|
||||||
|
|
||||||
// absorb flag constants into branches
|
// absorb flag constants into branches
|
||||||
(EQ (FlagEQ) yes no) -> (First yes no)
|
(EQ (FlagConstant [fc]) yes no) && fc.eq() => (First yes no)
|
||||||
(EQ (FlagLT_ULT) yes no) -> (First no yes)
|
(EQ (FlagConstant [fc]) yes no) && !fc.eq() => (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)
|
|
||||||
|
|
||||||
(NE (FlagEQ) yes no) -> (First no yes)
|
(NE (FlagConstant [fc]) yes no) && fc.ne() => (First yes no)
|
||||||
(NE (FlagLT_ULT) yes no) -> (First yes no)
|
(NE (FlagConstant [fc]) yes no) && !fc.ne() => (First no yes)
|
||||||
(NE (FlagLT_UGT) yes no) -> (First yes no)
|
|
||||||
(NE (FlagGT_ULT) yes no) -> (First yes no)
|
|
||||||
(NE (FlagGT_UGT) yes no) -> (First yes no)
|
|
||||||
|
|
||||||
(LT (FlagEQ) yes no) -> (First no yes)
|
(LT (FlagConstant [fc]) yes no) && fc.lt() => (First yes no)
|
||||||
(LT (FlagLT_ULT) yes no) -> (First yes no)
|
(LT (FlagConstant [fc]) yes no) && !fc.lt() => (First no yes)
|
||||||
(LT (FlagLT_UGT) yes no) -> (First yes no)
|
|
||||||
(LT (FlagGT_ULT) yes no) -> (First no yes)
|
|
||||||
(LT (FlagGT_UGT) yes no) -> (First no yes)
|
|
||||||
|
|
||||||
(LE (FlagEQ) yes no) -> (First yes no)
|
(LE (FlagConstant [fc]) yes no) && fc.le() => (First yes no)
|
||||||
(LE (FlagLT_ULT) yes no) -> (First yes no)
|
(LE (FlagConstant [fc]) yes no) && !fc.le() => (First no yes)
|
||||||
(LE (FlagLT_UGT) yes no) -> (First yes no)
|
|
||||||
(LE (FlagGT_ULT) yes no) -> (First no yes)
|
|
||||||
(LE (FlagGT_UGT) yes no) -> (First no yes)
|
|
||||||
|
|
||||||
(GT (FlagEQ) yes no) -> (First no yes)
|
(GT (FlagConstant [fc]) yes no) && fc.gt() => (First yes no)
|
||||||
(GT (FlagLT_ULT) yes no) -> (First no yes)
|
(GT (FlagConstant [fc]) yes no) && !fc.gt() => (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)
|
|
||||||
|
|
||||||
(GE (FlagEQ) yes no) -> (First yes no)
|
(GE (FlagConstant [fc]) yes no) && fc.ge() => (First yes no)
|
||||||
(GE (FlagLT_ULT) yes no) -> (First no yes)
|
(GE (FlagConstant [fc]) yes no) && !fc.ge() => (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)
|
|
||||||
|
|
||||||
(ULT (FlagEQ) yes no) -> (First no yes)
|
(ULT (FlagConstant [fc]) yes no) && fc.ult() => (First yes no)
|
||||||
(ULT (FlagLT_ULT) yes no) -> (First yes no)
|
(ULT (FlagConstant [fc]) yes no) && !fc.ult() => (First no yes)
|
||||||
(ULT (FlagLT_UGT) yes no) -> (First no yes)
|
|
||||||
(ULT (FlagGT_ULT) yes no) -> (First yes no)
|
|
||||||
(ULT (FlagGT_UGT) yes no) -> (First no yes)
|
|
||||||
|
|
||||||
(ULE (FlagEQ) yes no) -> (First yes no)
|
(ULE (FlagConstant [fc]) yes no) && fc.ule() => (First yes no)
|
||||||
(ULE (FlagLT_ULT) yes no) -> (First yes no)
|
(ULE (FlagConstant [fc]) yes no) && !fc.ule() => (First no yes)
|
||||||
(ULE (FlagLT_UGT) yes no) -> (First no yes)
|
|
||||||
(ULE (FlagGT_ULT) yes no) -> (First yes no)
|
|
||||||
(ULE (FlagGT_UGT) yes no) -> (First no yes)
|
|
||||||
|
|
||||||
(UGT (FlagEQ) yes no) -> (First no yes)
|
(UGT (FlagConstant [fc]) yes no) && fc.ugt() => (First yes no)
|
||||||
(UGT (FlagLT_ULT) yes no) -> (First no yes)
|
(UGT (FlagConstant [fc]) yes no) && !fc.ugt() => (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)
|
|
||||||
|
|
||||||
(UGE (FlagEQ) yes no) -> (First yes no)
|
(UGE (FlagConstant [fc]) yes no) && fc.uge() => (First yes no)
|
||||||
(UGE (FlagLT_ULT) yes no) -> (First no yes)
|
(UGE (FlagConstant [fc]) yes no) && !fc.uge() => (First no yes)
|
||||||
(UGE (FlagLT_UGT) yes no) -> (First yes no)
|
|
||||||
(UGE (FlagGT_ULT) yes no) -> (First no yes)
|
(LTnoov (FlagConstant [fc]) yes no) && fc.ltNoov() => (First yes no)
|
||||||
(UGE (FlagGT_UGT) yes no) -> (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 [0]) yes no) -> (First yes no)
|
||||||
(Z (MOVDconst [c]) yes no) && c != 0 -> (First no yes)
|
(Z (MOVDconst [c]) yes no) && c != 0 -> (First no yes)
|
||||||
|
@ -1503,71 +1464,26 @@
|
||||||
(FGT (InvertFlags cmp) yes no) -> (FLT cmp yes no)
|
(FGT (InvertFlags cmp) yes no) -> (FLT cmp yes no)
|
||||||
(FLE (InvertFlags cmp) yes no) -> (FGE cmp yes no)
|
(FLE (InvertFlags cmp) yes no) -> (FGE cmp yes no)
|
||||||
(FGE (InvertFlags cmp) yes no) -> (FLE 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)
|
// absorb InvertFlags into CSEL(0)
|
||||||
(CSEL {cc} x y (InvertFlags cmp)) -> (CSEL {arm64Invert(cc.(Op))} x y cmp)
|
(CSEL {cc} x y (InvertFlags cmp)) -> (CSEL {arm64Invert(cc.(Op))} x y cmp)
|
||||||
(CSEL0 {cc} x (InvertFlags cmp)) -> (CSEL0 {arm64Invert(cc.(Op))} x cmp)
|
(CSEL0 {cc} x (InvertFlags cmp)) -> (CSEL0 {arm64Invert(cc.(Op))} x cmp)
|
||||||
|
|
||||||
// absorb flag constants into boolean values
|
// absorb flag constants into boolean values
|
||||||
(Equal (FlagEQ)) -> (MOVDconst [1])
|
(Equal (FlagConstant [fc])) => (MOVDconst [b2i(fc.eq())])
|
||||||
(Equal (FlagLT_ULT)) -> (MOVDconst [0])
|
(NotEqual (FlagConstant [fc])) => (MOVDconst [b2i(fc.ne())])
|
||||||
(Equal (FlagLT_UGT)) -> (MOVDconst [0])
|
(LessThan (FlagConstant [fc])) => (MOVDconst [b2i(fc.lt())])
|
||||||
(Equal (FlagGT_ULT)) -> (MOVDconst [0])
|
(LessThanU (FlagConstant [fc])) => (MOVDconst [b2i(fc.ult())])
|
||||||
(Equal (FlagGT_UGT)) -> (MOVDconst [0])
|
(LessEqual (FlagConstant [fc])) => (MOVDconst [b2i(fc.le())])
|
||||||
|
(LessEqualU (FlagConstant [fc])) => (MOVDconst [b2i(fc.ule())])
|
||||||
(NotEqual (FlagEQ)) -> (MOVDconst [0])
|
(GreaterThan (FlagConstant [fc])) => (MOVDconst [b2i(fc.gt())])
|
||||||
(NotEqual (FlagLT_ULT)) -> (MOVDconst [1])
|
(GreaterThanU (FlagConstant [fc])) => (MOVDconst [b2i(fc.ugt())])
|
||||||
(NotEqual (FlagLT_UGT)) -> (MOVDconst [1])
|
(GreaterEqual (FlagConstant [fc])) => (MOVDconst [b2i(fc.ge())])
|
||||||
(NotEqual (FlagGT_ULT)) -> (MOVDconst [1])
|
(GreaterEqualU (FlagConstant [fc])) => (MOVDconst [b2i(fc.uge())])
|
||||||
(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])
|
|
||||||
|
|
||||||
// absorb InvertFlags into boolean values
|
// absorb InvertFlags into boolean values
|
||||||
(Equal (InvertFlags x)) -> (Equal x)
|
(Equal (InvertFlags x)) -> (Equal x)
|
||||||
|
|
|
@ -587,18 +587,12 @@ func init() {
|
||||||
// See runtime/stubs.go for a more detailed discussion.
|
// See runtime/stubs.go for a more detailed discussion.
|
||||||
{name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true},
|
{name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true},
|
||||||
|
|
||||||
// Constant flag values. For any comparison, there are 5 possible
|
// Constant flag value.
|
||||||
// outcomes: the three from the signed total order (<,==,>) and the
|
// Note: there's an "unordered" outcome for floating-point
|
||||||
// three from the unsigned total order. The == cases overlap.
|
|
||||||
// Note: there's a sixth "unordered" outcome for floating-point
|
|
||||||
// comparisons, but we don't use such a beast yet.
|
// 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.
|
// cannot appear in the generated assembly.
|
||||||
{name: "FlagEQ"}, // equal
|
{name: "FlagConstant", aux: "FlagConstant"},
|
||||||
{name: "FlagLT_ULT"}, // signed < and unsigned <
|
|
||||||
{name: "FlagLT_UGT"}, // signed < and unsigned >
|
|
||||||
{name: "FlagGT_UGT"}, // signed > and unsigned <
|
|
||||||
{name: "FlagGT_ULT"}, // signed > and unsigned >
|
|
||||||
|
|
||||||
// (InvertFlags (CMP a b)) == (CMP b a)
|
// (InvertFlags (CMP a b)) == (CMP b a)
|
||||||
// InvertFlags is a pseudo-op which can't appear in assembly output.
|
// InvertFlags is a pseudo-op which can't appear in assembly output.
|
||||||
|
@ -701,6 +695,10 @@ func init() {
|
||||||
{name: "FLE", controls: 1},
|
{name: "FLE", controls: 1},
|
||||||
{name: "FGT", controls: 1},
|
{name: "FGT", controls: 1},
|
||||||
{name: "FGE", 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{
|
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: "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).
|
{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
|
// Constant flag value.
|
||||||
// outcomes: the three from the signed total order (<,==,>) and the
|
// Note: there's an "unordered" outcome for floating-point
|
||||||
// three from the unsigned total order. The == cases overlap.
|
|
||||||
// Note: there's a sixth "unordered" outcome for floating-point
|
|
||||||
// comparisons, but we don't use such a beast yet.
|
// 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.
|
// cannot appear in the generated assembly.
|
||||||
{name: "FlagEQ"}, // equal
|
{name: "FlagConstant", aux: "FlagConstant"},
|
||||||
{name: "FlagLT_ULT"}, // signed < and unsigned <
|
|
||||||
{name: "FlagLT_UGT"}, // signed < and unsigned >
|
|
||||||
{name: "FlagGT_UGT"}, // signed > and unsigned <
|
|
||||||
{name: "FlagGT_ULT"}, // signed > and unsigned >
|
|
||||||
|
|
||||||
// (InvertFlags (CMP a b)) == (CMP b a)
|
// (InvertFlags (CMP a b)) == (CMP b a)
|
||||||
// InvertFlags is a pseudo-op which can't appear in assembly output.
|
// InvertFlags is a pseudo-op which can't appear in assembly output.
|
||||||
|
@ -584,6 +578,10 @@ func init() {
|
||||||
{name: "ULE", controls: 1},
|
{name: "ULE", controls: 1},
|
||||||
{name: "UGT", controls: 1},
|
{name: "UGT", controls: 1},
|
||||||
{name: "UGE", 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{
|
archs = append(archs, arch{
|
||||||
|
|
|
@ -153,18 +153,18 @@
|
||||||
(Rsh8x64 x (MOVDconst [c])) && uint64(c) < 8 => (SRAWconst (SignExt8to32 x) [c])
|
(Rsh8x64 x (MOVDconst [c])) && uint64(c) < 8 => (SRAWconst (SignExt8to32 x) [c])
|
||||||
(Rsh8Ux64 x (MOVDconst [c])) && uint64(c) < 8 => (SRWconst (ZeroExt8to32 x) [c])
|
(Rsh8Ux64 x (MOVDconst [c])) && uint64(c) < 8 => (SRWconst (ZeroExt8to32 x) [c])
|
||||||
|
|
||||||
(Lsh64x32 x (MOVDconst [c])) && uint32(c) < 64 => (SLDconst x [c])
|
(Lsh64x32 x (MOVDconst [c])) && uint32(c) < 64 => (SLDconst x [c&63])
|
||||||
(Rsh64x32 x (MOVDconst [c])) && uint32(c) < 64 => (SRADconst x [c])
|
(Rsh64x32 x (MOVDconst [c])) && uint32(c) < 64 => (SRADconst x [c&63])
|
||||||
(Rsh64Ux32 x (MOVDconst [c])) && uint32(c) < 64 => (SRDconst x [c])
|
(Rsh64Ux32 x (MOVDconst [c])) && uint32(c) < 64 => (SRDconst x [c&63])
|
||||||
(Lsh32x32 x (MOVDconst [c])) && uint32(c) < 32 => (SLWconst x [c])
|
(Lsh32x32 x (MOVDconst [c])) && uint32(c) < 32 => (SLWconst x [c&31])
|
||||||
(Rsh32x32 x (MOVDconst [c])) && uint32(c) < 32 => (SRAWconst x [c])
|
(Rsh32x32 x (MOVDconst [c])) && uint32(c) < 32 => (SRAWconst x [c&31])
|
||||||
(Rsh32Ux32 x (MOVDconst [c])) && uint32(c) < 32 => (SRWconst x [c])
|
(Rsh32Ux32 x (MOVDconst [c])) && uint32(c) < 32 => (SRWconst x [c&31])
|
||||||
(Lsh16x32 x (MOVDconst [c])) && uint32(c) < 16 => (SLWconst x [c])
|
(Lsh16x32 x (MOVDconst [c])) && uint32(c) < 16 => (SLWconst x [c&31])
|
||||||
(Rsh16x32 x (MOVDconst [c])) && uint32(c) < 16 => (SRAWconst (SignExt16to32 x) [c])
|
(Rsh16x32 x (MOVDconst [c])) && uint32(c) < 16 => (SRAWconst (SignExt16to32 x) [c&15])
|
||||||
(Rsh16Ux32 x (MOVDconst [c])) && uint32(c) < 16 => (SRWconst (ZeroExt16to32 x) [c])
|
(Rsh16Ux32 x (MOVDconst [c])) && uint32(c) < 16 => (SRWconst (ZeroExt16to32 x) [c&15])
|
||||||
(Lsh8x32 x (MOVDconst [c])) && uint32(c) < 8 => (SLWconst x [c])
|
(Lsh8x32 x (MOVDconst [c])) && uint32(c) < 8 => (SLWconst x [c&7])
|
||||||
(Rsh8x32 x (MOVDconst [c])) && uint32(c) < 8 => (SRAWconst (SignExt8to32 x) [c])
|
(Rsh8x32 x (MOVDconst [c])) && uint32(c) < 8 => (SRAWconst (SignExt8to32 x) [c&7])
|
||||||
(Rsh8Ux32 x (MOVDconst [c])) && uint32(c) < 8 => (SRWconst (ZeroExt8to32 x) [c])
|
(Rsh8Ux32 x (MOVDconst [c])) && uint32(c) < 8 => (SRWconst (ZeroExt8to32 x) [c&7])
|
||||||
|
|
||||||
// Lower bounded shifts first. No need to check shift value.
|
// Lower bounded shifts first. No need to check shift value.
|
||||||
(Lsh64x(64|32|16|8) x y) && shiftIsBounded(v) => (SLD x y)
|
(Lsh64x(64|32|16|8) x y) && shiftIsBounded(v) => (SLD x y)
|
||||||
|
@ -285,7 +285,8 @@
|
||||||
(MaskIfNotCarry (FlagCarrySet)) => (MOVDconst [0])
|
(MaskIfNotCarry (FlagCarrySet)) => (MOVDconst [0])
|
||||||
(MaskIfNotCarry (FlagCarryClear)) => (MOVDconst [-1])
|
(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)
|
(Addr {sym} base) => (MOVDaddr {sym} [0] base)
|
||||||
(LocalAddr {sym} base _) => (MOVDaddr {sym} base)
|
(LocalAddr {sym} base _) => (MOVDaddr {sym} base)
|
||||||
|
@ -785,7 +786,7 @@
|
||||||
(FMOVDstore [off] {sym} ptr (MTVSRD x) mem) => (MOVDstore [off] {sym} ptr x mem)
|
(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)
|
(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))])
|
(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)
|
(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: "FMSUB", argLength: 3, reg: fp31, asm: "FMSUB"}, // arg0*arg1 - arg2
|
||||||
{name: "FMSUBS", argLength: 3, reg: fp31, asm: "FMSUBS"}, // 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: "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"}, // arg0 >>a arg1, 32 bits (all sign if arg1 & 32 != 0)
|
{name: "SRAW", argLength: 2, reg: gp21, asm: "SRAW"}, // signed arg0 >> (arg1&63), 32 bit width
|
||||||
{name: "SRD", argLength: 2, reg: gp21, asm: "SRD"}, // arg0 >> arg1, 64 bits (0 if arg1 & 64 != 0)
|
{name: "SRD", argLength: 2, reg: gp21, asm: "SRD"}, // unsigned arg0 >> (arg1&127), 64 bit width
|
||||||
{name: "SRW", argLength: 2, reg: gp21, asm: "SRW"}, // arg0 >> arg1, 32 bits (0 if arg1 & 32 != 0)
|
{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, 64 bits (0 if arg1 & 64 != 0)
|
{name: "SLD", argLength: 2, reg: gp21, asm: "SLD"}, // arg0 << (arg1&127), 64 bit width
|
||||||
{name: "SLW", argLength: 2, reg: gp21, asm: "SLW"}, // arg0 << arg1, 32 bits (0 if arg1 & 32 != 0)
|
{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: "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
|
{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: "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: "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: "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"}, // arg0 >>a aux, 32 bits
|
{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"}, // arg0 >> aux, 64 bits
|
{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"}, // arg0 >> aux, 32 bits
|
{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 << aux, 64 bits
|
{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 << aux, 32 bits
|
{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: "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
|
{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)
|
(Addr {sym} base) => (MOVaddr {sym} [0] base)
|
||||||
(LocalAddr {sym} base _) => (MOVaddr {sym} 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
|
// Calls
|
||||||
(StaticCall ...) => (CALLstatic ...)
|
(StaticCall ...) => (CALLstatic ...)
|
||||||
(ClosureCall ...) => (CALLclosure ...)
|
(ClosureCall ...) => (CALLclosure ...)
|
||||||
|
@ -480,11 +470,31 @@
|
||||||
(AtomicExchange32 ...) => (LoweredAtomicExchange32 ...)
|
(AtomicExchange32 ...) => (LoweredAtomicExchange32 ...)
|
||||||
(AtomicExchange64 ...) => (LoweredAtomicExchange64 ...)
|
(AtomicExchange64 ...) => (LoweredAtomicExchange64 ...)
|
||||||
|
|
||||||
|
// Conditional branches
|
||||||
|
(If cond yes no) => (BNEZ cond yes no)
|
||||||
|
|
||||||
// Optimizations
|
// 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)
|
(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
|
// Store zero
|
||||||
(MOVBstore [off] {sym} ptr (MOVBconst [0]) mem) => (MOVBstorezero [off] {sym} ptr mem)
|
(MOVBstore [off] {sym} ptr (MOVBconst [0]) mem) => (MOVBstorezero [off] {sym} ptr mem)
|
||||||
(MOVHstore [off] {sym} ptr (MOVHconst [0]) mem) => (MOVHstorezero [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: "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: "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: "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: "CFDBRA", argLength: 1, reg: fpgp, asm: "CFDBRA", clobberFlags: true}, // convert float64 to int32
|
||||||
{name: "CFEBRA", argLength: 1, reg: fpgp, asm: "CFEBRA"}, // convert float32 to int32
|
{name: "CGDBRA", argLength: 1, reg: fpgp, asm: "CGDBRA", clobberFlags: true}, // convert float64 to int64
|
||||||
{name: "CGEBRA", argLength: 1, reg: fpgp, asm: "CGEBRA"}, // convert float32 to int64
|
{name: "CFEBRA", argLength: 1, reg: fpgp, asm: "CFEBRA", clobberFlags: true}, // convert float32 to int32
|
||||||
{name: "CEFBRA", argLength: 1, reg: gpfp, asm: "CEFBRA"}, // convert int32 to float32
|
{name: "CGEBRA", argLength: 1, reg: fpgp, asm: "CGEBRA", clobberFlags: true}, // convert float32 to int64
|
||||||
{name: "CDFBRA", argLength: 1, reg: gpfp, asm: "CDFBRA"}, // convert int32 to float64
|
{name: "CEFBRA", argLength: 1, reg: gpfp, asm: "CEFBRA", clobberFlags: true}, // convert int32 to float32
|
||||||
{name: "CEGBRA", argLength: 1, reg: gpfp, asm: "CEGBRA"}, // convert int64 to float32
|
{name: "CDFBRA", argLength: 1, reg: gpfp, asm: "CDFBRA", clobberFlags: true}, // convert int32 to float64
|
||||||
{name: "CDGBRA", argLength: 1, reg: gpfp, asm: "CDGBRA"}, // convert int64 to float64
|
{name: "CEGBRA", argLength: 1, reg: gpfp, asm: "CEGBRA", clobberFlags: true}, // convert int64 to float32
|
||||||
{name: "CLFEBR", argLength: 1, reg: fpgp, asm: "CLFEBR"}, // convert float32 to uint32
|
{name: "CDGBRA", argLength: 1, reg: gpfp, asm: "CDGBRA", clobberFlags: true}, // convert int64 to float64
|
||||||
{name: "CLFDBR", argLength: 1, reg: fpgp, asm: "CLFDBR"}, // convert float64 to uint32
|
{name: "CLFEBR", argLength: 1, reg: fpgp, asm: "CLFEBR", clobberFlags: true}, // convert float32 to uint32
|
||||||
{name: "CLGEBR", argLength: 1, reg: fpgp, asm: "CLGEBR"}, // convert float32 to uint64
|
{name: "CLFDBR", argLength: 1, reg: fpgp, asm: "CLFDBR", clobberFlags: true}, // convert float64 to uint32
|
||||||
{name: "CLGDBR", argLength: 1, reg: fpgp, asm: "CLGDBR"}, // convert float64 to uint64
|
{name: "CLGEBR", argLength: 1, reg: fpgp, asm: "CLGEBR", clobberFlags: true}, // convert float32 to uint64
|
||||||
{name: "CELFBR", argLength: 1, reg: gpfp, asm: "CELFBR"}, // convert uint32 to float32
|
{name: "CLGDBR", argLength: 1, reg: fpgp, asm: "CLGDBR", clobberFlags: true}, // convert float64 to uint64
|
||||||
{name: "CDLFBR", argLength: 1, reg: gpfp, asm: "CDLFBR"}, // convert uint32 to float64
|
{name: "CELFBR", argLength: 1, reg: gpfp, asm: "CELFBR", clobberFlags: true}, // convert uint32 to float32
|
||||||
{name: "CELGBR", argLength: 1, reg: gpfp, asm: "CELGBR"}, // convert uint64 to float32
|
{name: "CDLFBR", argLength: 1, reg: gpfp, asm: "CDLFBR", clobberFlags: true}, // convert uint32 to float64
|
||||||
{name: "CDLGBR", argLength: 1, reg: gpfp, asm: "CDLGBR"}, // convert uint64 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: "LEDBR", argLength: 1, reg: fp11, asm: "LEDBR"}, // convert float64 to float32
|
||||||
{name: "LDEBR", argLength: 1, reg: fp11, asm: "LDEBR"}, // convert float32 to float64
|
{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 {
|
func opHasAuxInt(op opData) bool {
|
||||||
switch op.aux {
|
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 true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -1818,6 +1818,8 @@ func (op opData) auxIntType() string {
|
||||||
return "int64"
|
return "int64"
|
||||||
case "CCop":
|
case "CCop":
|
||||||
return "Op"
|
return "Op"
|
||||||
|
case "FlagConstant":
|
||||||
|
return "flagConstant"
|
||||||
default:
|
default:
|
||||||
return "invalid"
|
return "invalid"
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,6 +77,7 @@ const (
|
||||||
auxInt128 // auxInt represents a 128-bit integer. Always 0.
|
auxInt128 // auxInt represents a 128-bit integer. Always 0.
|
||||||
auxFloat32 // auxInt is a float32 (encoded with math.Float64bits)
|
auxFloat32 // auxInt is a float32 (encoded with math.Float64bits)
|
||||||
auxFloat64 // auxInt is a float64 (encoded with math.Float64bits)
|
auxFloat64 // auxInt is a float64 (encoded with math.Float64bits)
|
||||||
|
auxFlagConstant // auxInt is a flagConstant
|
||||||
auxString // aux is a string
|
auxString // aux is a string
|
||||||
auxSym // aux is a symbol (a *gc.Node for locals, an *obj.LSym for globals, or nil for none)
|
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
|
auxSymOff // aux is a symbol, auxInt is an offset
|
||||||
|
|
|
@ -61,6 +61,10 @@ const (
|
||||||
BlockARMULE
|
BlockARMULE
|
||||||
BlockARMUGT
|
BlockARMUGT
|
||||||
BlockARMUGE
|
BlockARMUGE
|
||||||
|
BlockARMLTnoov
|
||||||
|
BlockARMLEnoov
|
||||||
|
BlockARMGTnoov
|
||||||
|
BlockARMGEnoov
|
||||||
|
|
||||||
BlockARM64EQ
|
BlockARM64EQ
|
||||||
BlockARM64NE
|
BlockARM64NE
|
||||||
|
@ -82,6 +86,10 @@ const (
|
||||||
BlockARM64FLE
|
BlockARM64FLE
|
||||||
BlockARM64FGT
|
BlockARM64FGT
|
||||||
BlockARM64FGE
|
BlockARM64FGE
|
||||||
|
BlockARM64LTnoov
|
||||||
|
BlockARM64LEnoov
|
||||||
|
BlockARM64GTnoov
|
||||||
|
BlockARM64GEnoov
|
||||||
|
|
||||||
BlockMIPSEQ
|
BlockMIPSEQ
|
||||||
BlockMIPSNE
|
BlockMIPSNE
|
||||||
|
@ -181,37 +189,45 @@ var blockString = [...]string{
|
||||||
BlockAMD64ORD: "ORD",
|
BlockAMD64ORD: "ORD",
|
||||||
BlockAMD64NAN: "NAN",
|
BlockAMD64NAN: "NAN",
|
||||||
|
|
||||||
BlockARMEQ: "EQ",
|
BlockARMEQ: "EQ",
|
||||||
BlockARMNE: "NE",
|
BlockARMNE: "NE",
|
||||||
BlockARMLT: "LT",
|
BlockARMLT: "LT",
|
||||||
BlockARMLE: "LE",
|
BlockARMLE: "LE",
|
||||||
BlockARMGT: "GT",
|
BlockARMGT: "GT",
|
||||||
BlockARMGE: "GE",
|
BlockARMGE: "GE",
|
||||||
BlockARMULT: "ULT",
|
BlockARMULT: "ULT",
|
||||||
BlockARMULE: "ULE",
|
BlockARMULE: "ULE",
|
||||||
BlockARMUGT: "UGT",
|
BlockARMUGT: "UGT",
|
||||||
BlockARMUGE: "UGE",
|
BlockARMUGE: "UGE",
|
||||||
|
BlockARMLTnoov: "LTnoov",
|
||||||
|
BlockARMLEnoov: "LEnoov",
|
||||||
|
BlockARMGTnoov: "GTnoov",
|
||||||
|
BlockARMGEnoov: "GEnoov",
|
||||||
|
|
||||||
BlockARM64EQ: "EQ",
|
BlockARM64EQ: "EQ",
|
||||||
BlockARM64NE: "NE",
|
BlockARM64NE: "NE",
|
||||||
BlockARM64LT: "LT",
|
BlockARM64LT: "LT",
|
||||||
BlockARM64LE: "LE",
|
BlockARM64LE: "LE",
|
||||||
BlockARM64GT: "GT",
|
BlockARM64GT: "GT",
|
||||||
BlockARM64GE: "GE",
|
BlockARM64GE: "GE",
|
||||||
BlockARM64ULT: "ULT",
|
BlockARM64ULT: "ULT",
|
||||||
BlockARM64ULE: "ULE",
|
BlockARM64ULE: "ULE",
|
||||||
BlockARM64UGT: "UGT",
|
BlockARM64UGT: "UGT",
|
||||||
BlockARM64UGE: "UGE",
|
BlockARM64UGE: "UGE",
|
||||||
BlockARM64Z: "Z",
|
BlockARM64Z: "Z",
|
||||||
BlockARM64NZ: "NZ",
|
BlockARM64NZ: "NZ",
|
||||||
BlockARM64ZW: "ZW",
|
BlockARM64ZW: "ZW",
|
||||||
BlockARM64NZW: "NZW",
|
BlockARM64NZW: "NZW",
|
||||||
BlockARM64TBZ: "TBZ",
|
BlockARM64TBZ: "TBZ",
|
||||||
BlockARM64TBNZ: "TBNZ",
|
BlockARM64TBNZ: "TBNZ",
|
||||||
BlockARM64FLT: "FLT",
|
BlockARM64FLT: "FLT",
|
||||||
BlockARM64FLE: "FLE",
|
BlockARM64FLE: "FLE",
|
||||||
BlockARM64FGT: "FGT",
|
BlockARM64FGT: "FGT",
|
||||||
BlockARM64FGE: "FGE",
|
BlockARM64FGE: "FGE",
|
||||||
|
BlockARM64LTnoov: "LTnoov",
|
||||||
|
BlockARM64LEnoov: "LEnoov",
|
||||||
|
BlockARM64GTnoov: "GTnoov",
|
||||||
|
BlockARM64GEnoov: "GEnoov",
|
||||||
|
|
||||||
BlockMIPSEQ: "EQ",
|
BlockMIPSEQ: "EQ",
|
||||||
BlockMIPSNE: "NE",
|
BlockMIPSNE: "NE",
|
||||||
|
@ -1267,11 +1283,7 @@ const (
|
||||||
OpARMLoweredPanicExtendA
|
OpARMLoweredPanicExtendA
|
||||||
OpARMLoweredPanicExtendB
|
OpARMLoweredPanicExtendB
|
||||||
OpARMLoweredPanicExtendC
|
OpARMLoweredPanicExtendC
|
||||||
OpARMFlagEQ
|
OpARMFlagConstant
|
||||||
OpARMFlagLT_ULT
|
|
||||||
OpARMFlagLT_UGT
|
|
||||||
OpARMFlagGT_UGT
|
|
||||||
OpARMFlagGT_ULT
|
|
||||||
OpARMInvertFlags
|
OpARMInvertFlags
|
||||||
OpARMLoweredWB
|
OpARMLoweredWB
|
||||||
|
|
||||||
|
@ -1542,11 +1554,7 @@ const (
|
||||||
OpARM64LoweredGetClosurePtr
|
OpARM64LoweredGetClosurePtr
|
||||||
OpARM64LoweredGetCallerSP
|
OpARM64LoweredGetCallerSP
|
||||||
OpARM64LoweredGetCallerPC
|
OpARM64LoweredGetCallerPC
|
||||||
OpARM64FlagEQ
|
OpARM64FlagConstant
|
||||||
OpARM64FlagLT_ULT
|
|
||||||
OpARM64FlagLT_UGT
|
|
||||||
OpARM64FlagGT_UGT
|
|
||||||
OpARM64FlagGT_ULT
|
|
||||||
OpARM64InvertFlags
|
OpARM64InvertFlags
|
||||||
OpARM64LDAR
|
OpARM64LDAR
|
||||||
OpARM64LDARB
|
OpARM64LDARB
|
||||||
|
@ -16895,29 +16903,10 @@ var opcodeTable = [...]opInfo{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "FlagEQ",
|
name: "FlagConstant",
|
||||||
argLen: 0,
|
auxType: auxFlagConstant,
|
||||||
reg: regInfo{},
|
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: "InvertFlags",
|
name: "InvertFlags",
|
||||||
|
@ -20505,29 +20494,10 @@ var opcodeTable = [...]opInfo{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "FlagEQ",
|
name: "FlagConstant",
|
||||||
argLen: 0,
|
auxType: auxFlagConstant,
|
||||||
reg: regInfo{},
|
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: "InvertFlags",
|
name: "InvertFlags",
|
||||||
|
@ -30175,9 +30145,10 @@ var opcodeTable = [...]opInfo{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "CFDBRA",
|
name: "CFDBRA",
|
||||||
argLen: 1,
|
argLen: 1,
|
||||||
asm: s390x.ACFDBRA,
|
clobberFlags: true,
|
||||||
|
asm: s390x.ACFDBRA,
|
||||||
reg: regInfo{
|
reg: regInfo{
|
||||||
inputs: []inputInfo{
|
inputs: []inputInfo{
|
||||||
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
|
{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",
|
name: "CGDBRA",
|
||||||
argLen: 1,
|
argLen: 1,
|
||||||
asm: s390x.ACGDBRA,
|
clobberFlags: true,
|
||||||
|
asm: s390x.ACGDBRA,
|
||||||
reg: regInfo{
|
reg: regInfo{
|
||||||
inputs: []inputInfo{
|
inputs: []inputInfo{
|
||||||
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
|
{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",
|
name: "CFEBRA",
|
||||||
argLen: 1,
|
argLen: 1,
|
||||||
asm: s390x.ACFEBRA,
|
clobberFlags: true,
|
||||||
|
asm: s390x.ACFEBRA,
|
||||||
reg: regInfo{
|
reg: regInfo{
|
||||||
inputs: []inputInfo{
|
inputs: []inputInfo{
|
||||||
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
|
{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",
|
name: "CGEBRA",
|
||||||
argLen: 1,
|
argLen: 1,
|
||||||
asm: s390x.ACGEBRA,
|
clobberFlags: true,
|
||||||
|
asm: s390x.ACGEBRA,
|
||||||
reg: regInfo{
|
reg: regInfo{
|
||||||
inputs: []inputInfo{
|
inputs: []inputInfo{
|
||||||
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
|
{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",
|
name: "CEFBRA",
|
||||||
argLen: 1,
|
argLen: 1,
|
||||||
asm: s390x.ACEFBRA,
|
clobberFlags: true,
|
||||||
|
asm: s390x.ACEFBRA,
|
||||||
reg: regInfo{
|
reg: regInfo{
|
||||||
inputs: []inputInfo{
|
inputs: []inputInfo{
|
||||||
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
|
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
|
||||||
|
@ -30240,9 +30215,10 @@ var opcodeTable = [...]opInfo{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "CDFBRA",
|
name: "CDFBRA",
|
||||||
argLen: 1,
|
argLen: 1,
|
||||||
asm: s390x.ACDFBRA,
|
clobberFlags: true,
|
||||||
|
asm: s390x.ACDFBRA,
|
||||||
reg: regInfo{
|
reg: regInfo{
|
||||||
inputs: []inputInfo{
|
inputs: []inputInfo{
|
||||||
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
|
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
|
||||||
|
@ -30253,9 +30229,10 @@ var opcodeTable = [...]opInfo{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "CEGBRA",
|
name: "CEGBRA",
|
||||||
argLen: 1,
|
argLen: 1,
|
||||||
asm: s390x.ACEGBRA,
|
clobberFlags: true,
|
||||||
|
asm: s390x.ACEGBRA,
|
||||||
reg: regInfo{
|
reg: regInfo{
|
||||||
inputs: []inputInfo{
|
inputs: []inputInfo{
|
||||||
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
|
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
|
||||||
|
@ -30266,9 +30243,10 @@ var opcodeTable = [...]opInfo{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "CDGBRA",
|
name: "CDGBRA",
|
||||||
argLen: 1,
|
argLen: 1,
|
||||||
asm: s390x.ACDGBRA,
|
clobberFlags: true,
|
||||||
|
asm: s390x.ACDGBRA,
|
||||||
reg: regInfo{
|
reg: regInfo{
|
||||||
inputs: []inputInfo{
|
inputs: []inputInfo{
|
||||||
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
|
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
|
||||||
|
@ -30279,9 +30257,10 @@ var opcodeTable = [...]opInfo{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "CLFEBR",
|
name: "CLFEBR",
|
||||||
argLen: 1,
|
argLen: 1,
|
||||||
asm: s390x.ACLFEBR,
|
clobberFlags: true,
|
||||||
|
asm: s390x.ACLFEBR,
|
||||||
reg: regInfo{
|
reg: regInfo{
|
||||||
inputs: []inputInfo{
|
inputs: []inputInfo{
|
||||||
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
|
{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",
|
name: "CLFDBR",
|
||||||
argLen: 1,
|
argLen: 1,
|
||||||
asm: s390x.ACLFDBR,
|
clobberFlags: true,
|
||||||
|
asm: s390x.ACLFDBR,
|
||||||
reg: regInfo{
|
reg: regInfo{
|
||||||
inputs: []inputInfo{
|
inputs: []inputInfo{
|
||||||
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
|
{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",
|
name: "CLGEBR",
|
||||||
argLen: 1,
|
argLen: 1,
|
||||||
asm: s390x.ACLGEBR,
|
clobberFlags: true,
|
||||||
|
asm: s390x.ACLGEBR,
|
||||||
reg: regInfo{
|
reg: regInfo{
|
||||||
inputs: []inputInfo{
|
inputs: []inputInfo{
|
||||||
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
|
{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",
|
name: "CLGDBR",
|
||||||
argLen: 1,
|
argLen: 1,
|
||||||
asm: s390x.ACLGDBR,
|
clobberFlags: true,
|
||||||
|
asm: s390x.ACLGDBR,
|
||||||
reg: regInfo{
|
reg: regInfo{
|
||||||
inputs: []inputInfo{
|
inputs: []inputInfo{
|
||||||
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
|
{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",
|
name: "CELFBR",
|
||||||
argLen: 1,
|
argLen: 1,
|
||||||
asm: s390x.ACELFBR,
|
clobberFlags: true,
|
||||||
|
asm: s390x.ACELFBR,
|
||||||
reg: regInfo{
|
reg: regInfo{
|
||||||
inputs: []inputInfo{
|
inputs: []inputInfo{
|
||||||
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
|
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
|
||||||
|
@ -30344,9 +30327,10 @@ var opcodeTable = [...]opInfo{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "CDLFBR",
|
name: "CDLFBR",
|
||||||
argLen: 1,
|
argLen: 1,
|
||||||
asm: s390x.ACDLFBR,
|
clobberFlags: true,
|
||||||
|
asm: s390x.ACDLFBR,
|
||||||
reg: regInfo{
|
reg: regInfo{
|
||||||
inputs: []inputInfo{
|
inputs: []inputInfo{
|
||||||
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
|
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
|
||||||
|
@ -30357,9 +30341,10 @@ var opcodeTable = [...]opInfo{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "CELGBR",
|
name: "CELGBR",
|
||||||
argLen: 1,
|
argLen: 1,
|
||||||
asm: s390x.ACELGBR,
|
clobberFlags: true,
|
||||||
|
asm: s390x.ACELGBR,
|
||||||
reg: regInfo{
|
reg: regInfo{
|
||||||
inputs: []inputInfo{
|
inputs: []inputInfo{
|
||||||
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
|
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
|
||||||
|
@ -30370,9 +30355,10 @@ var opcodeTable = [...]opInfo{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "CDLGBR",
|
name: "CDLGBR",
|
||||||
argLen: 1,
|
argLen: 1,
|
||||||
asm: s390x.ACDLGBR,
|
clobberFlags: true,
|
||||||
|
asm: s390x.ACDLGBR,
|
||||||
reg: regInfo{
|
reg: regInfo{
|
||||||
inputs: []inputInfo{
|
inputs: []inputInfo{
|
||||||
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
|
{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]
|
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,
|
case OpLsh8x8, OpLsh8x16, OpLsh8x32, OpLsh8x64,
|
||||||
OpLsh16x8, OpLsh16x16, OpLsh16x32, OpLsh16x64,
|
OpLsh16x8, OpLsh16x16, OpLsh16x32, OpLsh16x64,
|
||||||
OpLsh32x8, OpLsh32x16, OpLsh32x32, OpLsh32x64,
|
OpLsh32x8, OpLsh32x16, OpLsh32x32, OpLsh32x64,
|
||||||
OpLsh64x8, OpLsh64x16, OpLsh64x32, OpLsh64x64,
|
OpLsh64x8, OpLsh64x16, OpLsh64x32, OpLsh64x64,
|
||||||
OpRsh8x8, OpRsh8x16, OpRsh8x32, OpRsh8x64,
|
|
||||||
OpRsh16x8, OpRsh16x16, OpRsh16x32, OpRsh16x64,
|
|
||||||
OpRsh32x8, OpRsh32x16, OpRsh32x32, OpRsh32x64,
|
|
||||||
OpRsh64x8, OpRsh64x16, OpRsh64x32, OpRsh64x64,
|
|
||||||
OpRsh8Ux8, OpRsh8Ux16, OpRsh8Ux32, OpRsh8Ux64,
|
OpRsh8Ux8, OpRsh8Ux16, OpRsh8Ux32, OpRsh8Ux64,
|
||||||
OpRsh16Ux8, OpRsh16Ux16, OpRsh16Ux32, OpRsh16Ux64,
|
OpRsh16Ux8, OpRsh16Ux16, OpRsh16Ux32, OpRsh16Ux64,
|
||||||
OpRsh32Ux8, OpRsh32Ux16, OpRsh32Ux32, OpRsh32Ux64,
|
OpRsh32Ux8, OpRsh32Ux16, OpRsh32Ux32, OpRsh32Ux64,
|
||||||
|
|
|
@ -511,6 +511,14 @@ func b2i(b bool) int64 {
|
||||||
return 0
|
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.
|
// 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.
|
// A shift is bounded if it is shifting by less than the width of the shifted value.
|
||||||
func shiftIsBounded(v *Value) bool {
|
func shiftIsBounded(v *Value) bool {
|
||||||
|
@ -616,6 +624,9 @@ func auxIntToInt128(x int64) int128 {
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
func auxIntToFlagConstant(x int64) flagConstant {
|
||||||
|
return flagConstant(x)
|
||||||
|
}
|
||||||
|
|
||||||
func boolToAuxInt(b bool) int64 {
|
func boolToAuxInt(b bool) int64 {
|
||||||
if b {
|
if b {
|
||||||
|
@ -653,6 +664,9 @@ func int128ToAuxInt(x int128) int64 {
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
func flagConstantToAuxInt(x flagConstant) int64 {
|
||||||
|
return int64(x)
|
||||||
|
}
|
||||||
|
|
||||||
func auxToString(i interface{}) string {
|
func auxToString(i interface{}) string {
|
||||||
return i.(string)
|
return i.(string)
|
||||||
|
@ -997,52 +1011,42 @@ func arm64Invert(op Op) Op {
|
||||||
func ccARM64Eval(cc interface{}, flags *Value) int {
|
func ccARM64Eval(cc interface{}, flags *Value) int {
|
||||||
op := cc.(Op)
|
op := cc.(Op)
|
||||||
fop := flags.Op
|
fop := flags.Op
|
||||||
switch fop {
|
if fop == OpARM64InvertFlags {
|
||||||
case OpARM64InvertFlags:
|
|
||||||
return -ccARM64Eval(op, flags.Args[0])
|
return -ccARM64Eval(op, flags.Args[0])
|
||||||
case OpARM64FlagEQ:
|
}
|
||||||
switch op {
|
if fop != OpARM64FlagConstant {
|
||||||
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:
|
|
||||||
return 0
|
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
|
// 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
|
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
|
typ := &b.Func.Config.Types
|
||||||
// match: (Lsh16x32 x (MOVDconst [c]))
|
// match: (Lsh16x32 x (MOVDconst [c]))
|
||||||
// cond: uint32(c) < 16
|
// cond: uint32(c) < 16
|
||||||
// result: (SLWconst x [c])
|
// result: (SLWconst x [c&31])
|
||||||
for {
|
for {
|
||||||
x := v_0
|
x := v_0
|
||||||
if v_1.Op != OpPPC64MOVDconst {
|
if v_1.Op != OpPPC64MOVDconst {
|
||||||
|
@ -2362,7 +2362,7 @@ func rewriteValuePPC64_OpLsh16x32(v *Value) bool {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
v.reset(OpPPC64SLWconst)
|
v.reset(OpPPC64SLWconst)
|
||||||
v.AuxInt = int64ToAuxInt(c)
|
v.AuxInt = int64ToAuxInt(c & 31)
|
||||||
v.AddArg(x)
|
v.AddArg(x)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -2552,7 +2552,7 @@ func rewriteValuePPC64_OpLsh32x32(v *Value) bool {
|
||||||
typ := &b.Func.Config.Types
|
typ := &b.Func.Config.Types
|
||||||
// match: (Lsh32x32 x (MOVDconst [c]))
|
// match: (Lsh32x32 x (MOVDconst [c]))
|
||||||
// cond: uint32(c) < 32
|
// cond: uint32(c) < 32
|
||||||
// result: (SLWconst x [c])
|
// result: (SLWconst x [c&31])
|
||||||
for {
|
for {
|
||||||
x := v_0
|
x := v_0
|
||||||
if v_1.Op != OpPPC64MOVDconst {
|
if v_1.Op != OpPPC64MOVDconst {
|
||||||
|
@ -2563,7 +2563,7 @@ func rewriteValuePPC64_OpLsh32x32(v *Value) bool {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
v.reset(OpPPC64SLWconst)
|
v.reset(OpPPC64SLWconst)
|
||||||
v.AuxInt = int64ToAuxInt(c)
|
v.AuxInt = int64ToAuxInt(c & 31)
|
||||||
v.AddArg(x)
|
v.AddArg(x)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -2792,7 +2792,7 @@ func rewriteValuePPC64_OpLsh64x32(v *Value) bool {
|
||||||
typ := &b.Func.Config.Types
|
typ := &b.Func.Config.Types
|
||||||
// match: (Lsh64x32 x (MOVDconst [c]))
|
// match: (Lsh64x32 x (MOVDconst [c]))
|
||||||
// cond: uint32(c) < 64
|
// cond: uint32(c) < 64
|
||||||
// result: (SLDconst x [c])
|
// result: (SLDconst x [c&63])
|
||||||
for {
|
for {
|
||||||
x := v_0
|
x := v_0
|
||||||
if v_1.Op != OpPPC64MOVDconst {
|
if v_1.Op != OpPPC64MOVDconst {
|
||||||
|
@ -2803,7 +2803,7 @@ func rewriteValuePPC64_OpLsh64x32(v *Value) bool {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
v.reset(OpPPC64SLDconst)
|
v.reset(OpPPC64SLDconst)
|
||||||
v.AuxInt = int64ToAuxInt(c)
|
v.AuxInt = int64ToAuxInt(c & 63)
|
||||||
v.AddArg(x)
|
v.AddArg(x)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -3032,7 +3032,7 @@ func rewriteValuePPC64_OpLsh8x32(v *Value) bool {
|
||||||
typ := &b.Func.Config.Types
|
typ := &b.Func.Config.Types
|
||||||
// match: (Lsh8x32 x (MOVDconst [c]))
|
// match: (Lsh8x32 x (MOVDconst [c]))
|
||||||
// cond: uint32(c) < 8
|
// cond: uint32(c) < 8
|
||||||
// result: (SLWconst x [c])
|
// result: (SLWconst x [c&7])
|
||||||
for {
|
for {
|
||||||
x := v_0
|
x := v_0
|
||||||
if v_1.Op != OpPPC64MOVDconst {
|
if v_1.Op != OpPPC64MOVDconst {
|
||||||
|
@ -3043,7 +3043,7 @@ func rewriteValuePPC64_OpLsh8x32(v *Value) bool {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
v.reset(OpPPC64SLWconst)
|
v.reset(OpPPC64SLWconst)
|
||||||
v.AuxInt = int64ToAuxInt(c)
|
v.AuxInt = int64ToAuxInt(c & 7)
|
||||||
v.AddArg(x)
|
v.AddArg(x)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -10314,12 +10314,16 @@ func rewriteValuePPC64_OpPPC64MTVSRD(v *Value) bool {
|
||||||
b := v.Block
|
b := v.Block
|
||||||
typ := &b.Func.Config.Types
|
typ := &b.Func.Config.Types
|
||||||
// match: (MTVSRD (MOVDconst [c]))
|
// match: (MTVSRD (MOVDconst [c]))
|
||||||
|
// cond: !math.IsNaN(math.Float64frombits(uint64(c)))
|
||||||
// result: (FMOVDconst [math.Float64frombits(uint64(c))])
|
// result: (FMOVDconst [math.Float64frombits(uint64(c))])
|
||||||
for {
|
for {
|
||||||
if v_0.Op != OpPPC64MOVDconst {
|
if v_0.Op != OpPPC64MOVDconst {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
c := auxIntToInt64(v_0.AuxInt)
|
c := auxIntToInt64(v_0.AuxInt)
|
||||||
|
if !(!math.IsNaN(math.Float64frombits(uint64(c)))) {
|
||||||
|
break
|
||||||
|
}
|
||||||
v.reset(OpPPC64FMOVDconst)
|
v.reset(OpPPC64FMOVDconst)
|
||||||
v.AuxInt = float64ToAuxInt(math.Float64frombits(uint64(c)))
|
v.AuxInt = float64ToAuxInt(math.Float64frombits(uint64(c)))
|
||||||
return true
|
return true
|
||||||
|
@ -12042,7 +12046,7 @@ func rewriteValuePPC64_OpPPC64SLD(v *Value) bool {
|
||||||
v_1 := v.Args[1]
|
v_1 := v.Args[1]
|
||||||
v_0 := v.Args[0]
|
v_0 := v.Args[0]
|
||||||
// match: (SLD x (MOVDconst [c]))
|
// match: (SLD x (MOVDconst [c]))
|
||||||
// result: (SLDconst [c] x)
|
// result: (SLDconst [c&63 | (c>>6&1*63)] x)
|
||||||
for {
|
for {
|
||||||
x := v_0
|
x := v_0
|
||||||
if v_1.Op != OpPPC64MOVDconst {
|
if v_1.Op != OpPPC64MOVDconst {
|
||||||
|
@ -12050,7 +12054,7 @@ func rewriteValuePPC64_OpPPC64SLD(v *Value) bool {
|
||||||
}
|
}
|
||||||
c := auxIntToInt64(v_1.AuxInt)
|
c := auxIntToInt64(v_1.AuxInt)
|
||||||
v.reset(OpPPC64SLDconst)
|
v.reset(OpPPC64SLDconst)
|
||||||
v.AuxInt = int64ToAuxInt(c)
|
v.AuxInt = int64ToAuxInt(c&63 | (c >> 6 & 1 * 63))
|
||||||
v.AddArg(x)
|
v.AddArg(x)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -12060,7 +12064,7 @@ func rewriteValuePPC64_OpPPC64SLW(v *Value) bool {
|
||||||
v_1 := v.Args[1]
|
v_1 := v.Args[1]
|
||||||
v_0 := v.Args[0]
|
v_0 := v.Args[0]
|
||||||
// match: (SLW x (MOVDconst [c]))
|
// match: (SLW x (MOVDconst [c]))
|
||||||
// result: (SLWconst [c] x)
|
// result: (SLWconst [c&31 | (c>>5&1*31)] x)
|
||||||
for {
|
for {
|
||||||
x := v_0
|
x := v_0
|
||||||
if v_1.Op != OpPPC64MOVDconst {
|
if v_1.Op != OpPPC64MOVDconst {
|
||||||
|
@ -12068,7 +12072,7 @@ func rewriteValuePPC64_OpPPC64SLW(v *Value) bool {
|
||||||
}
|
}
|
||||||
c := auxIntToInt64(v_1.AuxInt)
|
c := auxIntToInt64(v_1.AuxInt)
|
||||||
v.reset(OpPPC64SLWconst)
|
v.reset(OpPPC64SLWconst)
|
||||||
v.AuxInt = int64ToAuxInt(c)
|
v.AuxInt = int64ToAuxInt(c&31 | (c >> 5 & 1 * 31))
|
||||||
v.AddArg(x)
|
v.AddArg(x)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -12078,7 +12082,7 @@ func rewriteValuePPC64_OpPPC64SRAD(v *Value) bool {
|
||||||
v_1 := v.Args[1]
|
v_1 := v.Args[1]
|
||||||
v_0 := v.Args[0]
|
v_0 := v.Args[0]
|
||||||
// match: (SRAD x (MOVDconst [c]))
|
// match: (SRAD x (MOVDconst [c]))
|
||||||
// result: (SRADconst [c] x)
|
// result: (SRADconst [c&63 | (c>>6&1*63)] x)
|
||||||
for {
|
for {
|
||||||
x := v_0
|
x := v_0
|
||||||
if v_1.Op != OpPPC64MOVDconst {
|
if v_1.Op != OpPPC64MOVDconst {
|
||||||
|
@ -12086,7 +12090,7 @@ func rewriteValuePPC64_OpPPC64SRAD(v *Value) bool {
|
||||||
}
|
}
|
||||||
c := auxIntToInt64(v_1.AuxInt)
|
c := auxIntToInt64(v_1.AuxInt)
|
||||||
v.reset(OpPPC64SRADconst)
|
v.reset(OpPPC64SRADconst)
|
||||||
v.AuxInt = int64ToAuxInt(c)
|
v.AuxInt = int64ToAuxInt(c&63 | (c >> 6 & 1 * 63))
|
||||||
v.AddArg(x)
|
v.AddArg(x)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -12096,7 +12100,7 @@ func rewriteValuePPC64_OpPPC64SRAW(v *Value) bool {
|
||||||
v_1 := v.Args[1]
|
v_1 := v.Args[1]
|
||||||
v_0 := v.Args[0]
|
v_0 := v.Args[0]
|
||||||
// match: (SRAW x (MOVDconst [c]))
|
// match: (SRAW x (MOVDconst [c]))
|
||||||
// result: (SRAWconst [c] x)
|
// result: (SRAWconst [c&31 | (c>>5&1*31)] x)
|
||||||
for {
|
for {
|
||||||
x := v_0
|
x := v_0
|
||||||
if v_1.Op != OpPPC64MOVDconst {
|
if v_1.Op != OpPPC64MOVDconst {
|
||||||
|
@ -12104,7 +12108,7 @@ func rewriteValuePPC64_OpPPC64SRAW(v *Value) bool {
|
||||||
}
|
}
|
||||||
c := auxIntToInt64(v_1.AuxInt)
|
c := auxIntToInt64(v_1.AuxInt)
|
||||||
v.reset(OpPPC64SRAWconst)
|
v.reset(OpPPC64SRAWconst)
|
||||||
v.AuxInt = int64ToAuxInt(c)
|
v.AuxInt = int64ToAuxInt(c&31 | (c >> 5 & 1 * 31))
|
||||||
v.AddArg(x)
|
v.AddArg(x)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -12114,7 +12118,7 @@ func rewriteValuePPC64_OpPPC64SRD(v *Value) bool {
|
||||||
v_1 := v.Args[1]
|
v_1 := v.Args[1]
|
||||||
v_0 := v.Args[0]
|
v_0 := v.Args[0]
|
||||||
// match: (SRD x (MOVDconst [c]))
|
// match: (SRD x (MOVDconst [c]))
|
||||||
// result: (SRDconst [c] x)
|
// result: (SRDconst [c&63 | (c>>6&1*63)] x)
|
||||||
for {
|
for {
|
||||||
x := v_0
|
x := v_0
|
||||||
if v_1.Op != OpPPC64MOVDconst {
|
if v_1.Op != OpPPC64MOVDconst {
|
||||||
|
@ -12122,7 +12126,7 @@ func rewriteValuePPC64_OpPPC64SRD(v *Value) bool {
|
||||||
}
|
}
|
||||||
c := auxIntToInt64(v_1.AuxInt)
|
c := auxIntToInt64(v_1.AuxInt)
|
||||||
v.reset(OpPPC64SRDconst)
|
v.reset(OpPPC64SRDconst)
|
||||||
v.AuxInt = int64ToAuxInt(c)
|
v.AuxInt = int64ToAuxInt(c&63 | (c >> 6 & 1 * 63))
|
||||||
v.AddArg(x)
|
v.AddArg(x)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -12132,7 +12136,7 @@ func rewriteValuePPC64_OpPPC64SRW(v *Value) bool {
|
||||||
v_1 := v.Args[1]
|
v_1 := v.Args[1]
|
||||||
v_0 := v.Args[0]
|
v_0 := v.Args[0]
|
||||||
// match: (SRW x (MOVDconst [c]))
|
// match: (SRW x (MOVDconst [c]))
|
||||||
// result: (SRWconst [c] x)
|
// result: (SRWconst [c&31 | (c>>5&1*31)] x)
|
||||||
for {
|
for {
|
||||||
x := v_0
|
x := v_0
|
||||||
if v_1.Op != OpPPC64MOVDconst {
|
if v_1.Op != OpPPC64MOVDconst {
|
||||||
|
@ -12140,7 +12144,7 @@ func rewriteValuePPC64_OpPPC64SRW(v *Value) bool {
|
||||||
}
|
}
|
||||||
c := auxIntToInt64(v_1.AuxInt)
|
c := auxIntToInt64(v_1.AuxInt)
|
||||||
v.reset(OpPPC64SRWconst)
|
v.reset(OpPPC64SRWconst)
|
||||||
v.AuxInt = int64ToAuxInt(c)
|
v.AuxInt = int64ToAuxInt(c&31 | (c >> 5 & 1 * 31))
|
||||||
v.AddArg(x)
|
v.AddArg(x)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -12626,7 +12630,7 @@ func rewriteValuePPC64_OpRsh16Ux32(v *Value) bool {
|
||||||
typ := &b.Func.Config.Types
|
typ := &b.Func.Config.Types
|
||||||
// match: (Rsh16Ux32 x (MOVDconst [c]))
|
// match: (Rsh16Ux32 x (MOVDconst [c]))
|
||||||
// cond: uint32(c) < 16
|
// cond: uint32(c) < 16
|
||||||
// result: (SRWconst (ZeroExt16to32 x) [c])
|
// result: (SRWconst (ZeroExt16to32 x) [c&15])
|
||||||
for {
|
for {
|
||||||
x := v_0
|
x := v_0
|
||||||
if v_1.Op != OpPPC64MOVDconst {
|
if v_1.Op != OpPPC64MOVDconst {
|
||||||
|
@ -12637,7 +12641,7 @@ func rewriteValuePPC64_OpRsh16Ux32(v *Value) bool {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
v.reset(OpPPC64SRWconst)
|
v.reset(OpPPC64SRWconst)
|
||||||
v.AuxInt = int64ToAuxInt(c)
|
v.AuxInt = int64ToAuxInt(c & 15)
|
||||||
v0 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
|
v0 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
|
||||||
v0.AddArg(x)
|
v0.AddArg(x)
|
||||||
v.AddArg(v0)
|
v.AddArg(v0)
|
||||||
|
@ -12847,7 +12851,7 @@ func rewriteValuePPC64_OpRsh16x32(v *Value) bool {
|
||||||
typ := &b.Func.Config.Types
|
typ := &b.Func.Config.Types
|
||||||
// match: (Rsh16x32 x (MOVDconst [c]))
|
// match: (Rsh16x32 x (MOVDconst [c]))
|
||||||
// cond: uint32(c) < 16
|
// cond: uint32(c) < 16
|
||||||
// result: (SRAWconst (SignExt16to32 x) [c])
|
// result: (SRAWconst (SignExt16to32 x) [c&15])
|
||||||
for {
|
for {
|
||||||
x := v_0
|
x := v_0
|
||||||
if v_1.Op != OpPPC64MOVDconst {
|
if v_1.Op != OpPPC64MOVDconst {
|
||||||
|
@ -12858,7 +12862,7 @@ func rewriteValuePPC64_OpRsh16x32(v *Value) bool {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
v.reset(OpPPC64SRAWconst)
|
v.reset(OpPPC64SRAWconst)
|
||||||
v.AuxInt = int64ToAuxInt(c)
|
v.AuxInt = int64ToAuxInt(c & 15)
|
||||||
v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
|
v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
|
||||||
v0.AddArg(x)
|
v0.AddArg(x)
|
||||||
v.AddArg(v0)
|
v.AddArg(v0)
|
||||||
|
@ -13068,7 +13072,7 @@ func rewriteValuePPC64_OpRsh32Ux32(v *Value) bool {
|
||||||
typ := &b.Func.Config.Types
|
typ := &b.Func.Config.Types
|
||||||
// match: (Rsh32Ux32 x (MOVDconst [c]))
|
// match: (Rsh32Ux32 x (MOVDconst [c]))
|
||||||
// cond: uint32(c) < 32
|
// cond: uint32(c) < 32
|
||||||
// result: (SRWconst x [c])
|
// result: (SRWconst x [c&31])
|
||||||
for {
|
for {
|
||||||
x := v_0
|
x := v_0
|
||||||
if v_1.Op != OpPPC64MOVDconst {
|
if v_1.Op != OpPPC64MOVDconst {
|
||||||
|
@ -13079,7 +13083,7 @@ func rewriteValuePPC64_OpRsh32Ux32(v *Value) bool {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
v.reset(OpPPC64SRWconst)
|
v.reset(OpPPC64SRWconst)
|
||||||
v.AuxInt = int64ToAuxInt(c)
|
v.AuxInt = int64ToAuxInt(c & 31)
|
||||||
v.AddArg(x)
|
v.AddArg(x)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -13373,7 +13377,7 @@ func rewriteValuePPC64_OpRsh32x32(v *Value) bool {
|
||||||
typ := &b.Func.Config.Types
|
typ := &b.Func.Config.Types
|
||||||
// match: (Rsh32x32 x (MOVDconst [c]))
|
// match: (Rsh32x32 x (MOVDconst [c]))
|
||||||
// cond: uint32(c) < 32
|
// cond: uint32(c) < 32
|
||||||
// result: (SRAWconst x [c])
|
// result: (SRAWconst x [c&31])
|
||||||
for {
|
for {
|
||||||
x := v_0
|
x := v_0
|
||||||
if v_1.Op != OpPPC64MOVDconst {
|
if v_1.Op != OpPPC64MOVDconst {
|
||||||
|
@ -13384,7 +13388,7 @@ func rewriteValuePPC64_OpRsh32x32(v *Value) bool {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
v.reset(OpPPC64SRAWconst)
|
v.reset(OpPPC64SRAWconst)
|
||||||
v.AuxInt = int64ToAuxInt(c)
|
v.AuxInt = int64ToAuxInt(c & 31)
|
||||||
v.AddArg(x)
|
v.AddArg(x)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -13680,7 +13684,7 @@ func rewriteValuePPC64_OpRsh64Ux32(v *Value) bool {
|
||||||
typ := &b.Func.Config.Types
|
typ := &b.Func.Config.Types
|
||||||
// match: (Rsh64Ux32 x (MOVDconst [c]))
|
// match: (Rsh64Ux32 x (MOVDconst [c]))
|
||||||
// cond: uint32(c) < 64
|
// cond: uint32(c) < 64
|
||||||
// result: (SRDconst x [c])
|
// result: (SRDconst x [c&63])
|
||||||
for {
|
for {
|
||||||
x := v_0
|
x := v_0
|
||||||
if v_1.Op != OpPPC64MOVDconst {
|
if v_1.Op != OpPPC64MOVDconst {
|
||||||
|
@ -13691,7 +13695,7 @@ func rewriteValuePPC64_OpRsh64Ux32(v *Value) bool {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
v.reset(OpPPC64SRDconst)
|
v.reset(OpPPC64SRDconst)
|
||||||
v.AuxInt = int64ToAuxInt(c)
|
v.AuxInt = int64ToAuxInt(c & 63)
|
||||||
v.AddArg(x)
|
v.AddArg(x)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -13985,7 +13989,7 @@ func rewriteValuePPC64_OpRsh64x32(v *Value) bool {
|
||||||
typ := &b.Func.Config.Types
|
typ := &b.Func.Config.Types
|
||||||
// match: (Rsh64x32 x (MOVDconst [c]))
|
// match: (Rsh64x32 x (MOVDconst [c]))
|
||||||
// cond: uint32(c) < 64
|
// cond: uint32(c) < 64
|
||||||
// result: (SRADconst x [c])
|
// result: (SRADconst x [c&63])
|
||||||
for {
|
for {
|
||||||
x := v_0
|
x := v_0
|
||||||
if v_1.Op != OpPPC64MOVDconst {
|
if v_1.Op != OpPPC64MOVDconst {
|
||||||
|
@ -13996,7 +14000,7 @@ func rewriteValuePPC64_OpRsh64x32(v *Value) bool {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
v.reset(OpPPC64SRADconst)
|
v.reset(OpPPC64SRADconst)
|
||||||
v.AuxInt = int64ToAuxInt(c)
|
v.AuxInt = int64ToAuxInt(c & 63)
|
||||||
v.AddArg(x)
|
v.AddArg(x)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -14296,7 +14300,7 @@ func rewriteValuePPC64_OpRsh8Ux32(v *Value) bool {
|
||||||
typ := &b.Func.Config.Types
|
typ := &b.Func.Config.Types
|
||||||
// match: (Rsh8Ux32 x (MOVDconst [c]))
|
// match: (Rsh8Ux32 x (MOVDconst [c]))
|
||||||
// cond: uint32(c) < 8
|
// cond: uint32(c) < 8
|
||||||
// result: (SRWconst (ZeroExt8to32 x) [c])
|
// result: (SRWconst (ZeroExt8to32 x) [c&7])
|
||||||
for {
|
for {
|
||||||
x := v_0
|
x := v_0
|
||||||
if v_1.Op != OpPPC64MOVDconst {
|
if v_1.Op != OpPPC64MOVDconst {
|
||||||
|
@ -14307,7 +14311,7 @@ func rewriteValuePPC64_OpRsh8Ux32(v *Value) bool {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
v.reset(OpPPC64SRWconst)
|
v.reset(OpPPC64SRWconst)
|
||||||
v.AuxInt = int64ToAuxInt(c)
|
v.AuxInt = int64ToAuxInt(c & 7)
|
||||||
v0 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
|
v0 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
|
||||||
v0.AddArg(x)
|
v0.AddArg(x)
|
||||||
v.AddArg(v0)
|
v.AddArg(v0)
|
||||||
|
@ -14517,7 +14521,7 @@ func rewriteValuePPC64_OpRsh8x32(v *Value) bool {
|
||||||
typ := &b.Func.Config.Types
|
typ := &b.Func.Config.Types
|
||||||
// match: (Rsh8x32 x (MOVDconst [c]))
|
// match: (Rsh8x32 x (MOVDconst [c]))
|
||||||
// cond: uint32(c) < 8
|
// cond: uint32(c) < 8
|
||||||
// result: (SRAWconst (SignExt8to32 x) [c])
|
// result: (SRAWconst (SignExt8to32 x) [c&7])
|
||||||
for {
|
for {
|
||||||
x := v_0
|
x := v_0
|
||||||
if v_1.Op != OpPPC64MOVDconst {
|
if v_1.Op != OpPPC64MOVDconst {
|
||||||
|
@ -14528,7 +14532,7 @@ func rewriteValuePPC64_OpRsh8x32(v *Value) bool {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
v.reset(OpPPC64SRAWconst)
|
v.reset(OpPPC64SRAWconst)
|
||||||
v.AuxInt = int64ToAuxInt(c)
|
v.AuxInt = int64ToAuxInt(c & 7)
|
||||||
v0 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
|
v0 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
|
||||||
v0.AddArg(x)
|
v0.AddArg(x)
|
||||||
v.AddArg(v0)
|
v.AddArg(v0)
|
||||||
|
|
|
@ -5120,7 +5120,105 @@ func rewriteValueRISCV64_OpZeroExt8to64(v *Value) bool {
|
||||||
}
|
}
|
||||||
func rewriteBlockRISCV64(b *Block) bool {
|
func rewriteBlockRISCV64(b *Block) bool {
|
||||||
switch b.Kind {
|
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:
|
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)
|
// match: (BNEZ (SNEZ x) yes no)
|
||||||
// result: (BNEZ x yes no)
|
// result: (BNEZ x yes no)
|
||||||
for b.Controls[0].Op == OpRISCV64SNEZ {
|
for b.Controls[0].Op == OpRISCV64SNEZ {
|
||||||
|
@ -5129,6 +5227,33 @@ func rewriteBlockRISCV64(b *Block) bool {
|
||||||
b.resetWithControl(BlockRISCV64BNEZ, x)
|
b.resetWithControl(BlockRISCV64BNEZ, x)
|
||||||
return true
|
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:
|
case BlockIf:
|
||||||
// match: (If cond yes no)
|
// match: (If cond yes no)
|
||||||
// result: (BNEZ 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))
|
return fmt.Sprintf(" {%s}", v.Aux.(Op))
|
||||||
case auxS390XCCMask, auxS390XRotateParams:
|
case auxS390XCCMask, auxS390XRotateParams:
|
||||||
return fmt.Sprintf(" {%v}", v.Aux)
|
return fmt.Sprintf(" {%v}", v.Aux)
|
||||||
|
case auxFlagConstant:
|
||||||
|
return fmt.Sprintf("[%s]", flagConstant(v.AuxInt))
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
|
@ -885,11 +885,11 @@ var blockJump = [...]struct {
|
||||||
ssa.Block386NAN: {x86.AJPS, x86.AJPC},
|
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.AJPS, Index: 1}}, // next == b.Succs[0]
|
||||||
{{Jump: x86.AJNE, Index: 1}, {Jump: x86.AJPC, Index: 0}}, // next == b.Succs[1]
|
{{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.AJPC, Index: 1}}, // next == b.Succs[0]
|
||||||
{{Jump: x86.AJNE, Index: 0}, {Jump: x86.AJPS, Index: 0}}, // next == b.Succs[1]
|
{{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)
|
p.To.Sym = b.Aux.(*obj.LSym)
|
||||||
|
|
||||||
case ssa.Block386EQF:
|
case ssa.Block386EQF:
|
||||||
s.FPJump(b, next, &eqfJumps)
|
s.CombJump(b, next, &eqfJumps)
|
||||||
|
|
||||||
case ssa.Block386NEF:
|
case ssa.Block386NEF:
|
||||||
s.FPJump(b, next, &nefJumps)
|
s.CombJump(b, next, &nefJumps)
|
||||||
|
|
||||||
case ssa.Block386EQ, ssa.Block386NE,
|
case ssa.Block386EQ, ssa.Block386NE,
|
||||||
ssa.Block386LT, ssa.Block386GE,
|
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
|
goos string
|
||||||
goarm string
|
goarm string
|
||||||
go386 string
|
go386 string
|
||||||
goamd64 string
|
|
||||||
gomips string
|
gomips string
|
||||||
gomips64 string
|
gomips64 string
|
||||||
goppc64 string
|
goppc64 string
|
||||||
|
@ -152,12 +151,6 @@ func xinit() {
|
||||||
}
|
}
|
||||||
go386 = b
|
go386 = b
|
||||||
|
|
||||||
b = os.Getenv("GOAMD64")
|
|
||||||
if b == "" {
|
|
||||||
b = "alignedjumps"
|
|
||||||
}
|
|
||||||
goamd64 = b
|
|
||||||
|
|
||||||
b = os.Getenv("GOMIPS")
|
b = os.Getenv("GOMIPS")
|
||||||
if b == "" {
|
if b == "" {
|
||||||
b = "hardfloat"
|
b = "hardfloat"
|
||||||
|
@ -230,7 +223,6 @@ func xinit() {
|
||||||
|
|
||||||
// For tools being invoked but also for os.ExpandEnv.
|
// For tools being invoked but also for os.ExpandEnv.
|
||||||
os.Setenv("GO386", go386)
|
os.Setenv("GO386", go386)
|
||||||
os.Setenv("GOAMD64", goamd64)
|
|
||||||
os.Setenv("GOARCH", goarch)
|
os.Setenv("GOARCH", goarch)
|
||||||
os.Setenv("GOARM", goarm)
|
os.Setenv("GOARM", goarm)
|
||||||
os.Setenv("GOHOSTARCH", gohostarch)
|
os.Setenv("GOHOSTARCH", gohostarch)
|
||||||
|
@ -1171,9 +1163,6 @@ func cmdenv() {
|
||||||
if goarch == "386" {
|
if goarch == "386" {
|
||||||
xprintf(format, "GO386", go386)
|
xprintf(format, "GO386", go386)
|
||||||
}
|
}
|
||||||
if goarch == "amd64" {
|
|
||||||
xprintf(format, "GOAMD64", goamd64)
|
|
||||||
}
|
|
||||||
if goarch == "mips" || goarch == "mipsle" {
|
if goarch == "mips" || goarch == "mipsle" {
|
||||||
xprintf(format, "GOMIPS", gomips)
|
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 defaultGOROOT = <goroot>
|
||||||
// const defaultGO386 = <go386>
|
// const defaultGO386 = <go386>
|
||||||
// const defaultGOAMD64 = <goamd64>
|
|
||||||
// const defaultGOARM = <goarm>
|
// const defaultGOARM = <goarm>
|
||||||
// const defaultGOMIPS = <gomips>
|
// const defaultGOMIPS = <gomips>
|
||||||
// const defaultGOMIPS64 = <gomips64>
|
// const defaultGOMIPS64 = <gomips64>
|
||||||
|
@ -72,7 +71,6 @@ func mkzbootstrap(file string) {
|
||||||
fmt.Fprintf(&buf, "import \"runtime\"\n")
|
fmt.Fprintf(&buf, "import \"runtime\"\n")
|
||||||
fmt.Fprintln(&buf)
|
fmt.Fprintln(&buf)
|
||||||
fmt.Fprintf(&buf, "const defaultGO386 = `%s`\n", go386)
|
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 defaultGOARM = `%s`\n", goarm)
|
||||||
fmt.Fprintf(&buf, "const defaultGOMIPS = `%s`\n", gomips)
|
fmt.Fprintf(&buf, "const defaultGOMIPS = `%s`\n", gomips)
|
||||||
fmt.Fprintf(&buf, "const defaultGOMIPS64 = `%s`\n", gomips64)
|
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.
|
// These must not be copied into the bootstrap build directory.
|
||||||
var ignoreSuffixes = []string{
|
var ignoreSuffixes = []string{
|
||||||
"_arm64.s",
|
"_arm64.s",
|
||||||
|
"_arm64_test.s",
|
||||||
"_arm64.go",
|
"_arm64.go",
|
||||||
"_riscv64.s",
|
"_riscv64.s",
|
||||||
"_riscv64.go",
|
"_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
|
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 {
|
for _, name := range t.runNames {
|
||||||
if !t.isRegisteredTestName(name) {
|
if !t.isRegisteredTestName(name) {
|
||||||
fatalf("unknown test %q", 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 {
|
if t.race {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,13 +9,14 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
register(eglFix)
|
register(eglFixDisplay)
|
||||||
|
register(eglFixConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
var eglFix = fix{
|
var eglFixDisplay = fix{
|
||||||
name: "egl",
|
name: "egl",
|
||||||
date: "2018-12-15",
|
date: "2018-12-15",
|
||||||
f: eglfix,
|
f: eglfixDisp,
|
||||||
desc: `Fixes initializers of EGLDisplay`,
|
desc: `Fixes initializers of EGLDisplay`,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
|
@ -25,8 +26,27 @@ var eglFix = fix{
|
||||||
// New state:
|
// New state:
|
||||||
// type EGLDisplay uintptr
|
// type EGLDisplay uintptr
|
||||||
// This fix finds nils initializing these types and replaces the nils with 0s.
|
// 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 typefix(f, func(s string) bool {
|
||||||
return s == "C.EGLDisplay"
|
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
|
package main
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
addTestCases(eglTests, eglfix)
|
addTestCases(eglTestsFor("EGLDisplay"), eglfixDisp)
|
||||||
|
addTestCases(eglTestsFor("EGLConfig"), eglfixConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
var eglTests = []testCase{
|
func eglTestsFor(tname string) []testCase {
|
||||||
{
|
var eglTests = []testCase{
|
||||||
Name: "egl.localVariable",
|
{
|
||||||
In: `package main
|
Name: "egl.localVariable",
|
||||||
|
In: `package main
|
||||||
|
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
func f() {
|
func f() {
|
||||||
var x C.EGLDisplay = nil
|
var x C.$EGLTYPE = nil
|
||||||
x = nil
|
x = nil
|
||||||
x, x = nil, nil
|
x, x = nil, nil
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
Out: `package main
|
Out: `package main
|
||||||
|
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
func f() {
|
func f() {
|
||||||
var x C.EGLDisplay = 0
|
var x C.$EGLTYPE = 0
|
||||||
x = 0
|
x = 0
|
||||||
x, x = 0, 0
|
x, x = 0, 0
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "egl.globalVariable",
|
Name: "egl.globalVariable",
|
||||||
In: `package main
|
In: `package main
|
||||||
|
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
var x C.EGLDisplay = nil
|
var x C.$EGLTYPE = nil
|
||||||
|
|
||||||
func f() {
|
func f() {
|
||||||
x = nil
|
x = nil
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
Out: `package main
|
Out: `package main
|
||||||
|
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
var x C.EGLDisplay = 0
|
var x C.$EGLTYPE = 0
|
||||||
|
|
||||||
func f() {
|
func f() {
|
||||||
x = 0
|
x = 0
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "egl.EqualArgument",
|
Name: "egl.EqualArgument",
|
||||||
In: `package main
|
In: `package main
|
||||||
|
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
var x C.EGLDisplay
|
var x C.$EGLTYPE
|
||||||
var y = x == nil
|
var y = x == nil
|
||||||
var z = x != nil
|
var z = x != nil
|
||||||
`,
|
`,
|
||||||
Out: `package main
|
Out: `package main
|
||||||
|
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
var x C.EGLDisplay
|
var x C.$EGLTYPE
|
||||||
var y = x == 0
|
var y = x == 0
|
||||||
var z = x != 0
|
var z = x != 0
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "egl.StructField",
|
Name: "egl.StructField",
|
||||||
In: `package main
|
In: `package main
|
||||||
|
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
type T struct {
|
type T struct {
|
||||||
x C.EGLDisplay
|
x C.$EGLTYPE
|
||||||
}
|
}
|
||||||
|
|
||||||
var t = T{x: nil}
|
var t = T{x: nil}
|
||||||
`,
|
`,
|
||||||
Out: `package main
|
Out: `package main
|
||||||
|
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
type T struct {
|
type T struct {
|
||||||
x C.EGLDisplay
|
x C.$EGLTYPE
|
||||||
}
|
}
|
||||||
|
|
||||||
var t = T{x: 0}
|
var t = T{x: 0}
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "egl.FunctionArgument",
|
Name: "egl.FunctionArgument",
|
||||||
In: `package main
|
In: `package main
|
||||||
|
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
func f(x C.EGLDisplay) {
|
func f(x C.$EGLTYPE) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func g() {
|
func g() {
|
||||||
f(nil)
|
f(nil)
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
Out: `package main
|
Out: `package main
|
||||||
|
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
func f(x C.EGLDisplay) {
|
func f(x C.$EGLTYPE) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func g() {
|
func g() {
|
||||||
f(0)
|
f(0)
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "egl.ArrayElement",
|
Name: "egl.ArrayElement",
|
||||||
In: `package main
|
In: `package main
|
||||||
|
|
||||||
import "C"
|
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"
|
import "C"
|
||||||
|
|
||||||
var x = [3]C.EGLDisplay{0, 0, 0}
|
var x = [3]C.$EGLTYPE{0, 0, 0}
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "egl.SliceElement",
|
Name: "egl.SliceElement",
|
||||||
In: `package main
|
In: `package main
|
||||||
|
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
var x = []C.EGLDisplay{nil, nil, nil}
|
var x = []C.$EGLTYPE{nil, nil, nil}
|
||||||
`,
|
`,
|
||||||
Out: `package main
|
Out: `package main
|
||||||
|
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
var x = []C.EGLDisplay{0, 0, 0}
|
var x = []C.$EGLTYPE{0, 0, 0}
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "egl.MapKey",
|
Name: "egl.MapKey",
|
||||||
In: `package main
|
In: `package main
|
||||||
|
|
||||||
import "C"
|
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"
|
import "C"
|
||||||
|
|
||||||
var x = map[C.EGLDisplay]int{0: 0}
|
var x = map[C.$EGLTYPE]int{0: 0}
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "egl.MapValue",
|
Name: "egl.MapValue",
|
||||||
In: `package main
|
In: `package main
|
||||||
|
|
||||||
import "C"
|
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"
|
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 (
|
require (
|
||||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3
|
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340 // indirect
|
github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340 // indirect
|
||||||
golang.org/x/arch v0.0.0-20200312215426-ff8b605520f4
|
golang.org/x/arch v0.0.0-20200511175325-f7c78586839d
|
||||||
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
|
||||||
golang.org/x/mod v0.2.1-0.20200429172858-859b3ef565e2
|
golang.org/x/mod v0.3.0
|
||||||
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 // indirect
|
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 h1:S1+yTUaFPXuDZnPDbO+TrDFIjPzQraYH8/CwSlu9Fac=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
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=
|
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-20200511175325-f7c78586839d h1:YvwchuJby5xEAPdBGmdAVSiVME50C+RJfJJwJJsGEV8=
|
||||||
golang.org/x/arch v0.0.0-20200312215426-ff8b605520f4/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
|
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-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-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-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||||
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
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.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.2.1-0.20200429172858-859b3ef565e2 h1:VUsRDZIYpMs3R7PyYeN7BSbDfYjhxaX6HlWvM5iAEqs=
|
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
|
||||||
golang.org/x/mod v0.2.1-0.20200429172858-859b3ef565e2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
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-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-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=
|
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/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/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-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-20200616133436-c1934b75d054 h1:HHeAlu5H9b71C+Fx0K+1dGgVFN1DM1/wz4aoGOA5qS8=
|
||||||
golang.org/x/tools v0.0.0-20200504152539-33427f1b0364/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
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-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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
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
|
// 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
|
// 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
|
// binary. Only a high-confidence subset of the default go vet checks are
|
||||||
// used. That subset is: 'atomic', 'bool', 'buildtags', 'nilfunc', and
|
// used. That subset is: 'atomic', 'bool', 'buildtags', 'errorsas',
|
||||||
// 'printf'. You can see the documentation for these and other vet tests
|
// 'ifaceassert', 'nilfunc', 'printf', and 'stringintconv'. You can see
|
||||||
// via "go doc cmd/vet". To disable the running of go vet, use the
|
// the documentation for these and other vet tests via "go doc cmd/vet".
|
||||||
// -vet=off flag.
|
// 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
|
// 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
|
// standard output, even if the test printed them to its own standard
|
||||||
|
@ -1480,56 +1480,91 @@
|
||||||
//
|
//
|
||||||
// Build constraints
|
// Build constraints
|
||||||
//
|
//
|
||||||
// Build constraints describe the conditions under which each source file
|
// A build constraint, also known as a build tag, is a line comment that begins
|
||||||
// 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:
|
|
||||||
//
|
//
|
||||||
// // +build
|
// // +build
|
||||||
//
|
//
|
||||||
// and follows with a space-separated list of options on the same line.
|
// that lists the conditions under which a file should be included in the package.
|
||||||
// The constraint is evaluated as the OR of the options.
|
// 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 option evaluates as the AND of its comma-separated terms.
|
||||||
// Each term consists of letters, digits, underscores, and dots.
|
// 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:
|
// 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:
|
// A file may have multiple build constraints. The overall constraint is the AND
|
||||||
// - the target operating system and architecture, as spelled by
|
// of the individual constraints. That is, the build constraints:
|
||||||
// runtime.GOOS and runtime.GOARCH respectively
|
//
|
||||||
// - the compiler being used, either "gc" or "gccgo"
|
// // +build linux darwin
|
||||||
// - "cgo", if the cgo command is supported
|
// // +build amd64
|
||||||
// (see CGO_ENABLED in 'go help environment')
|
//
|
||||||
// - a term for each Go major release, through the current version:
|
// corresponds to the boolean formula:
|
||||||
// "go1.1" from Go version 1.1 onward,
|
//
|
||||||
// "go1.2" from Go version 1.2 onward, and so on
|
// (linux OR darwin) AND amd64
|
||||||
// - and any additional tags given by the '-tags' flag (see 'go help build').
|
//
|
||||||
|
// 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,
|
// 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
|
// matches any of the following patterns:
|
||||||
// GOOS or GOARCH value, then the file is implicitly constrained to that
|
// *_GOOS
|
||||||
// specific GOOS and/or GOARCH, in addition to any other build constraints
|
// *_GOARCH
|
||||||
// declared as comments within the file.
|
// *_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
|
// Build modes
|
||||||
|
@ -1754,9 +1789,6 @@
|
||||||
// GO386
|
// GO386
|
||||||
// For GOARCH=386, the floating point instruction set.
|
// For GOARCH=386, the floating point instruction set.
|
||||||
// Valid values are 387, sse2.
|
// 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
|
// GOMIPS
|
||||||
// For GOARCH=mips{,le}, whether to use floating point instructions.
|
// For GOARCH=mips{,le}, whether to use floating point instructions.
|
||||||
// Valid values are hardfloat (default), softfloat.
|
// Valid values are hardfloat (default), softfloat.
|
||||||
|
|
|
@ -6,7 +6,6 @@ package main_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
|
||||||
"debug/elf"
|
"debug/elf"
|
||||||
"debug/macho"
|
"debug/macho"
|
||||||
"debug/pe"
|
"debug/pe"
|
||||||
|
@ -114,12 +113,6 @@ var testGo string
|
||||||
var testTmpDir string
|
var testTmpDir string
|
||||||
var testBin 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
|
// The TestMain function creates a go command for testing purposes and
|
||||||
// deletes it after the tests have been run.
|
// deletes it after the tests have been run.
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
@ -131,23 +124,9 @@ func TestMain(m *testing.M) {
|
||||||
fmt.Printf("SKIP\n")
|
fmt.Printf("SKIP\n")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
os.Unsetenv("GOROOT_FINAL")
|
|
||||||
|
|
||||||
flag.Parse()
|
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 != "" {
|
if *proxyAddr != "" {
|
||||||
StartProxy()
|
StartProxy()
|
||||||
select {}
|
select {}
|
||||||
|
@ -200,6 +179,11 @@ func TestMain(m *testing.M) {
|
||||||
}
|
}
|
||||||
testGOROOT = goEnv("GOROOT")
|
testGOROOT = goEnv("GOROOT")
|
||||||
os.Setenv("TESTGO_GOROOT", testGOROOT)
|
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
|
// The whole GOROOT/pkg tree was installed using the GOHOSTOS/GOHOSTARCH
|
||||||
// toolchain (installed in GOROOT/pkg/tool/GOHOSTOS_GOHOSTARCH).
|
// toolchain (installed in GOROOT/pkg/tool/GOHOSTOS_GOHOSTARCH).
|
||||||
|
@ -236,8 +220,10 @@ func TestMain(m *testing.M) {
|
||||||
}
|
}
|
||||||
testCC = strings.TrimSpace(string(out))
|
testCC = strings.TrimSpace(string(out))
|
||||||
|
|
||||||
if out, err := exec.Command(testGo, "env", "CGO_ENABLED").Output(); err != nil {
|
cmd := exec.Command(testGo, "env", "CGO_ENABLED")
|
||||||
fmt.Fprintf(os.Stderr, "running testgo failed: %v\n", err)
|
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
|
canRun = false
|
||||||
} else {
|
} else {
|
||||||
canCgo, err = strconv.ParseBool(strings.TrimSpace(string(out)))
|
canCgo, err = strconv.ParseBool(strings.TrimSpace(string(out)))
|
||||||
|
@ -829,10 +815,9 @@ func removeAll(dir string) error {
|
||||||
// module cache has 0444 directories;
|
// module cache has 0444 directories;
|
||||||
// make them writable in order to remove content.
|
// make them writable in order to remove content.
|
||||||
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
||||||
if err != nil {
|
// chmod not only directories, but also things that we couldn't even stat
|
||||||
return nil // ignore errors walking in file system
|
// due to permission errors: they may also be unreadable directories.
|
||||||
}
|
if err != nil || info.IsDir() {
|
||||||
if info.IsDir() {
|
|
||||||
os.Chmod(path, 0777)
|
os.Chmod(path, 0777)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -241,7 +241,6 @@ var (
|
||||||
// Used in envcmd.MkEnv and build ID computations.
|
// Used in envcmd.MkEnv and build ID computations.
|
||||||
GOARM = envOr("GOARM", fmt.Sprint(objabi.GOARM))
|
GOARM = envOr("GOARM", fmt.Sprint(objabi.GOARM))
|
||||||
GO386 = envOr("GO386", objabi.GO386)
|
GO386 = envOr("GO386", objabi.GO386)
|
||||||
GOAMD64 = envOr("GOAMD64", objabi.GOAMD64)
|
|
||||||
GOMIPS = envOr("GOMIPS", objabi.GOMIPS)
|
GOMIPS = envOr("GOMIPS", objabi.GOMIPS)
|
||||||
GOMIPS64 = envOr("GOMIPS64", objabi.GOMIPS64)
|
GOMIPS64 = envOr("GOMIPS64", objabi.GOMIPS64)
|
||||||
GOPPC64 = envOr("GOPPC64", fmt.Sprintf("%s%d", "power", objabi.GOPPC64))
|
GOPPC64 = envOr("GOPPC64", fmt.Sprintf("%s%d", "power", objabi.GOPPC64))
|
||||||
|
@ -267,8 +266,6 @@ func GetArchEnv() (key, val string) {
|
||||||
return "GOARM", GOARM
|
return "GOARM", GOARM
|
||||||
case "386":
|
case "386":
|
||||||
return "GO386", GO386
|
return "GO386", GO386
|
||||||
case "amd64":
|
|
||||||
return "GOAMD64", GOAMD64
|
|
||||||
case "mips", "mipsle":
|
case "mips", "mipsle":
|
||||||
return "GOMIPS", GOMIPS
|
return "GOMIPS", GOMIPS
|
||||||
case "mips64", "mips64le":
|
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