mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.link] all: merge branch 'master' into dev.link
NOT apply CL 238779, which is for sym.Symbols. Clean merge other than that. Change-Id: I535e9580fcf7d6f382bd684c3d53f11f90d0b6ed
This commit is contained in:
commit
5e526e67e7
70 changed files with 2089 additions and 2929 deletions
3
AUTHORS
3
AUTHORS
|
|
@ -934,7 +934,7 @@ Maya Rashish <maya@netbsd.org>
|
|||
Mayank Kumar <krmayankk@gmail.com>
|
||||
MediaMath, Inc
|
||||
Meir Fischer <meirfischer@gmail.com>
|
||||
Meng Zhuo <mengzhuo1203@gmail.com>
|
||||
Meng Zhuo <mengzhuo1203@gmail.com> <mzh@golangcn.org>
|
||||
Meteor Development Group
|
||||
Mhd Sulhan <m.shulhan@gmail.com>
|
||||
Micah Stetson <micah.stetson@gmail.com>
|
||||
|
|
@ -1044,6 +1044,7 @@ Niels Widger <niels.widger@gmail.com>
|
|||
Nigel Kerr <nigel.kerr@gmail.com>
|
||||
Nik Nyby <nnyby@columbia.edu>
|
||||
Nikhil Benesch <nikhil.benesch@gmail.com>
|
||||
Nikita Gillmann <nikita@n0.is> <ng0@n0.is>
|
||||
Niklas Schnelle <niklas.schnelle@gmail.com>
|
||||
Niko Dziemba <niko@dziemba.com>
|
||||
Nikolay Turpitko <nikolay@turpitko.com>
|
||||
|
|
|
|||
|
|
@ -1501,7 +1501,7 @@ Maxwell Krohn <themax@gmail.com>
|
|||
Maya Rashish <maya@NetBSD.org>
|
||||
Mayank Kumar <krmayankk@gmail.com>
|
||||
Meir Fischer <meirfischer@gmail.com>
|
||||
Meng Zhuo <mengzhuo1203@gmail.com>
|
||||
Meng Zhuo <mengzhuo1203@gmail.com> <mzh@golangcn.org>
|
||||
Mhd Sulhan <m.shulhan@gmail.com>
|
||||
Micah Stetson <micah.stetson@gmail.com>
|
||||
Michael Anthony Knyszek <mknyszek@google.com>
|
||||
|
|
@ -1654,6 +1654,7 @@ Nigel Kerr <nigel.kerr@gmail.com>
|
|||
Nigel Tao <nigeltao@golang.org>
|
||||
Nik Nyby <nnyby@columbia.edu>
|
||||
Nikhil Benesch <nikhil.benesch@gmail.com>
|
||||
Nikita Gillmann <nikita@n0.is> <ng0@n0.is>
|
||||
Nikita Kryuchkov <nkryuchkov10@gmail.com>
|
||||
Nikita Vanyasin <nikita.vanyasin@gmail.com>
|
||||
Niklas Schnelle <niklas.schnelle@gmail.com>
|
||||
|
|
|
|||
|
|
@ -79,15 +79,13 @@ release.
|
|||
<h2 id="Source_code">Source code</h2>
|
||||
|
||||
<p>
|
||||
If you cannot use a release, or prefer to build gccgo for
|
||||
yourself,
|
||||
the gccgo source code is accessible via Subversion. The
|
||||
GCC web site
|
||||
has <a href="https://gcc.gnu.org/svn.html">instructions for getting the
|
||||
GCC source code</a>. The gccgo source code is included. As a
|
||||
convenience, a stable version of the Go support is available in
|
||||
a branch of the main GCC code
|
||||
repository: <code>svn://gcc.gnu.org/svn/gcc/branches/gccgo</code>.
|
||||
If you cannot use a release, or prefer to build gccgo for yourself, the
|
||||
gccgo source code is accessible via Git. The GCC web site has
|
||||
<a href="https://gcc.gnu.org/git.html">instructions for getting the GCC
|
||||
source code</a>. The gccgo source code is included. As a convenience, a
|
||||
stable version of the Go support is available in the
|
||||
<code>devel/gccgo</code> branch of the main GCC code repository:
|
||||
<code>git://gcc.gnu.org/git/gcc.git</code>.
|
||||
This branch is periodically updated with stable Go compiler sources.
|
||||
</p>
|
||||
|
||||
|
|
@ -139,13 +137,10 @@ which you have write access):
|
|||
</p>
|
||||
|
||||
<pre>
|
||||
cvs -z 9 -d :pserver:anoncvs@sourceware.org:/cvs/src login
|
||||
[password is "anoncvs"]
|
||||
[The next command will create a directory named src, not binutils]
|
||||
cvs -z 9 -d :pserver:anoncvs@sourceware.org:/cvs/src co binutils
|
||||
git clone git://sourceware.org/git/binutils-gdb.git
|
||||
mkdir binutils-objdir
|
||||
cd binutils-objdir
|
||||
../src/configure --enable-gold=default --prefix=/opt/gold
|
||||
../binutils-gdb/configure --enable-gold=default --prefix=/opt/gold
|
||||
make
|
||||
make install
|
||||
</pre>
|
||||
|
|
@ -176,7 +171,7 @@ described above):
|
|||
</p>
|
||||
|
||||
<pre>
|
||||
svn checkout svn://gcc.gnu.org/svn/gcc/branches/gccgo gccgo
|
||||
git clone --branch devel/gccgo git://gcc.gnu.org/git/gcc.git gccgo
|
||||
mkdir objdir
|
||||
cd objdir
|
||||
../gccgo/configure --prefix=/opt/gccgo --enable-languages=c,c++,go --with-ld=/opt/gold/bin/ld
|
||||
|
|
|
|||
|
|
@ -50,8 +50,8 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
<h3 id="windows">Windows</h3>
|
||||
|
||||
<p> <!-- CL 214397 and CL 230217 -->
|
||||
Go 1.15 now generates Windows ASLR executables when -buildmode=pie
|
||||
cmd/link flag is provided. Go command uses -buildmode=pie by default
|
||||
Go 1.15 now generates Windows ASLR executables when <code>-buildmode=pie</code>
|
||||
cmd/link flag is provided. Go command uses <code>-buildmode=pie</code> by default
|
||||
on Windows.
|
||||
</p>
|
||||
|
||||
|
|
@ -145,7 +145,7 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
<a href="https://golang.org/issue/36568">issue #36568</a>). The workaround is
|
||||
not enabled by default because it is not safe to use when Go versions lower
|
||||
than 1.14.2 and 1.13.10 are running concurrently with the same module cache.
|
||||
It can be enabled by explictly setting the environment variable
|
||||
It can be enabled by explicitly setting the environment variable
|
||||
<code>GODEBUG=modcacheunzipinplace=1</code>.
|
||||
</p>
|
||||
|
||||
|
|
@ -313,7 +313,8 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
<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 running on <code>amd64</code> architectures, with more modest
|
||||
OSes (Linux, FreeBSD, NetBSD, OpenBSD, Dragonfly, and Solaris)
|
||||
running on <code>amd64</code> architectures, with more modest
|
||||
improvements for other architecture/OS combinations.
|
||||
</p>
|
||||
|
||||
|
|
@ -374,24 +375,27 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
in mind.
|
||||
</p>
|
||||
|
||||
<dl id="debug/pe"><dt><a href="/pkg/debug/pe/">debug/pe</a></dt>
|
||||
<dl id="bufio"><dt><a href="/pkg/bufio/">bufio</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><!-- 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><!-- debug/pe -->
|
||||
</dl><!-- bufio -->
|
||||
|
||||
<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
|
||||
<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
|
||||
|
|
@ -551,6 +555,46 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
</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/json"><dt><a href="/pkg/encoding/json/">encoding/json</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 191783 -->
|
||||
|
|
@ -604,6 +648,16 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
</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 -->
|
||||
|
|
@ -633,7 +687,7 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
<code>Conn.SetReadDeadline</code>,
|
||||
or <code>Conn.SetWriteDeadline</code> methods, it will now
|
||||
return an error that is or wraps
|
||||
<a href="/pkg/os#ErrDeadlineExceeded"><code>os.ErrDeadlineExceeded</code></a>.
|
||||
<a href="/pkg/os/#ErrDeadlineExceeded"><code>os.ErrDeadlineExceeded</code></a>.
|
||||
This may be used to reliably detect whether an error is due to
|
||||
an exceeded deadline.
|
||||
Earlier releases recommended calling the <code>Timeout</code>
|
||||
|
|
@ -712,7 +766,7 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
<a href="/pkg/os/#File.SetReadDeadline"><code>File.SetReadDeadline</code></a>,
|
||||
or <a href="/pkg/os/#File.SetWriteDeadline"><code>File.SetWriteDeadline</code></a>
|
||||
methods, it will now return an error that is or wraps
|
||||
<a href="/pkg/os#ErrDeadlineExceeded"><code>os.ErrDeadlineExceeded</code></a>.
|
||||
<a href="/pkg/os/#ErrDeadlineExceeded"><code>os.ErrDeadlineExceeded</code></a>.
|
||||
This may be used to reliably detect whether an error is due to
|
||||
an exceeded deadline.
|
||||
Earlier releases recommended calling the <code>Timeout</code>
|
||||
|
|
@ -778,7 +832,7 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="pkg-runtime-pprof"><dt><a href="/pkg/runtime/pprof">runtime/pprof</a></dt>
|
||||
<dl id="pkg-runtime-pprof"><dt><a href="/pkg/runtime/pprof/">runtime/pprof</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 189318 -->
|
||||
The goroutine profile includes the profile labels associated with each goroutine
|
||||
|
|
@ -797,7 +851,7 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
<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 specificed precision. <code>ParseComplex</code> accepts complex numbers in the format <code>N+Ni</code>.
|
||||
<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 -->
|
||||
|
|
|
|||
12
misc/cgo/testgodefs/testdata/issue39534.go
vendored
Normal file
12
misc/cgo/testgodefs/testdata/issue39534.go
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
// enum { ENUMVAL = 0x1 };
|
||||
import "C"
|
||||
|
||||
const ENUMVAL = C.ENUMVAL
|
||||
|
|
@ -24,6 +24,7 @@ var filePrefixes = []string{
|
|||
"issue37479",
|
||||
"issue37621",
|
||||
"issue38649",
|
||||
"issue39534",
|
||||
}
|
||||
|
||||
func TestGoDefs(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -558,8 +558,8 @@ func (r *negativeEOFReader) Read(p []byte) (int, error) {
|
|||
return -1, io.EOF
|
||||
}
|
||||
|
||||
// Test that the scanner doesn't panic on a reader that returns a
|
||||
// negative count of bytes read (issue 38053).
|
||||
// Test that the scanner doesn't panic and returns ErrBadReadCount
|
||||
// on a reader that returns a negative count of bytes read (issue 38053).
|
||||
func TestNegativeEOFReader(t *testing.T) {
|
||||
r := negativeEOFReader(10)
|
||||
scanner := NewScanner(&r)
|
||||
|
|
@ -571,8 +571,8 @@ func TestNegativeEOFReader(t *testing.T) {
|
|||
break
|
||||
}
|
||||
}
|
||||
if scanner.Err() == nil {
|
||||
t.Error("scanner.Err returned nil, expected an error")
|
||||
if got, want := scanner.Err(), ErrBadReadCount; got != want {
|
||||
t.Errorf("scanner.Err: got %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -584,11 +584,13 @@ func (largeReader) Read(p []byte) (int, error) {
|
|||
return len(p) + 1, nil
|
||||
}
|
||||
|
||||
// Test that the scanner doesn't panic and returns ErrBadReadCount
|
||||
// on a reader that returns an impossibly large count of bytes read (issue 38053).
|
||||
func TestLargeReader(t *testing.T) {
|
||||
scanner := NewScanner(largeReader{})
|
||||
for scanner.Scan() {
|
||||
}
|
||||
if scanner.Err() == nil {
|
||||
t.Error("scanner.Err returned nil, expected an error")
|
||||
if got, want := scanner.Err(), ErrBadReadCount; got != want {
|
||||
t.Errorf("scanner.Err: got %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1354,7 +1354,7 @@ func (p *Package) rewriteRef(f *File) {
|
|||
|
||||
if *godefs {
|
||||
// Substitute definition for mangled type name.
|
||||
if r.Name.Type != nil {
|
||||
if r.Name.Type != nil && r.Name.Kind == "type" {
|
||||
expr = r.Name.Type.Go
|
||||
}
|
||||
if id, ok := expr.(*ast.Ident); ok {
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ var knownFormats = map[string]string{
|
|||
"cmd/compile/internal/ssa.Sym %v": "",
|
||||
"cmd/compile/internal/ssa.ValAndOff %s": "",
|
||||
"cmd/compile/internal/ssa.domain %v": "",
|
||||
"cmd/compile/internal/ssa.flagConstant %s": "",
|
||||
"cmd/compile/internal/ssa.posetNode %v": "",
|
||||
"cmd/compile/internal/ssa.posetTestOp %v": "",
|
||||
"cmd/compile/internal/ssa.rbrank %d": "",
|
||||
|
|
|
|||
|
|
@ -857,12 +857,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
|||
p := s.Prog(obj.AGETCALLERPC)
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = v.Reg()
|
||||
case ssa.OpARMFlagEQ,
|
||||
ssa.OpARMFlagLT_ULT,
|
||||
ssa.OpARMFlagLT_UGT,
|
||||
ssa.OpARMFlagGT_ULT,
|
||||
ssa.OpARMFlagGT_UGT:
|
||||
v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString())
|
||||
case ssa.OpARMFlagConstant:
|
||||
v.Fatalf("FlagConstant op should never make it to codegen %v", v.LongString())
|
||||
case ssa.OpARMInvertFlags:
|
||||
v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
|
||||
case ssa.OpClobber:
|
||||
|
|
|
|||
|
|
@ -943,12 +943,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
|||
p := s.Prog(obj.AGETCALLERPC)
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = v.Reg()
|
||||
case ssa.OpARM64FlagEQ,
|
||||
ssa.OpARM64FlagLT_ULT,
|
||||
ssa.OpARM64FlagLT_UGT,
|
||||
ssa.OpARM64FlagGT_ULT,
|
||||
ssa.OpARM64FlagGT_UGT:
|
||||
v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString())
|
||||
case ssa.OpARM64FlagConstant:
|
||||
v.Fatalf("FlagConstant op should never make it to codegen %v", v.LongString())
|
||||
case ssa.OpARM64InvertFlags:
|
||||
v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
|
||||
case ssa.OpClobber:
|
||||
|
|
|
|||
|
|
@ -63,6 +63,26 @@ func IncomparableField(t *types.Type) *types.Field {
|
|||
return nil
|
||||
}
|
||||
|
||||
// EqCanPanic reports whether == on type t could panic (has an interface somewhere).
|
||||
// t must be comparable.
|
||||
func EqCanPanic(t *types.Type) bool {
|
||||
switch t.Etype {
|
||||
default:
|
||||
return false
|
||||
case TINTER:
|
||||
return true
|
||||
case TARRAY:
|
||||
return EqCanPanic(t.Elem())
|
||||
case TSTRUCT:
|
||||
for _, f := range t.FieldSlice() {
|
||||
if !f.Sym.IsBlank() && EqCanPanic(f.Type) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// algtype is like algtype1, except it returns the fixed-width AMEMxx variants
|
||||
// instead of the general AMEM kind when possible.
|
||||
func algtype(t *types.Type) AlgKind {
|
||||
|
|
@ -624,14 +644,19 @@ func geneq(t *types.Type) *obj.LSym {
|
|||
|
||||
case TSTRUCT:
|
||||
// Build a list of conditions to satisfy.
|
||||
// Track their order so that we can preserve aspects of that order.
|
||||
// The conditions are a list-of-lists. Conditions are reorderable
|
||||
// within each inner list. The outer lists must be evaluated in order.
|
||||
// Even within each inner list, track their order so that we can preserve
|
||||
// aspects of that order. (TODO: latter part needed?)
|
||||
type nodeIdx struct {
|
||||
n *Node
|
||||
idx int
|
||||
}
|
||||
var conds []nodeIdx
|
||||
var conds [][]nodeIdx
|
||||
conds = append(conds, []nodeIdx{})
|
||||
and := func(n *Node) {
|
||||
conds = append(conds, nodeIdx{n: n, idx: len(conds)})
|
||||
i := len(conds) - 1
|
||||
conds[i] = append(conds[i], nodeIdx{n: n, idx: len(conds[i])})
|
||||
}
|
||||
|
||||
// Walk the struct using memequal for runs of AMEM
|
||||
|
|
@ -647,6 +672,10 @@ func geneq(t *types.Type) *obj.LSym {
|
|||
|
||||
// Compare non-memory fields with field equality.
|
||||
if !IsRegularMemory(f.Type) {
|
||||
if EqCanPanic(f.Type) {
|
||||
// Enforce ordering by starting a new set of reorderable conditions.
|
||||
conds = append(conds, []nodeIdx{})
|
||||
}
|
||||
p := nodSym(OXDOT, np, f.Sym)
|
||||
q := nodSym(OXDOT, nq, f.Sym)
|
||||
switch {
|
||||
|
|
@ -657,6 +686,10 @@ func geneq(t *types.Type) *obj.LSym {
|
|||
default:
|
||||
and(nod(OEQ, p, q))
|
||||
}
|
||||
if EqCanPanic(f.Type) {
|
||||
// Also enforce ordering after something that can panic.
|
||||
conds = append(conds, []nodeIdx{})
|
||||
}
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
|
@ -680,20 +713,24 @@ func geneq(t *types.Type) *obj.LSym {
|
|||
|
||||
// Sort conditions to put runtime calls last.
|
||||
// Preserve the rest of the ordering.
|
||||
sort.SliceStable(conds, func(i, j int) bool {
|
||||
x, y := conds[i], conds[j]
|
||||
var flatConds []nodeIdx
|
||||
for _, c := range conds {
|
||||
sort.SliceStable(c, func(i, j int) bool {
|
||||
x, y := c[i], c[j]
|
||||
if (x.n.Op != OCALL) == (y.n.Op != OCALL) {
|
||||
return x.idx < y.idx
|
||||
}
|
||||
return x.n.Op != OCALL
|
||||
})
|
||||
flatConds = append(flatConds, c...)
|
||||
}
|
||||
|
||||
var cond *Node
|
||||
if len(conds) == 0 {
|
||||
if len(flatConds) == 0 {
|
||||
cond = nodbool(true)
|
||||
} else {
|
||||
cond = conds[0].n
|
||||
for _, c := range conds[1:] {
|
||||
cond = flatConds[0].n
|
||||
for _, c := range flatConds[1:] {
|
||||
cond = nod(OANDAND, cond, c.n)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -680,8 +680,9 @@ func (lv *Liveness) pointerMap(liveout bvec, vars []*Node, args, locals bvec) {
|
|||
}
|
||||
}
|
||||
|
||||
// markUnsafePoints finds unsafe points and computes lv.unsafePoints.
|
||||
func (lv *Liveness) markUnsafePoints() {
|
||||
// allUnsafe indicates that all points in this function are
|
||||
// unsafe-points.
|
||||
func allUnsafe(f *ssa.Func) bool {
|
||||
// The runtime assumes the only safe-points are function
|
||||
// prologues (because that's how it used to be). We could and
|
||||
// should improve that, but for now keep consider all points
|
||||
|
|
@ -691,7 +692,12 @@ func (lv *Liveness) markUnsafePoints() {
|
|||
// go:nosplit functions are similar. Since safe points used to
|
||||
// be coupled with stack checks, go:nosplit often actually
|
||||
// means "no safe points in this function".
|
||||
if compiling_runtime || lv.f.NoSplit {
|
||||
return compiling_runtime || f.NoSplit
|
||||
}
|
||||
|
||||
// markUnsafePoints finds unsafe points and computes lv.unsafePoints.
|
||||
func (lv *Liveness) markUnsafePoints() {
|
||||
if allUnsafe(lv.f) {
|
||||
// No complex analysis necessary.
|
||||
lv.allUnsafe = true
|
||||
return
|
||||
|
|
|
|||
|
|
@ -6010,8 +6010,8 @@ func genssa(f *ssa.Func, pp *Progs) {
|
|||
// for an empty block this will be used for its control
|
||||
// instruction. We won't use the actual liveness map on a
|
||||
// control instruction. Just mark it something that is
|
||||
// preemptible.
|
||||
s.pp.nextLive = LivenessIndex{-1, -1, false}
|
||||
// preemptible, unless this function is "all unsafe".
|
||||
s.pp.nextLive = LivenessIndex{-1, -1, allUnsafe(f)}
|
||||
|
||||
// Emit values in block
|
||||
thearch.SSAMarkMoves(&s, b)
|
||||
|
|
|
|||
|
|
@ -185,6 +185,11 @@ func checkFunc(f *Func) {
|
|||
f.Fatalf("bad type %T for S390XRotateParams in %v", v.Aux, v)
|
||||
}
|
||||
canHaveAux = true
|
||||
case auxFlagConstant:
|
||||
if v.AuxInt < 0 || v.AuxInt > 15 {
|
||||
f.Fatalf("bad FlagConstant AuxInt value for %v", v)
|
||||
}
|
||||
canHaveAuxInt = true
|
||||
default:
|
||||
f.Fatalf("unknown aux type for %s", v.Op)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,11 +49,11 @@ var gogcflags = os.Getenv("GO_GCFLAGS")
|
|||
// optimizedLibs usually means "not running in a noopt test builder".
|
||||
var optimizedLibs = (!strings.Contains(gogcflags, "-N") && !strings.Contains(gogcflags, "-l"))
|
||||
|
||||
// TestNexting go-builds a file, then uses a debugger (default gdb, optionally delve)
|
||||
// TestNexting go-builds a file, then uses a debugger (default delve, optionally gdb)
|
||||
// to next through the generated executable, recording each line landed at, and
|
||||
// then compares those lines with reference file(s).
|
||||
// Flag -u updates the reference file(s).
|
||||
// Flag -d changes the debugger to delve (and uses delve-specific reference files)
|
||||
// Flag -g changes the debugger to gdb (and uses gdb-specific reference files)
|
||||
// Flag -v is ever-so-slightly verbose.
|
||||
// Flag -n is for dry-run, and prints the shell and first debug commands.
|
||||
//
|
||||
|
|
@ -83,9 +83,9 @@ var optimizedLibs = (!strings.Contains(gogcflags, "-N") && !strings.Contains(gog
|
|||
// to indicate normalization of Strings, (hex) addresses, and numbers.
|
||||
// "O" is an explicit indication that we expect it to be optimized out.
|
||||
// For example:
|
||||
/*
|
||||
if len(os.Args) > 1 { //gdb-dbg=(hist/A,cannedInput/A) //dlv-dbg=(hist/A,cannedInput/A)
|
||||
*/
|
||||
//
|
||||
// if len(os.Args) > 1 { //gdb-dbg=(hist/A,cannedInput/A) //dlv-dbg=(hist/A,cannedInput/A)
|
||||
//
|
||||
// TODO: not implemented for Delve yet, but this is the plan
|
||||
//
|
||||
// After a compiler change that causes a difference in the debug behavior, check
|
||||
|
|
@ -93,7 +93,7 @@ var optimizedLibs = (!strings.Contains(gogcflags, "-N") && !strings.Contains(gog
|
|||
// go test debug_test.go -args -u
|
||||
// (for Delve)
|
||||
// go test debug_test.go -args -u -d
|
||||
|
||||
//
|
||||
func TestNexting(t *testing.T) {
|
||||
testenv.SkipFlaky(t, 37404)
|
||||
|
||||
|
|
@ -110,7 +110,13 @@ func TestNexting(t *testing.T) {
|
|||
// Various architectures tend to differ slightly sometimes, and keeping them
|
||||
// all in sync is a pain for people who don't have them all at hand,
|
||||
// so limit testing to amd64 (for now)
|
||||
skipReasons += "not run when testing gdb (-g) unless forced (-f) or linux-amd64"
|
||||
skipReasons += "not run when testing gdb (-g) unless forced (-f) or linux-amd64; "
|
||||
}
|
||||
|
||||
if !*useGdb && !*force && testenv.Builder() == "linux-386-longtest" {
|
||||
// The latest version of Delve does support linux/386. However, the version currently
|
||||
// installed in the linux-386-longtest builder does not. See golang.org/issue/39309.
|
||||
skipReasons += "not run when testing delve on linux-386-longtest builder unless forced (-f); "
|
||||
}
|
||||
|
||||
if *useGdb {
|
||||
|
|
|
|||
31
src/cmd/compile/internal/ssa/flags_amd64_test.s
Normal file
31
src/cmd/compile/internal/ssa/flags_amd64_test.s
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build amd64
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
TEXT ·asmAddFlags(SB),NOSPLIT,$0-24
|
||||
MOVQ x+0(FP), AX
|
||||
ADDQ y+8(FP), AX
|
||||
PUSHFQ
|
||||
POPQ AX
|
||||
MOVQ AX, ret+16(FP)
|
||||
RET
|
||||
|
||||
TEXT ·asmSubFlags(SB),NOSPLIT,$0-24
|
||||
MOVQ x+0(FP), AX
|
||||
SUBQ y+8(FP), AX
|
||||
PUSHFQ
|
||||
POPQ AX
|
||||
MOVQ AX, ret+16(FP)
|
||||
RET
|
||||
|
||||
TEXT ·asmAndFlags(SB),NOSPLIT,$0-24
|
||||
MOVQ x+0(FP), AX
|
||||
ANDQ y+8(FP), AX
|
||||
PUSHFQ
|
||||
POPQ AX
|
||||
MOVQ AX, ret+16(FP)
|
||||
RET
|
||||
32
src/cmd/compile/internal/ssa/flags_arm64_test.s
Normal file
32
src/cmd/compile/internal/ssa/flags_arm64_test.s
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build arm64
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
TEXT ·asmAddFlags(SB),NOSPLIT,$0-24
|
||||
MOVD x+0(FP), R0
|
||||
MOVD y+8(FP), R1
|
||||
CMN R0, R1
|
||||
WORD $0xd53b4200 // MOVD NZCV, R0
|
||||
MOVD R0, ret+16(FP)
|
||||
RET
|
||||
|
||||
TEXT ·asmSubFlags(SB),NOSPLIT,$0-24
|
||||
MOVD x+0(FP), R0
|
||||
MOVD y+8(FP), R1
|
||||
CMP R1, R0
|
||||
WORD $0xd53b4200 // MOVD NZCV, R0
|
||||
MOVD R0, ret+16(FP)
|
||||
RET
|
||||
|
||||
TEXT ·asmAndFlags(SB),NOSPLIT,$0-24
|
||||
MOVD x+0(FP), R0
|
||||
MOVD y+8(FP), R1
|
||||
TST R1, R0
|
||||
WORD $0xd53b4200 // MOVD NZCV, R0
|
||||
BIC $0x30000000, R0 // clear C, V bits, as TST does not change those flags
|
||||
MOVD R0, ret+16(FP)
|
||||
RET
|
||||
108
src/cmd/compile/internal/ssa/flags_test.go
Normal file
108
src/cmd/compile/internal/ssa/flags_test.go
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build amd64 arm64
|
||||
|
||||
package ssa
|
||||
|
||||
// This file tests the functions addFlags64 and subFlags64 by comparing their
|
||||
// results to what the chip calculates.
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAddFlagsNative(t *testing.T) {
|
||||
var numbers = []int64{
|
||||
1, 0, -1,
|
||||
2, -2,
|
||||
1<<63 - 1, -1 << 63,
|
||||
}
|
||||
coverage := map[flagConstant]bool{}
|
||||
for _, x := range numbers {
|
||||
for _, y := range numbers {
|
||||
a := addFlags64(x, y)
|
||||
b := flagRegister2flagConstant(asmAddFlags(x, y), false)
|
||||
if a != b {
|
||||
t.Errorf("asmAdd diff: x=%x y=%x got=%s want=%s\n", x, y, a, b)
|
||||
}
|
||||
coverage[a] = true
|
||||
}
|
||||
}
|
||||
if len(coverage) != 9 { // TODO: can we cover all outputs?
|
||||
t.Errorf("coverage too small, got %d want 9", len(coverage))
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubFlagsNative(t *testing.T) {
|
||||
var numbers = []int64{
|
||||
1, 0, -1,
|
||||
2, -2,
|
||||
1<<63 - 1, -1 << 63,
|
||||
}
|
||||
coverage := map[flagConstant]bool{}
|
||||
for _, x := range numbers {
|
||||
for _, y := range numbers {
|
||||
a := subFlags64(x, y)
|
||||
b := flagRegister2flagConstant(asmSubFlags(x, y), true)
|
||||
if a != b {
|
||||
t.Errorf("asmSub diff: x=%x y=%x got=%s want=%s\n", x, y, a, b)
|
||||
}
|
||||
coverage[a] = true
|
||||
}
|
||||
}
|
||||
if len(coverage) != 7 { // TODO: can we cover all outputs?
|
||||
t.Errorf("coverage too small, got %d want 7", len(coverage))
|
||||
}
|
||||
}
|
||||
|
||||
func TestAndFlagsNative(t *testing.T) {
|
||||
var numbers = []int64{
|
||||
1, 0, -1,
|
||||
2, -2,
|
||||
1<<63 - 1, -1 << 63,
|
||||
}
|
||||
coverage := map[flagConstant]bool{}
|
||||
for _, x := range numbers {
|
||||
for _, y := range numbers {
|
||||
a := logicFlags64(x & y)
|
||||
b := flagRegister2flagConstant(asmAndFlags(x, y), false)
|
||||
if a != b {
|
||||
t.Errorf("asmAnd diff: x=%x y=%x got=%s want=%s\n", x, y, a, b)
|
||||
}
|
||||
coverage[a] = true
|
||||
}
|
||||
}
|
||||
if len(coverage) != 3 {
|
||||
t.Errorf("coverage too small, got %d want 3", len(coverage))
|
||||
}
|
||||
}
|
||||
|
||||
func asmAddFlags(x, y int64) int
|
||||
func asmSubFlags(x, y int64) int
|
||||
func asmAndFlags(x, y int64) int
|
||||
|
||||
func flagRegister2flagConstant(x int, sub bool) flagConstant {
|
||||
var fcb flagConstantBuilder
|
||||
switch runtime.GOARCH {
|
||||
case "amd64":
|
||||
fcb.Z = x>>6&1 != 0
|
||||
fcb.N = x>>7&1 != 0
|
||||
fcb.C = x>>0&1 != 0
|
||||
if sub {
|
||||
// Convert from amd64-sense to arm-sense
|
||||
fcb.C = !fcb.C
|
||||
}
|
||||
fcb.V = x>>11&1 != 0
|
||||
case "arm64":
|
||||
fcb.Z = x>>30&1 != 0
|
||||
fcb.N = x>>31&1 != 0
|
||||
fcb.C = x>>29&1 != 0
|
||||
fcb.V = x>>28&1 != 0
|
||||
default:
|
||||
panic("unsupported architecture: " + runtime.GOARCH)
|
||||
}
|
||||
return fcb.encode()
|
||||
}
|
||||
|
|
@ -609,89 +609,59 @@
|
|||
(Select1 (CALLudiv x (MOVWconst [c]))) && isPowerOfTwo(c) -> (ANDconst [c-1] x)
|
||||
|
||||
// constant comparisons
|
||||
(CMPconst (MOVWconst [x]) [y]) && int32(x)==int32(y) -> (FlagEQ)
|
||||
(CMPconst (MOVWconst [x]) [y]) && int32(x)<int32(y) && uint32(x)<uint32(y) -> (FlagLT_ULT)
|
||||
(CMPconst (MOVWconst [x]) [y]) && int32(x)<int32(y) && uint32(x)>uint32(y) -> (FlagLT_UGT)
|
||||
(CMPconst (MOVWconst [x]) [y]) && int32(x)>int32(y) && uint32(x)<uint32(y) -> (FlagGT_ULT)
|
||||
(CMPconst (MOVWconst [x]) [y]) && int32(x)>int32(y) && uint32(x)>uint32(y) -> (FlagGT_UGT)
|
||||
(CMNconst (MOVWconst [x]) [y]) && int32(x)==int32(-y) -> (FlagEQ)
|
||||
(CMNconst (MOVWconst [x]) [y]) && int32(x)<int32(-y) && uint32(x)<uint32(-y) -> (FlagLT_ULT)
|
||||
(CMNconst (MOVWconst [x]) [y]) && int32(x)<int32(-y) && uint32(x)>uint32(-y) -> (FlagLT_UGT)
|
||||
(CMNconst (MOVWconst [x]) [y]) && int32(x)>int32(-y) && uint32(x)<uint32(-y) -> (FlagGT_ULT)
|
||||
(CMNconst (MOVWconst [x]) [y]) && int32(x)>int32(-y) && uint32(x)>uint32(-y) -> (FlagGT_UGT)
|
||||
(TSTconst (MOVWconst [x]) [y]) && int32(x&y)==0 -> (FlagEQ)
|
||||
(TSTconst (MOVWconst [x]) [y]) && int32(x&y)<0 -> (FlagLT_UGT)
|
||||
(TSTconst (MOVWconst [x]) [y]) && int32(x&y)>0 -> (FlagGT_UGT)
|
||||
(TEQconst (MOVWconst [x]) [y]) && int32(x^y)==0 -> (FlagEQ)
|
||||
(TEQconst (MOVWconst [x]) [y]) && int32(x^y)<0 -> (FlagLT_UGT)
|
||||
(TEQconst (MOVWconst [x]) [y]) && int32(x^y)>0 -> (FlagGT_UGT)
|
||||
(CMPconst (MOVWconst [x]) [y]) => (FlagConstant [subFlags32(x,y)])
|
||||
(CMNconst (MOVWconst [x]) [y]) => (FlagConstant [addFlags32(x,y)])
|
||||
(TSTconst (MOVWconst [x]) [y]) => (FlagConstant [logicFlags32(x&y)])
|
||||
(TEQconst (MOVWconst [x]) [y]) => (FlagConstant [logicFlags32(x^y)])
|
||||
|
||||
// other known comparisons
|
||||
(CMPconst (MOVBUreg _) [c]) && 0xff < c -> (FlagLT_ULT)
|
||||
(CMPconst (MOVHUreg _) [c]) && 0xffff < c -> (FlagLT_ULT)
|
||||
(CMPconst (ANDconst _ [m]) [n]) && 0 <= int32(m) && int32(m) < int32(n) -> (FlagLT_ULT)
|
||||
(CMPconst (SRLconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 32 && (1<<uint32(32-c)) <= uint32(n) -> (FlagLT_ULT)
|
||||
(CMPconst (MOVBUreg _) [c]) && 0xff < c => (FlagConstant [subFlags32(0, 1)])
|
||||
(CMPconst (MOVHUreg _) [c]) && 0xffff < c => (FlagConstant [subFlags32(0, 1)])
|
||||
(CMPconst (ANDconst _ [m]) [n]) && 0 <= m && m < n => (FlagConstant [subFlags32(0, 1)])
|
||||
(CMPconst (SRLconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 32 && (1<<uint32(32-c)) <= uint32(n) => (FlagConstant [subFlags32(0, 1)])
|
||||
|
||||
// absorb flag constants into branches
|
||||
(EQ (FlagEQ) yes no) -> (First yes no)
|
||||
(EQ (FlagLT_ULT) yes no) -> (First no yes)
|
||||
(EQ (FlagLT_UGT) yes no) -> (First no yes)
|
||||
(EQ (FlagGT_ULT) yes no) -> (First no yes)
|
||||
(EQ (FlagGT_UGT) yes no) -> (First no yes)
|
||||
(EQ (FlagConstant [fc]) yes no) && fc.eq() => (First yes no)
|
||||
(EQ (FlagConstant [fc]) yes no) && !fc.eq() => (First no yes)
|
||||
|
||||
(NE (FlagEQ) yes no) -> (First no yes)
|
||||
(NE (FlagLT_ULT) yes no) -> (First yes no)
|
||||
(NE (FlagLT_UGT) yes no) -> (First yes no)
|
||||
(NE (FlagGT_ULT) yes no) -> (First yes no)
|
||||
(NE (FlagGT_UGT) yes no) -> (First yes no)
|
||||
(NE (FlagConstant [fc]) yes no) && fc.ne() => (First yes no)
|
||||
(NE (FlagConstant [fc]) yes no) && !fc.ne() => (First no yes)
|
||||
|
||||
(LT (FlagEQ) yes no) -> (First no yes)
|
||||
(LT (FlagLT_ULT) yes no) -> (First yes no)
|
||||
(LT (FlagLT_UGT) yes no) -> (First yes no)
|
||||
(LT (FlagGT_ULT) yes no) -> (First no yes)
|
||||
(LT (FlagGT_UGT) yes no) -> (First no yes)
|
||||
(LT (FlagConstant [fc]) yes no) && fc.lt() => (First yes no)
|
||||
(LT (FlagConstant [fc]) yes no) && !fc.lt() => (First no yes)
|
||||
|
||||
(LE (FlagEQ) yes no) -> (First yes no)
|
||||
(LE (FlagLT_ULT) yes no) -> (First yes no)
|
||||
(LE (FlagLT_UGT) yes no) -> (First yes no)
|
||||
(LE (FlagGT_ULT) yes no) -> (First no yes)
|
||||
(LE (FlagGT_UGT) yes no) -> (First no yes)
|
||||
(LE (FlagConstant [fc]) yes no) && fc.le() => (First yes no)
|
||||
(LE (FlagConstant [fc]) yes no) && !fc.le() => (First no yes)
|
||||
|
||||
(GT (FlagEQ) yes no) -> (First no yes)
|
||||
(GT (FlagLT_ULT) yes no) -> (First no yes)
|
||||
(GT (FlagLT_UGT) yes no) -> (First no yes)
|
||||
(GT (FlagGT_ULT) yes no) -> (First yes no)
|
||||
(GT (FlagGT_UGT) yes no) -> (First yes no)
|
||||
(GT (FlagConstant [fc]) yes no) && fc.gt() => (First yes no)
|
||||
(GT (FlagConstant [fc]) yes no) && !fc.gt() => (First no yes)
|
||||
|
||||
(GE (FlagEQ) yes no) -> (First yes no)
|
||||
(GE (FlagLT_ULT) yes no) -> (First no yes)
|
||||
(GE (FlagLT_UGT) yes no) -> (First no yes)
|
||||
(GE (FlagGT_ULT) yes no) -> (First yes no)
|
||||
(GE (FlagGT_UGT) yes no) -> (First yes no)
|
||||
(GE (FlagConstant [fc]) yes no) && fc.ge() => (First yes no)
|
||||
(GE (FlagConstant [fc]) yes no) && !fc.ge() => (First no yes)
|
||||
|
||||
(ULT (FlagEQ) yes no) -> (First no yes)
|
||||
(ULT (FlagLT_ULT) yes no) -> (First yes no)
|
||||
(ULT (FlagLT_UGT) yes no) -> (First no yes)
|
||||
(ULT (FlagGT_ULT) yes no) -> (First yes no)
|
||||
(ULT (FlagGT_UGT) yes no) -> (First no yes)
|
||||
(ULT (FlagConstant [fc]) yes no) && fc.ult() => (First yes no)
|
||||
(ULT (FlagConstant [fc]) yes no) && !fc.ult() => (First no yes)
|
||||
|
||||
(ULE (FlagEQ) yes no) -> (First yes no)
|
||||
(ULE (FlagLT_ULT) yes no) -> (First yes no)
|
||||
(ULE (FlagLT_UGT) yes no) -> (First no yes)
|
||||
(ULE (FlagGT_ULT) yes no) -> (First yes no)
|
||||
(ULE (FlagGT_UGT) yes no) -> (First no yes)
|
||||
(ULE (FlagConstant [fc]) yes no) && fc.ule() => (First yes no)
|
||||
(ULE (FlagConstant [fc]) yes no) && !fc.ule() => (First no yes)
|
||||
|
||||
(UGT (FlagEQ) yes no) -> (First no yes)
|
||||
(UGT (FlagLT_ULT) yes no) -> (First no yes)
|
||||
(UGT (FlagLT_UGT) yes no) -> (First yes no)
|
||||
(UGT (FlagGT_ULT) yes no) -> (First no yes)
|
||||
(UGT (FlagGT_UGT) yes no) -> (First yes no)
|
||||
(UGT (FlagConstant [fc]) yes no) && fc.ugt() => (First yes no)
|
||||
(UGT (FlagConstant [fc]) yes no) && !fc.ugt() => (First no yes)
|
||||
|
||||
(UGE (FlagEQ) yes no) -> (First yes no)
|
||||
(UGE (FlagLT_ULT) yes no) -> (First no yes)
|
||||
(UGE (FlagLT_UGT) yes no) -> (First yes no)
|
||||
(UGE (FlagGT_ULT) yes no) -> (First no yes)
|
||||
(UGE (FlagGT_UGT) yes no) -> (First yes no)
|
||||
(UGE (FlagConstant [fc]) yes no) && fc.uge() => (First yes no)
|
||||
(UGE (FlagConstant [fc]) yes no) && !fc.uge() => (First no yes)
|
||||
|
||||
(LTnoov (FlagConstant [fc]) yes no) && fc.ltNoov() => (First yes no)
|
||||
(LTnoov (FlagConstant [fc]) yes no) && !fc.ltNoov() => (First no yes)
|
||||
|
||||
(LEnoov (FlagConstant [fc]) yes no) && fc.leNoov() => (First yes no)
|
||||
(LEnoov (FlagConstant [fc]) yes no) && !fc.leNoov() => (First no yes)
|
||||
|
||||
(GTnoov (FlagConstant [fc]) yes no) && fc.gtNoov() => (First yes no)
|
||||
(GTnoov (FlagConstant [fc]) yes no) && !fc.gtNoov() => (First no yes)
|
||||
|
||||
(GEnoov (FlagConstant [fc]) yes no) && fc.geNoov() => (First yes no)
|
||||
(GEnoov (FlagConstant [fc]) yes no) && !fc.geNoov() => (First no yes)
|
||||
|
||||
// absorb InvertFlags into branches
|
||||
(LT (InvertFlags cmp) yes no) -> (GT cmp yes no)
|
||||
|
|
@ -710,65 +680,16 @@
|
|||
(GTnoov (InvertFlags cmp) yes no) => (LTnoov cmp yes no)
|
||||
|
||||
// absorb flag constants into boolean values
|
||||
(Equal (FlagEQ)) -> (MOVWconst [1])
|
||||
(Equal (FlagLT_ULT)) -> (MOVWconst [0])
|
||||
(Equal (FlagLT_UGT)) -> (MOVWconst [0])
|
||||
(Equal (FlagGT_ULT)) -> (MOVWconst [0])
|
||||
(Equal (FlagGT_UGT)) -> (MOVWconst [0])
|
||||
|
||||
(NotEqual (FlagEQ)) -> (MOVWconst [0])
|
||||
(NotEqual (FlagLT_ULT)) -> (MOVWconst [1])
|
||||
(NotEqual (FlagLT_UGT)) -> (MOVWconst [1])
|
||||
(NotEqual (FlagGT_ULT)) -> (MOVWconst [1])
|
||||
(NotEqual (FlagGT_UGT)) -> (MOVWconst [1])
|
||||
|
||||
(LessThan (FlagEQ)) -> (MOVWconst [0])
|
||||
(LessThan (FlagLT_ULT)) -> (MOVWconst [1])
|
||||
(LessThan (FlagLT_UGT)) -> (MOVWconst [1])
|
||||
(LessThan (FlagGT_ULT)) -> (MOVWconst [0])
|
||||
(LessThan (FlagGT_UGT)) -> (MOVWconst [0])
|
||||
|
||||
(LessThanU (FlagEQ)) -> (MOVWconst [0])
|
||||
(LessThanU (FlagLT_ULT)) -> (MOVWconst [1])
|
||||
(LessThanU (FlagLT_UGT)) -> (MOVWconst [0])
|
||||
(LessThanU (FlagGT_ULT)) -> (MOVWconst [1])
|
||||
(LessThanU (FlagGT_UGT)) -> (MOVWconst [0])
|
||||
|
||||
(LessEqual (FlagEQ)) -> (MOVWconst [1])
|
||||
(LessEqual (FlagLT_ULT)) -> (MOVWconst [1])
|
||||
(LessEqual (FlagLT_UGT)) -> (MOVWconst [1])
|
||||
(LessEqual (FlagGT_ULT)) -> (MOVWconst [0])
|
||||
(LessEqual (FlagGT_UGT)) -> (MOVWconst [0])
|
||||
|
||||
(LessEqualU (FlagEQ)) -> (MOVWconst [1])
|
||||
(LessEqualU (FlagLT_ULT)) -> (MOVWconst [1])
|
||||
(LessEqualU (FlagLT_UGT)) -> (MOVWconst [0])
|
||||
(LessEqualU (FlagGT_ULT)) -> (MOVWconst [1])
|
||||
(LessEqualU (FlagGT_UGT)) -> (MOVWconst [0])
|
||||
|
||||
(GreaterThan (FlagEQ)) -> (MOVWconst [0])
|
||||
(GreaterThan (FlagLT_ULT)) -> (MOVWconst [0])
|
||||
(GreaterThan (FlagLT_UGT)) -> (MOVWconst [0])
|
||||
(GreaterThan (FlagGT_ULT)) -> (MOVWconst [1])
|
||||
(GreaterThan (FlagGT_UGT)) -> (MOVWconst [1])
|
||||
|
||||
(GreaterThanU (FlagEQ)) -> (MOVWconst [0])
|
||||
(GreaterThanU (FlagLT_ULT)) -> (MOVWconst [0])
|
||||
(GreaterThanU (FlagLT_UGT)) -> (MOVWconst [1])
|
||||
(GreaterThanU (FlagGT_ULT)) -> (MOVWconst [0])
|
||||
(GreaterThanU (FlagGT_UGT)) -> (MOVWconst [1])
|
||||
|
||||
(GreaterEqual (FlagEQ)) -> (MOVWconst [1])
|
||||
(GreaterEqual (FlagLT_ULT)) -> (MOVWconst [0])
|
||||
(GreaterEqual (FlagLT_UGT)) -> (MOVWconst [0])
|
||||
(GreaterEqual (FlagGT_ULT)) -> (MOVWconst [1])
|
||||
(GreaterEqual (FlagGT_UGT)) -> (MOVWconst [1])
|
||||
|
||||
(GreaterEqualU (FlagEQ)) -> (MOVWconst [1])
|
||||
(GreaterEqualU (FlagLT_ULT)) -> (MOVWconst [0])
|
||||
(GreaterEqualU (FlagLT_UGT)) -> (MOVWconst [1])
|
||||
(GreaterEqualU (FlagGT_ULT)) -> (MOVWconst [0])
|
||||
(GreaterEqualU (FlagGT_UGT)) -> (MOVWconst [1])
|
||||
(Equal (FlagConstant [fc])) => (MOVWconst [b2i32(fc.eq())])
|
||||
(NotEqual (FlagConstant [fc])) => (MOVWconst [b2i32(fc.ne())])
|
||||
(LessThan (FlagConstant [fc])) => (MOVWconst [b2i32(fc.lt())])
|
||||
(LessThanU (FlagConstant [fc])) => (MOVWconst [b2i32(fc.ult())])
|
||||
(LessEqual (FlagConstant [fc])) => (MOVWconst [b2i32(fc.le())])
|
||||
(LessEqualU (FlagConstant [fc])) => (MOVWconst [b2i32(fc.ule())])
|
||||
(GreaterThan (FlagConstant [fc])) => (MOVWconst [b2i32(fc.gt())])
|
||||
(GreaterThanU (FlagConstant [fc])) => (MOVWconst [b2i32(fc.ugt())])
|
||||
(GreaterEqual (FlagConstant [fc])) => (MOVWconst [b2i32(fc.ge())])
|
||||
(GreaterEqualU (FlagConstant [fc])) => (MOVWconst [b2i32(fc.uge())])
|
||||
|
||||
// absorb InvertFlags into boolean values
|
||||
(Equal (InvertFlags x)) -> (Equal x)
|
||||
|
|
@ -783,26 +704,17 @@
|
|||
(GreaterEqualU (InvertFlags x)) -> (LessEqualU x)
|
||||
|
||||
// absorb flag constants into conditional instructions
|
||||
(CMOVWLSconst _ (FlagEQ) [c]) -> (MOVWconst [c])
|
||||
(CMOVWLSconst _ (FlagLT_ULT) [c]) -> (MOVWconst [c])
|
||||
(CMOVWLSconst x (FlagLT_UGT)) -> x
|
||||
(CMOVWLSconst _ (FlagGT_ULT) [c]) -> (MOVWconst [c])
|
||||
(CMOVWLSconst x (FlagGT_UGT)) -> x
|
||||
(CMOVWLSconst _ (FlagConstant [fc]) [c]) && fc.ule() => (MOVWconst [c])
|
||||
(CMOVWLSconst x (FlagConstant [fc]) [c]) && fc.ugt() => x
|
||||
|
||||
(CMOVWHSconst _ (FlagEQ) [c]) -> (MOVWconst [c])
|
||||
(CMOVWHSconst x (FlagLT_ULT)) -> x
|
||||
(CMOVWHSconst _ (FlagLT_UGT) [c]) -> (MOVWconst [c])
|
||||
(CMOVWHSconst x (FlagGT_ULT)) -> x
|
||||
(CMOVWHSconst _ (FlagGT_UGT) [c]) -> (MOVWconst [c])
|
||||
(CMOVWHSconst _ (FlagConstant [fc]) [c]) && fc.uge() => (MOVWconst [c])
|
||||
(CMOVWHSconst x (FlagConstant [fc]) [c]) && fc.ult() => x
|
||||
|
||||
(CMOVWLSconst x (InvertFlags flags) [c]) -> (CMOVWHSconst x flags [c])
|
||||
(CMOVWHSconst x (InvertFlags flags) [c]) -> (CMOVWLSconst x flags [c])
|
||||
|
||||
(SRAcond x _ (FlagEQ)) -> (SRAconst x [31])
|
||||
(SRAcond x y (FlagLT_ULT)) -> (SRA x y)
|
||||
(SRAcond x _ (FlagLT_UGT)) -> (SRAconst x [31])
|
||||
(SRAcond x y (FlagGT_ULT)) -> (SRA x y)
|
||||
(SRAcond x _ (FlagGT_UGT)) -> (SRAconst x [31])
|
||||
(SRAcond x _ (FlagConstant [fc])) && fc.uge() => (SRAconst x [31])
|
||||
(SRAcond x y (FlagConstant [fc])) && fc.ult() => (SRA x y)
|
||||
|
||||
// remove redundant *const ops
|
||||
(ADDconst [0] x) -> x
|
||||
|
|
|
|||
|
|
@ -1381,103 +1381,64 @@
|
|||
(MOVDreg (MOVDconst [c])) -> (MOVDconst [c])
|
||||
|
||||
// constant comparisons
|
||||
(CMPconst (MOVDconst [x]) [y]) && x==y -> (FlagEQ)
|
||||
(CMPconst (MOVDconst [x]) [y]) && x<y && uint64(x)<uint64(y) -> (FlagLT_ULT)
|
||||
(CMPconst (MOVDconst [x]) [y]) && x<y && uint64(x)>uint64(y) -> (FlagLT_UGT)
|
||||
(CMPconst (MOVDconst [x]) [y]) && x>y && uint64(x)<uint64(y) -> (FlagGT_ULT)
|
||||
(CMPconst (MOVDconst [x]) [y]) && x>y && uint64(x)>uint64(y) -> (FlagGT_UGT)
|
||||
(CMPWconst (MOVDconst [x]) [y]) && int32(x)==int32(y) -> (FlagEQ)
|
||||
(CMPWconst (MOVDconst [x]) [y]) && int32(x)<int32(y) && uint32(x)<uint32(y) -> (FlagLT_ULT)
|
||||
(CMPWconst (MOVDconst [x]) [y]) && int32(x)<int32(y) && uint32(x)>uint32(y) -> (FlagLT_UGT)
|
||||
(CMPWconst (MOVDconst [x]) [y]) && int32(x)>int32(y) && uint32(x)<uint32(y) -> (FlagGT_ULT)
|
||||
(CMPWconst (MOVDconst [x]) [y]) && int32(x)>int32(y) && uint32(x)>uint32(y) -> (FlagGT_UGT)
|
||||
(TSTconst (MOVDconst [x]) [y]) && int64(x&y)==0 -> (FlagEQ)
|
||||
(TSTconst (MOVDconst [x]) [y]) && int64(x&y)<0 -> (FlagLT_UGT)
|
||||
(TSTconst (MOVDconst [x]) [y]) && int64(x&y)>0 -> (FlagGT_UGT)
|
||||
(TSTWconst (MOVDconst [x]) [y]) && int32(x&y)==0 -> (FlagEQ)
|
||||
(TSTWconst (MOVDconst [x]) [y]) && int32(x&y)<0 -> (FlagLT_UGT)
|
||||
(TSTWconst (MOVDconst [x]) [y]) && int32(x&y)>0 -> (FlagGT_UGT)
|
||||
(CMNconst (MOVDconst [x]) [y]) && int64(x)==int64(-y) -> (FlagEQ)
|
||||
(CMNconst (MOVDconst [x]) [y]) && int64(x)<int64(-y) && uint64(x)<uint64(-y) -> (FlagLT_ULT)
|
||||
(CMNconst (MOVDconst [x]) [y]) && int64(x)<int64(-y) && uint64(x)>uint64(-y) -> (FlagLT_UGT)
|
||||
(CMNconst (MOVDconst [x]) [y]) && int64(x)>int64(-y) && uint64(x)<uint64(-y) -> (FlagGT_ULT)
|
||||
(CMNconst (MOVDconst [x]) [y]) && int64(x)>int64(-y) && uint64(x)>uint64(-y) -> (FlagGT_UGT)
|
||||
(CMNWconst (MOVDconst [x]) [y]) && int32(x)==int32(-y) -> (FlagEQ)
|
||||
(CMNWconst (MOVDconst [x]) [y]) && int32(x)<int32(-y) && uint32(x)<uint32(-y) -> (FlagLT_ULT)
|
||||
(CMNWconst (MOVDconst [x]) [y]) && int32(x)<int32(-y) && uint32(x)>uint32(-y) -> (FlagLT_UGT)
|
||||
(CMNWconst (MOVDconst [x]) [y]) && int32(x)>int32(-y) && uint32(x)<uint32(-y) -> (FlagGT_ULT)
|
||||
(CMNWconst (MOVDconst [x]) [y]) && int32(x)>int32(-y) && uint32(x)>uint32(-y) -> (FlagGT_UGT)
|
||||
|
||||
(CMPconst (MOVDconst [x]) [y]) => (FlagConstant [subFlags64(x,y)])
|
||||
(CMPWconst (MOVDconst [x]) [y]) => (FlagConstant [subFlags32(int32(x),y)])
|
||||
(TSTconst (MOVDconst [x]) [y]) => (FlagConstant [logicFlags64(x&y)])
|
||||
(TSTWconst (MOVDconst [x]) [y]) => (FlagConstant [logicFlags32(int32(x)&y)])
|
||||
(CMNconst (MOVDconst [x]) [y]) => (FlagConstant [addFlags64(x,y)])
|
||||
(CMNWconst (MOVDconst [x]) [y]) => (FlagConstant [addFlags32(int32(x),y)])
|
||||
|
||||
// other known comparisons
|
||||
(CMPconst (MOVBUreg _) [c]) && 0xff < c -> (FlagLT_ULT)
|
||||
(CMPconst (MOVHUreg _) [c]) && 0xffff < c -> (FlagLT_ULT)
|
||||
(CMPconst (MOVWUreg _) [c]) && 0xffffffff < c -> (FlagLT_ULT)
|
||||
(CMPconst (ANDconst _ [m]) [n]) && 0 <= m && m < n -> (FlagLT_ULT)
|
||||
(CMPconst (SRLconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 63 && (1<<uint64(64-c)) <= uint64(n) -> (FlagLT_ULT)
|
||||
(CMPWconst (MOVBUreg _) [c]) && 0xff < int32(c) -> (FlagLT_ULT)
|
||||
(CMPWconst (MOVHUreg _) [c]) && 0xffff < int32(c) -> (FlagLT_ULT)
|
||||
(CMPconst (MOVBUreg _) [c]) && 0xff < c => (FlagConstant [subFlags64(0,1)])
|
||||
(CMPconst (MOVHUreg _) [c]) && 0xffff < c => (FlagConstant [subFlags64(0,1)])
|
||||
(CMPconst (MOVWUreg _) [c]) && 0xffffffff < c => (FlagConstant [subFlags64(0,1)])
|
||||
(CMPconst (ANDconst _ [m]) [n]) && 0 <= m && m < n => (FlagConstant [subFlags64(0,1)])
|
||||
(CMPconst (SRLconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 63 && (1<<uint64(64-c)) <= uint64(n) => (FlagConstant [subFlags64(0,1)])
|
||||
(CMPWconst (MOVBUreg _) [c]) && 0xff < c => (FlagConstant [subFlags64(0,1)])
|
||||
(CMPWconst (MOVHUreg _) [c]) && 0xffff < c => (FlagConstant [subFlags64(0,1)])
|
||||
|
||||
// absorb flag constants into branches
|
||||
(EQ (FlagEQ) yes no) -> (First yes no)
|
||||
(EQ (FlagLT_ULT) yes no) -> (First no yes)
|
||||
(EQ (FlagLT_UGT) yes no) -> (First no yes)
|
||||
(EQ (FlagGT_ULT) yes no) -> (First no yes)
|
||||
(EQ (FlagGT_UGT) yes no) -> (First no yes)
|
||||
(EQ (FlagConstant [fc]) yes no) && fc.eq() => (First yes no)
|
||||
(EQ (FlagConstant [fc]) yes no) && !fc.eq() => (First no yes)
|
||||
|
||||
(NE (FlagEQ) yes no) -> (First no yes)
|
||||
(NE (FlagLT_ULT) yes no) -> (First yes no)
|
||||
(NE (FlagLT_UGT) yes no) -> (First yes no)
|
||||
(NE (FlagGT_ULT) yes no) -> (First yes no)
|
||||
(NE (FlagGT_UGT) yes no) -> (First yes no)
|
||||
(NE (FlagConstant [fc]) yes no) && fc.ne() => (First yes no)
|
||||
(NE (FlagConstant [fc]) yes no) && !fc.ne() => (First no yes)
|
||||
|
||||
(LT (FlagEQ) yes no) -> (First no yes)
|
||||
(LT (FlagLT_ULT) yes no) -> (First yes no)
|
||||
(LT (FlagLT_UGT) yes no) -> (First yes no)
|
||||
(LT (FlagGT_ULT) yes no) -> (First no yes)
|
||||
(LT (FlagGT_UGT) yes no) -> (First no yes)
|
||||
(LT (FlagConstant [fc]) yes no) && fc.lt() => (First yes no)
|
||||
(LT (FlagConstant [fc]) yes no) && !fc.lt() => (First no yes)
|
||||
|
||||
(LE (FlagEQ) yes no) -> (First yes no)
|
||||
(LE (FlagLT_ULT) yes no) -> (First yes no)
|
||||
(LE (FlagLT_UGT) yes no) -> (First yes no)
|
||||
(LE (FlagGT_ULT) yes no) -> (First no yes)
|
||||
(LE (FlagGT_UGT) yes no) -> (First no yes)
|
||||
(LE (FlagConstant [fc]) yes no) && fc.le() => (First yes no)
|
||||
(LE (FlagConstant [fc]) yes no) && !fc.le() => (First no yes)
|
||||
|
||||
(GT (FlagEQ) yes no) -> (First no yes)
|
||||
(GT (FlagLT_ULT) yes no) -> (First no yes)
|
||||
(GT (FlagLT_UGT) yes no) -> (First no yes)
|
||||
(GT (FlagGT_ULT) yes no) -> (First yes no)
|
||||
(GT (FlagGT_UGT) yes no) -> (First yes no)
|
||||
(GT (FlagConstant [fc]) yes no) && fc.gt() => (First yes no)
|
||||
(GT (FlagConstant [fc]) yes no) && !fc.gt() => (First no yes)
|
||||
|
||||
(GE (FlagEQ) yes no) -> (First yes no)
|
||||
(GE (FlagLT_ULT) yes no) -> (First no yes)
|
||||
(GE (FlagLT_UGT) yes no) -> (First no yes)
|
||||
(GE (FlagGT_ULT) yes no) -> (First yes no)
|
||||
(GE (FlagGT_UGT) yes no) -> (First yes no)
|
||||
(GE (FlagConstant [fc]) yes no) && fc.ge() => (First yes no)
|
||||
(GE (FlagConstant [fc]) yes no) && !fc.ge() => (First no yes)
|
||||
|
||||
(ULT (FlagEQ) yes no) -> (First no yes)
|
||||
(ULT (FlagLT_ULT) yes no) -> (First yes no)
|
||||
(ULT (FlagLT_UGT) yes no) -> (First no yes)
|
||||
(ULT (FlagGT_ULT) yes no) -> (First yes no)
|
||||
(ULT (FlagGT_UGT) yes no) -> (First no yes)
|
||||
(ULT (FlagConstant [fc]) yes no) && fc.ult() => (First yes no)
|
||||
(ULT (FlagConstant [fc]) yes no) && !fc.ult() => (First no yes)
|
||||
|
||||
(ULE (FlagEQ) yes no) -> (First yes no)
|
||||
(ULE (FlagLT_ULT) yes no) -> (First yes no)
|
||||
(ULE (FlagLT_UGT) yes no) -> (First no yes)
|
||||
(ULE (FlagGT_ULT) yes no) -> (First yes no)
|
||||
(ULE (FlagGT_UGT) yes no) -> (First no yes)
|
||||
(ULE (FlagConstant [fc]) yes no) && fc.ule() => (First yes no)
|
||||
(ULE (FlagConstant [fc]) yes no) && !fc.ule() => (First no yes)
|
||||
|
||||
(UGT (FlagEQ) yes no) -> (First no yes)
|
||||
(UGT (FlagLT_ULT) yes no) -> (First no yes)
|
||||
(UGT (FlagLT_UGT) yes no) -> (First yes no)
|
||||
(UGT (FlagGT_ULT) yes no) -> (First no yes)
|
||||
(UGT (FlagGT_UGT) yes no) -> (First yes no)
|
||||
(UGT (FlagConstant [fc]) yes no) && fc.ugt() => (First yes no)
|
||||
(UGT (FlagConstant [fc]) yes no) && !fc.ugt() => (First no yes)
|
||||
|
||||
(UGE (FlagEQ) yes no) -> (First yes no)
|
||||
(UGE (FlagLT_ULT) yes no) -> (First no yes)
|
||||
(UGE (FlagLT_UGT) yes no) -> (First yes no)
|
||||
(UGE (FlagGT_ULT) yes no) -> (First no yes)
|
||||
(UGE (FlagGT_UGT) yes no) -> (First yes no)
|
||||
(UGE (FlagConstant [fc]) yes no) && fc.uge() => (First yes no)
|
||||
(UGE (FlagConstant [fc]) yes no) && !fc.uge() => (First no yes)
|
||||
|
||||
(LTnoov (FlagConstant [fc]) yes no) && fc.ltNoov() => (First yes no)
|
||||
(LTnoov (FlagConstant [fc]) yes no) && !fc.ltNoov() => (First no yes)
|
||||
|
||||
(LEnoov (FlagConstant [fc]) yes no) && fc.leNoov() => (First yes no)
|
||||
(LEnoov (FlagConstant [fc]) yes no) && !fc.leNoov() => (First no yes)
|
||||
|
||||
(GTnoov (FlagConstant [fc]) yes no) && fc.gtNoov() => (First yes no)
|
||||
(GTnoov (FlagConstant [fc]) yes no) && !fc.gtNoov() => (First no yes)
|
||||
|
||||
(GEnoov (FlagConstant [fc]) yes no) && fc.geNoov() => (First yes no)
|
||||
(GEnoov (FlagConstant [fc]) yes no) && !fc.geNoov() => (First no yes)
|
||||
|
||||
(Z (MOVDconst [0]) yes no) -> (First yes no)
|
||||
(Z (MOVDconst [c]) yes no) && c != 0 -> (First no yes)
|
||||
|
|
@ -1513,65 +1474,16 @@
|
|||
(CSEL0 {cc} x (InvertFlags cmp)) -> (CSEL0 {arm64Invert(cc.(Op))} x cmp)
|
||||
|
||||
// absorb flag constants into boolean values
|
||||
(Equal (FlagEQ)) -> (MOVDconst [1])
|
||||
(Equal (FlagLT_ULT)) -> (MOVDconst [0])
|
||||
(Equal (FlagLT_UGT)) -> (MOVDconst [0])
|
||||
(Equal (FlagGT_ULT)) -> (MOVDconst [0])
|
||||
(Equal (FlagGT_UGT)) -> (MOVDconst [0])
|
||||
|
||||
(NotEqual (FlagEQ)) -> (MOVDconst [0])
|
||||
(NotEqual (FlagLT_ULT)) -> (MOVDconst [1])
|
||||
(NotEqual (FlagLT_UGT)) -> (MOVDconst [1])
|
||||
(NotEqual (FlagGT_ULT)) -> (MOVDconst [1])
|
||||
(NotEqual (FlagGT_UGT)) -> (MOVDconst [1])
|
||||
|
||||
(LessThan (FlagEQ)) -> (MOVDconst [0])
|
||||
(LessThan (FlagLT_ULT)) -> (MOVDconst [1])
|
||||
(LessThan (FlagLT_UGT)) -> (MOVDconst [1])
|
||||
(LessThan (FlagGT_ULT)) -> (MOVDconst [0])
|
||||
(LessThan (FlagGT_UGT)) -> (MOVDconst [0])
|
||||
|
||||
(LessThanU (FlagEQ)) -> (MOVDconst [0])
|
||||
(LessThanU (FlagLT_ULT)) -> (MOVDconst [1])
|
||||
(LessThanU (FlagLT_UGT)) -> (MOVDconst [0])
|
||||
(LessThanU (FlagGT_ULT)) -> (MOVDconst [1])
|
||||
(LessThanU (FlagGT_UGT)) -> (MOVDconst [0])
|
||||
|
||||
(LessEqual (FlagEQ)) -> (MOVDconst [1])
|
||||
(LessEqual (FlagLT_ULT)) -> (MOVDconst [1])
|
||||
(LessEqual (FlagLT_UGT)) -> (MOVDconst [1])
|
||||
(LessEqual (FlagGT_ULT)) -> (MOVDconst [0])
|
||||
(LessEqual (FlagGT_UGT)) -> (MOVDconst [0])
|
||||
|
||||
(LessEqualU (FlagEQ)) -> (MOVDconst [1])
|
||||
(LessEqualU (FlagLT_ULT)) -> (MOVDconst [1])
|
||||
(LessEqualU (FlagLT_UGT)) -> (MOVDconst [0])
|
||||
(LessEqualU (FlagGT_ULT)) -> (MOVDconst [1])
|
||||
(LessEqualU (FlagGT_UGT)) -> (MOVDconst [0])
|
||||
|
||||
(GreaterThan (FlagEQ)) -> (MOVDconst [0])
|
||||
(GreaterThan (FlagLT_ULT)) -> (MOVDconst [0])
|
||||
(GreaterThan (FlagLT_UGT)) -> (MOVDconst [0])
|
||||
(GreaterThan (FlagGT_ULT)) -> (MOVDconst [1])
|
||||
(GreaterThan (FlagGT_UGT)) -> (MOVDconst [1])
|
||||
|
||||
(GreaterThanU (FlagEQ)) -> (MOVDconst [0])
|
||||
(GreaterThanU (FlagLT_ULT)) -> (MOVDconst [0])
|
||||
(GreaterThanU (FlagLT_UGT)) -> (MOVDconst [1])
|
||||
(GreaterThanU (FlagGT_ULT)) -> (MOVDconst [0])
|
||||
(GreaterThanU (FlagGT_UGT)) -> (MOVDconst [1])
|
||||
|
||||
(GreaterEqual (FlagEQ)) -> (MOVDconst [1])
|
||||
(GreaterEqual (FlagLT_ULT)) -> (MOVDconst [0])
|
||||
(GreaterEqual (FlagLT_UGT)) -> (MOVDconst [0])
|
||||
(GreaterEqual (FlagGT_ULT)) -> (MOVDconst [1])
|
||||
(GreaterEqual (FlagGT_UGT)) -> (MOVDconst [1])
|
||||
|
||||
(GreaterEqualU (FlagEQ)) -> (MOVDconst [1])
|
||||
(GreaterEqualU (FlagLT_ULT)) -> (MOVDconst [0])
|
||||
(GreaterEqualU (FlagLT_UGT)) -> (MOVDconst [1])
|
||||
(GreaterEqualU (FlagGT_ULT)) -> (MOVDconst [0])
|
||||
(GreaterEqualU (FlagGT_UGT)) -> (MOVDconst [1])
|
||||
(Equal (FlagConstant [fc])) => (MOVDconst [b2i(fc.eq())])
|
||||
(NotEqual (FlagConstant [fc])) => (MOVDconst [b2i(fc.ne())])
|
||||
(LessThan (FlagConstant [fc])) => (MOVDconst [b2i(fc.lt())])
|
||||
(LessThanU (FlagConstant [fc])) => (MOVDconst [b2i(fc.ult())])
|
||||
(LessEqual (FlagConstant [fc])) => (MOVDconst [b2i(fc.le())])
|
||||
(LessEqualU (FlagConstant [fc])) => (MOVDconst [b2i(fc.ule())])
|
||||
(GreaterThan (FlagConstant [fc])) => (MOVDconst [b2i(fc.gt())])
|
||||
(GreaterThanU (FlagConstant [fc])) => (MOVDconst [b2i(fc.ugt())])
|
||||
(GreaterEqual (FlagConstant [fc])) => (MOVDconst [b2i(fc.ge())])
|
||||
(GreaterEqualU (FlagConstant [fc])) => (MOVDconst [b2i(fc.uge())])
|
||||
|
||||
// absorb InvertFlags into boolean values
|
||||
(Equal (InvertFlags x)) -> (Equal x)
|
||||
|
|
|
|||
|
|
@ -587,18 +587,12 @@ func init() {
|
|||
// See runtime/stubs.go for a more detailed discussion.
|
||||
{name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true},
|
||||
|
||||
// Constant flag values. For any comparison, there are 5 possible
|
||||
// outcomes: the three from the signed total order (<,==,>) and the
|
||||
// three from the unsigned total order. The == cases overlap.
|
||||
// Note: there's a sixth "unordered" outcome for floating-point
|
||||
// Constant flag value.
|
||||
// Note: there's an "unordered" outcome for floating-point
|
||||
// comparisons, but we don't use such a beast yet.
|
||||
// These ops are for temporary use by rewrite rules. They
|
||||
// This op is for temporary use by rewrite rules. It
|
||||
// cannot appear in the generated assembly.
|
||||
{name: "FlagEQ"}, // equal
|
||||
{name: "FlagLT_ULT"}, // signed < and unsigned <
|
||||
{name: "FlagLT_UGT"}, // signed < and unsigned >
|
||||
{name: "FlagGT_UGT"}, // signed > and unsigned <
|
||||
{name: "FlagGT_ULT"}, // signed > and unsigned >
|
||||
{name: "FlagConstant", aux: "FlagConstant"},
|
||||
|
||||
// (InvertFlags (CMP a b)) == (CMP b a)
|
||||
// InvertFlags is a pseudo-op which can't appear in assembly output.
|
||||
|
|
|
|||
|
|
@ -550,18 +550,12 @@ func init() {
|
|||
{name: "LoweredPanicExtendB", argLength: 4, aux: "Int64", reg: regInfo{inputs: []regMask{r4, r1, r2}}, typ: "Mem", call: true}, // arg0=idxHi, arg1=idxLo, arg2=len, arg3=mem, returns memory. AuxInt contains report code (see PanicExtend in genericOps.go).
|
||||
{name: "LoweredPanicExtendC", argLength: 4, aux: "Int64", reg: regInfo{inputs: []regMask{r4, r0, r1}}, typ: "Mem", call: true}, // arg0=idxHi, arg1=idxLo, arg2=len, arg3=mem, returns memory. AuxInt contains report code (see PanicExtend in genericOps.go).
|
||||
|
||||
// Constant flag values. For any comparison, there are 5 possible
|
||||
// outcomes: the three from the signed total order (<,==,>) and the
|
||||
// three from the unsigned total order. The == cases overlap.
|
||||
// Note: there's a sixth "unordered" outcome for floating-point
|
||||
// Constant flag value.
|
||||
// Note: there's an "unordered" outcome for floating-point
|
||||
// comparisons, but we don't use such a beast yet.
|
||||
// These ops are for temporary use by rewrite rules. They
|
||||
// This op is for temporary use by rewrite rules. It
|
||||
// cannot appear in the generated assembly.
|
||||
{name: "FlagEQ"}, // equal
|
||||
{name: "FlagLT_ULT"}, // signed < and unsigned <
|
||||
{name: "FlagLT_UGT"}, // signed < and unsigned >
|
||||
{name: "FlagGT_UGT"}, // signed > and unsigned <
|
||||
{name: "FlagGT_ULT"}, // signed > and unsigned >
|
||||
{name: "FlagConstant", aux: "FlagConstant"},
|
||||
|
||||
// (InvertFlags (CMP a b)) == (CMP b a)
|
||||
// InvertFlags is a pseudo-op which can't appear in assembly output.
|
||||
|
|
|
|||
|
|
@ -396,22 +396,23 @@ func init() {
|
|||
|
||||
{name: "LDGR", argLength: 1, reg: gpfp, asm: "LDGR"}, // move int64 to float64 (no conversion)
|
||||
{name: "LGDR", argLength: 1, reg: fpgp, asm: "LGDR"}, // move float64 to int64 (no conversion)
|
||||
{name: "CFDBRA", argLength: 1, reg: fpgp, asm: "CFDBRA"}, // convert float64 to int32
|
||||
{name: "CGDBRA", argLength: 1, reg: fpgp, asm: "CGDBRA"}, // convert float64 to int64
|
||||
{name: "CFEBRA", argLength: 1, reg: fpgp, asm: "CFEBRA"}, // convert float32 to int32
|
||||
{name: "CGEBRA", argLength: 1, reg: fpgp, asm: "CGEBRA"}, // convert float32 to int64
|
||||
{name: "CEFBRA", argLength: 1, reg: gpfp, asm: "CEFBRA"}, // convert int32 to float32
|
||||
{name: "CDFBRA", argLength: 1, reg: gpfp, asm: "CDFBRA"}, // convert int32 to float64
|
||||
{name: "CEGBRA", argLength: 1, reg: gpfp, asm: "CEGBRA"}, // convert int64 to float32
|
||||
{name: "CDGBRA", argLength: 1, reg: gpfp, asm: "CDGBRA"}, // convert int64 to float64
|
||||
{name: "CLFEBR", argLength: 1, reg: fpgp, asm: "CLFEBR"}, // convert float32 to uint32
|
||||
{name: "CLFDBR", argLength: 1, reg: fpgp, asm: "CLFDBR"}, // convert float64 to uint32
|
||||
{name: "CLGEBR", argLength: 1, reg: fpgp, asm: "CLGEBR"}, // convert float32 to uint64
|
||||
{name: "CLGDBR", argLength: 1, reg: fpgp, asm: "CLGDBR"}, // convert float64 to uint64
|
||||
{name: "CELFBR", argLength: 1, reg: gpfp, asm: "CELFBR"}, // convert uint32 to float32
|
||||
{name: "CDLFBR", argLength: 1, reg: gpfp, asm: "CDLFBR"}, // convert uint32 to float64
|
||||
{name: "CELGBR", argLength: 1, reg: gpfp, asm: "CELGBR"}, // convert uint64 to float32
|
||||
{name: "CDLGBR", argLength: 1, reg: gpfp, asm: "CDLGBR"}, // convert uint64 to float64
|
||||
|
||||
{name: "CFDBRA", argLength: 1, reg: fpgp, asm: "CFDBRA", clobberFlags: true}, // convert float64 to int32
|
||||
{name: "CGDBRA", argLength: 1, reg: fpgp, asm: "CGDBRA", clobberFlags: true}, // convert float64 to int64
|
||||
{name: "CFEBRA", argLength: 1, reg: fpgp, asm: "CFEBRA", clobberFlags: true}, // convert float32 to int32
|
||||
{name: "CGEBRA", argLength: 1, reg: fpgp, asm: "CGEBRA", clobberFlags: true}, // convert float32 to int64
|
||||
{name: "CEFBRA", argLength: 1, reg: gpfp, asm: "CEFBRA", clobberFlags: true}, // convert int32 to float32
|
||||
{name: "CDFBRA", argLength: 1, reg: gpfp, asm: "CDFBRA", clobberFlags: true}, // convert int32 to float64
|
||||
{name: "CEGBRA", argLength: 1, reg: gpfp, asm: "CEGBRA", clobberFlags: true}, // convert int64 to float32
|
||||
{name: "CDGBRA", argLength: 1, reg: gpfp, asm: "CDGBRA", clobberFlags: true}, // convert int64 to float64
|
||||
{name: "CLFEBR", argLength: 1, reg: fpgp, asm: "CLFEBR", clobberFlags: true}, // convert float32 to uint32
|
||||
{name: "CLFDBR", argLength: 1, reg: fpgp, asm: "CLFDBR", clobberFlags: true}, // convert float64 to uint32
|
||||
{name: "CLGEBR", argLength: 1, reg: fpgp, asm: "CLGEBR", clobberFlags: true}, // convert float32 to uint64
|
||||
{name: "CLGDBR", argLength: 1, reg: fpgp, asm: "CLGDBR", clobberFlags: true}, // convert float64 to uint64
|
||||
{name: "CELFBR", argLength: 1, reg: gpfp, asm: "CELFBR", clobberFlags: true}, // convert uint32 to float32
|
||||
{name: "CDLFBR", argLength: 1, reg: gpfp, asm: "CDLFBR", clobberFlags: true}, // convert uint32 to float64
|
||||
{name: "CELGBR", argLength: 1, reg: gpfp, asm: "CELGBR", clobberFlags: true}, // convert uint64 to float32
|
||||
{name: "CDLGBR", argLength: 1, reg: gpfp, asm: "CDLGBR", clobberFlags: true}, // convert uint64 to float64
|
||||
|
||||
{name: "LEDBR", argLength: 1, reg: fp11, asm: "LEDBR"}, // convert float64 to float32
|
||||
{name: "LDEBR", argLength: 1, reg: fp11, asm: "LDEBR"}, // convert float32 to float64
|
||||
|
|
|
|||
|
|
@ -1423,7 +1423,7 @@ func parseValue(val string, arch arch, loc string) (op opData, oparch, typ, auxi
|
|||
|
||||
func opHasAuxInt(op opData) bool {
|
||||
switch op.aux {
|
||||
case "Bool", "Int8", "Int16", "Int32", "Int64", "Int128", "Float32", "Float64", "SymOff", "SymValAndOff", "TypSize", "ARM64BitField":
|
||||
case "Bool", "Int8", "Int16", "Int32", "Int64", "Int128", "Float32", "Float64", "SymOff", "SymValAndOff", "TypSize", "ARM64BitField", "FlagConstant":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
|
@ -1818,6 +1818,8 @@ func (op opData) auxIntType() string {
|
|||
return "int64"
|
||||
case "CCop":
|
||||
return "Op"
|
||||
case "FlagConstant":
|
||||
return "flagConstant"
|
||||
default:
|
||||
return "invalid"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ const (
|
|||
auxInt128 // auxInt represents a 128-bit integer. Always 0.
|
||||
auxFloat32 // auxInt is a float32 (encoded with math.Float64bits)
|
||||
auxFloat64 // auxInt is a float64 (encoded with math.Float64bits)
|
||||
auxFlagConstant // auxInt is a flagConstant
|
||||
auxString // aux is a string
|
||||
auxSym // aux is a symbol (a *gc.Node for locals, an *obj.LSym for globals, or nil for none)
|
||||
auxSymOff // aux is a symbol, auxInt is an offset
|
||||
|
|
|
|||
|
|
@ -1283,11 +1283,7 @@ const (
|
|||
OpARMLoweredPanicExtendA
|
||||
OpARMLoweredPanicExtendB
|
||||
OpARMLoweredPanicExtendC
|
||||
OpARMFlagEQ
|
||||
OpARMFlagLT_ULT
|
||||
OpARMFlagLT_UGT
|
||||
OpARMFlagGT_UGT
|
||||
OpARMFlagGT_ULT
|
||||
OpARMFlagConstant
|
||||
OpARMInvertFlags
|
||||
OpARMLoweredWB
|
||||
|
||||
|
|
@ -1558,11 +1554,7 @@ const (
|
|||
OpARM64LoweredGetClosurePtr
|
||||
OpARM64LoweredGetCallerSP
|
||||
OpARM64LoweredGetCallerPC
|
||||
OpARM64FlagEQ
|
||||
OpARM64FlagLT_ULT
|
||||
OpARM64FlagLT_UGT
|
||||
OpARM64FlagGT_UGT
|
||||
OpARM64FlagGT_ULT
|
||||
OpARM64FlagConstant
|
||||
OpARM64InvertFlags
|
||||
OpARM64LDAR
|
||||
OpARM64LDARB
|
||||
|
|
@ -16911,27 +16903,8 @@ var opcodeTable = [...]opInfo{
|
|||
},
|
||||
},
|
||||
{
|
||||
name: "FlagEQ",
|
||||
argLen: 0,
|
||||
reg: regInfo{},
|
||||
},
|
||||
{
|
||||
name: "FlagLT_ULT",
|
||||
argLen: 0,
|
||||
reg: regInfo{},
|
||||
},
|
||||
{
|
||||
name: "FlagLT_UGT",
|
||||
argLen: 0,
|
||||
reg: regInfo{},
|
||||
},
|
||||
{
|
||||
name: "FlagGT_UGT",
|
||||
argLen: 0,
|
||||
reg: regInfo{},
|
||||
},
|
||||
{
|
||||
name: "FlagGT_ULT",
|
||||
name: "FlagConstant",
|
||||
auxType: auxFlagConstant,
|
||||
argLen: 0,
|
||||
reg: regInfo{},
|
||||
},
|
||||
|
|
@ -20521,27 +20494,8 @@ var opcodeTable = [...]opInfo{
|
|||
},
|
||||
},
|
||||
{
|
||||
name: "FlagEQ",
|
||||
argLen: 0,
|
||||
reg: regInfo{},
|
||||
},
|
||||
{
|
||||
name: "FlagLT_ULT",
|
||||
argLen: 0,
|
||||
reg: regInfo{},
|
||||
},
|
||||
{
|
||||
name: "FlagLT_UGT",
|
||||
argLen: 0,
|
||||
reg: regInfo{},
|
||||
},
|
||||
{
|
||||
name: "FlagGT_UGT",
|
||||
argLen: 0,
|
||||
reg: regInfo{},
|
||||
},
|
||||
{
|
||||
name: "FlagGT_ULT",
|
||||
name: "FlagConstant",
|
||||
auxType: auxFlagConstant,
|
||||
argLen: 0,
|
||||
reg: regInfo{},
|
||||
},
|
||||
|
|
@ -30193,6 +30147,7 @@ var opcodeTable = [...]opInfo{
|
|||
{
|
||||
name: "CFDBRA",
|
||||
argLen: 1,
|
||||
clobberFlags: true,
|
||||
asm: s390x.ACFDBRA,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
|
|
@ -30206,6 +30161,7 @@ var opcodeTable = [...]opInfo{
|
|||
{
|
||||
name: "CGDBRA",
|
||||
argLen: 1,
|
||||
clobberFlags: true,
|
||||
asm: s390x.ACGDBRA,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
|
|
@ -30219,6 +30175,7 @@ var opcodeTable = [...]opInfo{
|
|||
{
|
||||
name: "CFEBRA",
|
||||
argLen: 1,
|
||||
clobberFlags: true,
|
||||
asm: s390x.ACFEBRA,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
|
|
@ -30232,6 +30189,7 @@ var opcodeTable = [...]opInfo{
|
|||
{
|
||||
name: "CGEBRA",
|
||||
argLen: 1,
|
||||
clobberFlags: true,
|
||||
asm: s390x.ACGEBRA,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
|
|
@ -30245,6 +30203,7 @@ var opcodeTable = [...]opInfo{
|
|||
{
|
||||
name: "CEFBRA",
|
||||
argLen: 1,
|
||||
clobberFlags: true,
|
||||
asm: s390x.ACEFBRA,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
|
|
@ -30258,6 +30217,7 @@ var opcodeTable = [...]opInfo{
|
|||
{
|
||||
name: "CDFBRA",
|
||||
argLen: 1,
|
||||
clobberFlags: true,
|
||||
asm: s390x.ACDFBRA,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
|
|
@ -30271,6 +30231,7 @@ var opcodeTable = [...]opInfo{
|
|||
{
|
||||
name: "CEGBRA",
|
||||
argLen: 1,
|
||||
clobberFlags: true,
|
||||
asm: s390x.ACEGBRA,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
|
|
@ -30284,6 +30245,7 @@ var opcodeTable = [...]opInfo{
|
|||
{
|
||||
name: "CDGBRA",
|
||||
argLen: 1,
|
||||
clobberFlags: true,
|
||||
asm: s390x.ACDGBRA,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
|
|
@ -30297,6 +30259,7 @@ var opcodeTable = [...]opInfo{
|
|||
{
|
||||
name: "CLFEBR",
|
||||
argLen: 1,
|
||||
clobberFlags: true,
|
||||
asm: s390x.ACLFEBR,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
|
|
@ -30310,6 +30273,7 @@ var opcodeTable = [...]opInfo{
|
|||
{
|
||||
name: "CLFDBR",
|
||||
argLen: 1,
|
||||
clobberFlags: true,
|
||||
asm: s390x.ACLFDBR,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
|
|
@ -30323,6 +30287,7 @@ var opcodeTable = [...]opInfo{
|
|||
{
|
||||
name: "CLGEBR",
|
||||
argLen: 1,
|
||||
clobberFlags: true,
|
||||
asm: s390x.ACLGEBR,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
|
|
@ -30336,6 +30301,7 @@ var opcodeTable = [...]opInfo{
|
|||
{
|
||||
name: "CLGDBR",
|
||||
argLen: 1,
|
||||
clobberFlags: true,
|
||||
asm: s390x.ACLGDBR,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
|
|
@ -30349,6 +30315,7 @@ var opcodeTable = [...]opInfo{
|
|||
{
|
||||
name: "CELFBR",
|
||||
argLen: 1,
|
||||
clobberFlags: true,
|
||||
asm: s390x.ACELFBR,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
|
|
@ -30362,6 +30329,7 @@ var opcodeTable = [...]opInfo{
|
|||
{
|
||||
name: "CDLFBR",
|
||||
argLen: 1,
|
||||
clobberFlags: true,
|
||||
asm: s390x.ACDLFBR,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
|
|
@ -30375,6 +30343,7 @@ var opcodeTable = [...]opInfo{
|
|||
{
|
||||
name: "CELGBR",
|
||||
argLen: 1,
|
||||
clobberFlags: true,
|
||||
asm: s390x.ACELGBR,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
|
|
@ -30388,6 +30357,7 @@ var opcodeTable = [...]opInfo{
|
|||
{
|
||||
name: "CDLGBR",
|
||||
argLen: 1,
|
||||
clobberFlags: true,
|
||||
asm: s390x.ACDLGBR,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
|
|
|
|||
|
|
@ -511,6 +511,14 @@ func b2i(b bool) int64 {
|
|||
return 0
|
||||
}
|
||||
|
||||
// b2i32 translates a boolean value to 0 or 1.
|
||||
func b2i32(b bool) int32 {
|
||||
if b {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// shiftIsBounded reports whether (left/right) shift Value v is known to be bounded.
|
||||
// A shift is bounded if it is shifting by less than the width of the shifted value.
|
||||
func shiftIsBounded(v *Value) bool {
|
||||
|
|
@ -616,6 +624,9 @@ func auxIntToInt128(x int64) int128 {
|
|||
}
|
||||
return 0
|
||||
}
|
||||
func auxIntToFlagConstant(x int64) flagConstant {
|
||||
return flagConstant(x)
|
||||
}
|
||||
|
||||
func boolToAuxInt(b bool) int64 {
|
||||
if b {
|
||||
|
|
@ -653,6 +664,9 @@ func int128ToAuxInt(x int128) int64 {
|
|||
}
|
||||
return 0
|
||||
}
|
||||
func flagConstantToAuxInt(x flagConstant) int64 {
|
||||
return int64(x)
|
||||
}
|
||||
|
||||
func auxToString(i interface{}) string {
|
||||
return i.(string)
|
||||
|
|
@ -997,52 +1011,42 @@ func arm64Invert(op Op) Op {
|
|||
func ccARM64Eval(cc interface{}, flags *Value) int {
|
||||
op := cc.(Op)
|
||||
fop := flags.Op
|
||||
switch fop {
|
||||
case OpARM64InvertFlags:
|
||||
if fop == OpARM64InvertFlags {
|
||||
return -ccARM64Eval(op, flags.Args[0])
|
||||
case OpARM64FlagEQ:
|
||||
switch op {
|
||||
case OpARM64Equal, OpARM64GreaterEqual, OpARM64LessEqual,
|
||||
OpARM64GreaterEqualU, OpARM64LessEqualU:
|
||||
return 1
|
||||
default:
|
||||
return -1
|
||||
}
|
||||
case OpARM64FlagLT_ULT:
|
||||
switch op {
|
||||
case OpARM64LessThan, OpARM64LessThanU,
|
||||
OpARM64LessEqual, OpARM64LessEqualU:
|
||||
return 1
|
||||
default:
|
||||
return -1
|
||||
}
|
||||
case OpARM64FlagLT_UGT:
|
||||
switch op {
|
||||
case OpARM64LessThan, OpARM64GreaterThanU,
|
||||
OpARM64LessEqual, OpARM64GreaterEqualU:
|
||||
return 1
|
||||
default:
|
||||
return -1
|
||||
}
|
||||
case OpARM64FlagGT_ULT:
|
||||
switch op {
|
||||
case OpARM64GreaterThan, OpARM64LessThanU,
|
||||
OpARM64GreaterEqual, OpARM64LessEqualU:
|
||||
return 1
|
||||
default:
|
||||
return -1
|
||||
}
|
||||
case OpARM64FlagGT_UGT:
|
||||
switch op {
|
||||
case OpARM64GreaterThan, OpARM64GreaterThanU,
|
||||
OpARM64GreaterEqual, OpARM64GreaterEqualU:
|
||||
return 1
|
||||
default:
|
||||
return -1
|
||||
}
|
||||
default:
|
||||
if fop != OpARM64FlagConstant {
|
||||
return 0
|
||||
}
|
||||
fc := flagConstant(flags.AuxInt)
|
||||
b2i := func(b bool) int {
|
||||
if b {
|
||||
return 1
|
||||
}
|
||||
return -1
|
||||
}
|
||||
switch op {
|
||||
case OpARM64Equal:
|
||||
return b2i(fc.eq())
|
||||
case OpARM64NotEqual:
|
||||
return b2i(fc.ne())
|
||||
case OpARM64LessThan:
|
||||
return b2i(fc.lt())
|
||||
case OpARM64LessThanU:
|
||||
return b2i(fc.ult())
|
||||
case OpARM64GreaterThan:
|
||||
return b2i(fc.gt())
|
||||
case OpARM64GreaterThanU:
|
||||
return b2i(fc.ugt())
|
||||
case OpARM64LessEqual:
|
||||
return b2i(fc.le())
|
||||
case OpARM64LessEqualU:
|
||||
return b2i(fc.ule())
|
||||
case OpARM64GreaterEqual:
|
||||
return b2i(fc.ge())
|
||||
case OpARM64GreaterEqualU:
|
||||
return b2i(fc.uge())
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// logRule logs the use of the rule s. This will only be enabled if
|
||||
|
|
@ -1473,3 +1477,170 @@ func sequentialAddresses(x, y *Value, n int64) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// flagConstant represents the result of a compile-time comparison.
|
||||
// The sense of these flags does not necessarily represent the hardware's notion
|
||||
// of a flags register - these are just a compile-time construct.
|
||||
// We happen to match the semantics to those of arm/arm64.
|
||||
// Note that these semantics differ from x86: the carry flag has the opposite
|
||||
// sense on a subtraction!
|
||||
// On amd64, C=1 represents a borrow, e.g. SBB on amd64 does x - y - C.
|
||||
// On arm64, C=0 represents a borrow, e.g. SBC on arm64 does x - y - ^C.
|
||||
// (because it does x + ^y + C).
|
||||
// See https://en.wikipedia.org/wiki/Carry_flag#Vs._borrow_flag
|
||||
type flagConstant uint8
|
||||
|
||||
// N reports whether the result of an operation is negative (high bit set).
|
||||
func (fc flagConstant) N() bool {
|
||||
return fc&1 != 0
|
||||
}
|
||||
|
||||
// Z reports whether the result of an operation is 0.
|
||||
func (fc flagConstant) Z() bool {
|
||||
return fc&2 != 0
|
||||
}
|
||||
|
||||
// C reports whether an unsigned add overflowed (carry), or an
|
||||
// unsigned subtract did not underflow (borrow).
|
||||
func (fc flagConstant) C() bool {
|
||||
return fc&4 != 0
|
||||
}
|
||||
|
||||
// V reports whether a signed operation overflowed or underflowed.
|
||||
func (fc flagConstant) V() bool {
|
||||
return fc&8 != 0
|
||||
}
|
||||
|
||||
func (fc flagConstant) eq() bool {
|
||||
return fc.Z()
|
||||
}
|
||||
func (fc flagConstant) ne() bool {
|
||||
return !fc.Z()
|
||||
}
|
||||
func (fc flagConstant) lt() bool {
|
||||
return fc.N() != fc.V()
|
||||
}
|
||||
func (fc flagConstant) le() bool {
|
||||
return fc.Z() || fc.lt()
|
||||
}
|
||||
func (fc flagConstant) gt() bool {
|
||||
return !fc.Z() && fc.ge()
|
||||
}
|
||||
func (fc flagConstant) ge() bool {
|
||||
return fc.N() == fc.V()
|
||||
}
|
||||
func (fc flagConstant) ult() bool {
|
||||
return !fc.C()
|
||||
}
|
||||
func (fc flagConstant) ule() bool {
|
||||
return fc.Z() || fc.ult()
|
||||
}
|
||||
func (fc flagConstant) ugt() bool {
|
||||
return !fc.Z() && fc.uge()
|
||||
}
|
||||
func (fc flagConstant) uge() bool {
|
||||
return fc.C()
|
||||
}
|
||||
|
||||
func (fc flagConstant) ltNoov() bool {
|
||||
return fc.lt() && !fc.V()
|
||||
}
|
||||
func (fc flagConstant) leNoov() bool {
|
||||
return fc.le() && !fc.V()
|
||||
}
|
||||
func (fc flagConstant) gtNoov() bool {
|
||||
return fc.gt() && !fc.V()
|
||||
}
|
||||
func (fc flagConstant) geNoov() bool {
|
||||
return fc.ge() && !fc.V()
|
||||
}
|
||||
|
||||
func (fc flagConstant) String() string {
|
||||
return fmt.Sprintf("N=%v,Z=%v,C=%v,V=%v", fc.N(), fc.Z(), fc.C(), fc.V())
|
||||
}
|
||||
|
||||
type flagConstantBuilder struct {
|
||||
N bool
|
||||
Z bool
|
||||
C bool
|
||||
V bool
|
||||
}
|
||||
|
||||
func (fcs flagConstantBuilder) encode() flagConstant {
|
||||
var fc flagConstant
|
||||
if fcs.N {
|
||||
fc |= 1
|
||||
}
|
||||
if fcs.Z {
|
||||
fc |= 2
|
||||
}
|
||||
if fcs.C {
|
||||
fc |= 4
|
||||
}
|
||||
if fcs.V {
|
||||
fc |= 8
|
||||
}
|
||||
return fc
|
||||
}
|
||||
|
||||
// Note: addFlags(x,y) != subFlags(x,-y) in some situations:
|
||||
// - the results of the C flag are different
|
||||
// - the results of the V flag when y==minint are different
|
||||
|
||||
// addFlags64 returns the flags that would be set from computing x+y.
|
||||
func addFlags64(x, y int64) flagConstant {
|
||||
var fcb flagConstantBuilder
|
||||
fcb.Z = x+y == 0
|
||||
fcb.N = x+y < 0
|
||||
fcb.C = uint64(x+y) < uint64(x)
|
||||
fcb.V = x >= 0 && y >= 0 && x+y < 0 || x < 0 && y < 0 && x+y >= 0
|
||||
return fcb.encode()
|
||||
}
|
||||
|
||||
// subFlags64 returns the flags that would be set from computing x-y.
|
||||
func subFlags64(x, y int64) flagConstant {
|
||||
var fcb flagConstantBuilder
|
||||
fcb.Z = x-y == 0
|
||||
fcb.N = x-y < 0
|
||||
fcb.C = uint64(y) <= uint64(x) // This code follows the arm carry flag model.
|
||||
fcb.V = x >= 0 && y < 0 && x-y < 0 || x < 0 && y >= 0 && x-y >= 0
|
||||
return fcb.encode()
|
||||
}
|
||||
|
||||
// addFlags32 returns the flags that would be set from computing x+y.
|
||||
func addFlags32(x, y int32) flagConstant {
|
||||
var fcb flagConstantBuilder
|
||||
fcb.Z = x+y == 0
|
||||
fcb.N = x+y < 0
|
||||
fcb.C = uint32(x+y) < uint32(x)
|
||||
fcb.V = x >= 0 && y >= 0 && x+y < 0 || x < 0 && y < 0 && x+y >= 0
|
||||
return fcb.encode()
|
||||
}
|
||||
|
||||
// subFlags32 returns the flags that would be set from computing x-y.
|
||||
func subFlags32(x, y int32) flagConstant {
|
||||
var fcb flagConstantBuilder
|
||||
fcb.Z = x-y == 0
|
||||
fcb.N = x-y < 0
|
||||
fcb.C = uint32(y) <= uint32(x) // This code follows the arm carry flag model.
|
||||
fcb.V = x >= 0 && y < 0 && x-y < 0 || x < 0 && y >= 0 && x-y >= 0
|
||||
return fcb.encode()
|
||||
}
|
||||
|
||||
// logicFlags64 returns flags set to the sign/zeroness of x.
|
||||
// C and V are set to false.
|
||||
func logicFlags64(x int64) flagConstant {
|
||||
var fcb flagConstantBuilder
|
||||
fcb.Z = x == 0
|
||||
fcb.N = x < 0
|
||||
return fcb.encode()
|
||||
}
|
||||
|
||||
// logicFlags32 returns flags set to the sign/zeroness of x.
|
||||
// C and V are set to false.
|
||||
func logicFlags32(x int32) flagConstant {
|
||||
var fcb flagConstantBuilder
|
||||
fcb.Z = x == 0
|
||||
fcb.N = x < 0
|
||||
return fcb.encode()
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -206,6 +206,8 @@ func (v *Value) auxString() string {
|
|||
return fmt.Sprintf(" {%s}", v.Aux.(Op))
|
||||
case auxS390XCCMask, auxS390XRotateParams:
|
||||
return fmt.Sprintf(" {%v}", v.Aux)
|
||||
case auxFlagConstant:
|
||||
return fmt.Sprintf("[%s]", flagConstant(v.AuxInt))
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
|
|
|||
1
src/cmd/dist/buildtool.go
vendored
1
src/cmd/dist/buildtool.go
vendored
|
|
@ -115,6 +115,7 @@ var ignorePrefixes = []string{
|
|||
// These must not be copied into the bootstrap build directory.
|
||||
var ignoreSuffixes = []string{
|
||||
"_arm64.s",
|
||||
"_arm64_test.s",
|
||||
"_arm64.go",
|
||||
"_riscv64.s",
|
||||
"_riscv64.go",
|
||||
|
|
|
|||
|
|
@ -9,5 +9,5 @@ require (
|
|||
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79
|
||||
golang.org/x/mod v0.3.0
|
||||
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 // indirect
|
||||
golang.org/x/tools v0.0.0-20200601175630-2caf76543d99
|
||||
golang.org/x/tools v0.0.0-20200616133436-c1934b75d054
|
||||
)
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 h1:5B6i6EAiSYyejWfvc5Rc9BbI3
|
|||
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200601175630-2caf76543d99 h1:deddXmhOJb/bvD/4M/j2AUMrhHeh6GkqykJSCWyTNVk=
|
||||
golang.org/x/tools v0.0.0-20200601175630-2caf76543d99/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200616133436-c1934b75d054 h1:HHeAlu5H9b71C+Fx0K+1dGgVFN1DM1/wz4aoGOA5qS8=
|
||||
golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
|
|
|
|||
3
src/cmd/go/testdata/script/generate_env.txt
vendored
3
src/cmd/go/testdata/script/generate_env.txt
vendored
|
|
@ -1,7 +1,8 @@
|
|||
# Install an env command because Windows and plan9 don't have it.
|
||||
env GOBIN=$WORK/tmp/bin
|
||||
go install env.go
|
||||
env PATH=$GOBIN${:}$PATH
|
||||
[plan9] env path=$GOBIN${:}$path
|
||||
[!plan9] env PATH=$GOBIN${:}$PATH
|
||||
|
||||
# Test generators have access to the environment
|
||||
go generate ./printenv.go
|
||||
|
|
|
|||
|
|
@ -24,7 +24,8 @@ grep '{"Version":"v1.0.0","Time":"2018-02-14T00:45:20Z"}' $GOPATH/pkg/mod/cache/
|
|||
|
||||
# If neither GOMODCACHE or GOPATH are set, GOPATH defaults to the user's $HOME/go, so GOMODCACHE becomes $HOME/go/pkg/mod
|
||||
[windows] env USERPROFILE=$WORK/home # Ensure USERPROFILE is a valid path (rather than /no-home/ so we don't run into the logic that "uninfers" GOPATH in cmd/go/main.go
|
||||
[!windows] env HOME=$WORK/home
|
||||
[plan9] env home=$WORK/home
|
||||
[!windows] [!plan9] env HOME=$WORK/home
|
||||
env GOMODCACHE=
|
||||
env GOPATH=
|
||||
go env GOMODCACHE
|
||||
|
|
|
|||
|
|
@ -4,9 +4,7 @@
|
|||
|
||||
/*
|
||||
Package ppc64 implements a PPC64 assembler that assembles Go asm into
|
||||
the corresponding PPC64 binary instructions as defined by the Power
|
||||
ISA. Since POWER8 is the minimum instruction set used by GOARCHes ppc64le
|
||||
and ppc64, refer to ISA 2.07B or later for details.
|
||||
the corresponding PPC64 instructions as defined by the Power ISA 3.0B.
|
||||
|
||||
This document provides information on how to write code in Go assembler
|
||||
for PPC64, focusing on the differences between Go and PPC64 assembly language.
|
||||
|
|
@ -16,16 +14,24 @@ updates to the Go assembly language used mnemonics that are mostly similar if no
|
|||
identical to the PPC64 mneumonics, such as VMX and VSX instructions. Not all detail
|
||||
is included here; refer to the Power ISA document if interested in more detail.
|
||||
|
||||
Starting with Go 1.15 the Go objdump supports the -gnu option, which provides a
|
||||
side by side view of the Go assembler and the PPC64 assembler output. This is
|
||||
extremely helpful in determining what final PPC64 assembly is generated from the
|
||||
corresponding Go assembly.
|
||||
|
||||
In the examples below, the Go assembly is on the left, PPC64 assembly on the right.
|
||||
|
||||
1. Operand ordering
|
||||
|
||||
In Go asm, the last operand (right) is the target operand, but with PPC64 asm,
|
||||
the first operand (left) is the target. In general, the remaining operands are
|
||||
in the same order except in a few special cases, especially those with 4 operands.
|
||||
the first operand (left) is the target. The order of the remaining operands is
|
||||
not consistent: in general opcodes with 3 operands that perform math or logical
|
||||
operations have their operands in reverse order. Opcodes for vector instructions
|
||||
and those with more than 3 operands usually have operands in the same order except
|
||||
for the target operand, which is first in PPC64 asm and last in Go asm.
|
||||
|
||||
Example:
|
||||
ADD R3, R4, R5 <=> add r5, r3, r4
|
||||
ADD R3, R4, R5 <=> add r5, r4, r3
|
||||
|
||||
2. Constant operands
|
||||
|
||||
|
|
@ -179,6 +185,40 @@ In the examples below, the Go assembly is on the left, PPC64 assembly on the rig
|
|||
Functions in Go are aligned to 16 bytes, as is the case in all other compilers
|
||||
for PPC64.
|
||||
|
||||
6. Shift instructions
|
||||
|
||||
The simple scalar shifts on PPC64 expect a shift count that fits in 5 bits for
|
||||
32-bit values or 6 bit for 64-bit values. If the shift count is a constant value
|
||||
greater than the max then the assembler sets it to the max for that size (31 for
|
||||
32 bit values, 63 for 64 bit values). If the shift count is in a register, then
|
||||
only the low 5 or 6 bits of the register will be used as the shift count. The
|
||||
Go compiler will add appropriate code to compare the shift value to achieve the
|
||||
the correct result, and the assembler does not add extra checking.
|
||||
|
||||
Examples:
|
||||
|
||||
SRAD $8,R3,R4 => sradi r4,r3,8
|
||||
SRD $8,R3,R4 => rldicl r4,r3,56,8
|
||||
SLD $8,R3,R4 => rldicr r4,r3,8,55
|
||||
SRAW $16,R4,R5 => srawi r5,r4,16
|
||||
SRW $40,R4,R5 => rlwinm r5,r4,0,0,31
|
||||
SLW $12,R4,R5 => rlwinm r5,r4,12,0,19
|
||||
|
||||
Some non-simple shifts have operands in the Go assembly which don't map directly
|
||||
onto operands in the PPC64 assembly. When an operand in a shift instruction in the
|
||||
Go assembly is a bit mask, that mask is represented as a start and end bit in the
|
||||
PPC64 assembly instead of a mask. See the ISA for more detail on these types of shifts.
|
||||
Here are a few examples:
|
||||
|
||||
RLWMI $7,R3,$65535,R6 => rlwimi r6,r3,7,16,31
|
||||
RLDMI $0,R4,$7,R6 => rldimi r6,r4,0,61
|
||||
|
||||
More recently, Go opcodes were added which map directly onto the PPC64 opcodes. It is
|
||||
recommended to use the newer opcodes to avoid confusion.
|
||||
|
||||
RLDICL $0,R4,$15,R6 => rldicl r6,r4,0,15
|
||||
RLDICR $0,R4,$15,R6 => rldicr r6.r4,0,15
|
||||
|
||||
Register naming
|
||||
|
||||
1. Special register usage in Go asm
|
||||
|
|
|
|||
|
|
@ -722,3 +722,37 @@ func TestIndexMismatch(t *testing.T) {
|
|||
t.Errorf("did not see expected error message. out:\n%s", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPErsrc(t *testing.T) {
|
||||
// Test that PE rsrc section is handled correctly (issue 39658).
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
if runtime.GOARCH != "amd64" || runtime.GOOS != "windows" {
|
||||
t.Skipf("this is a windows/amd64-only test")
|
||||
}
|
||||
|
||||
tmpdir, err := ioutil.TempDir("", "TestPErsrc")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
pkgdir := filepath.Join("testdata", "testPErsrc")
|
||||
exe := filepath.Join(tmpdir, "a.exe")
|
||||
cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", exe)
|
||||
cmd.Dir = pkgdir
|
||||
// cmd.Env = append(os.Environ(), "GOOS=windows", "GOARCH=amd64") // uncomment if debugging in a cross-compiling environment
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("building failed: %v, output:\n%s", err, out)
|
||||
}
|
||||
|
||||
// Check that the binary contains the rsrc data
|
||||
b, err := ioutil.ReadFile(exe)
|
||||
if err != nil {
|
||||
t.Fatalf("reading output failed: %v", err)
|
||||
}
|
||||
if !bytes.Contains(b, []byte("Hello Gophers!")) {
|
||||
t.Fatalf("binary does not contain expected content")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
19
src/cmd/link/testdata/testPErsrc/main.go
vendored
Normal file
19
src/cmd/link/testdata/testPErsrc/main.go
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// 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 a PE rsrc section is handled correctly (issue 39658).
|
||||
//
|
||||
// rsrc.syso is created with:
|
||||
// windres -i a.rc -o rsrc.syso -O coff
|
||||
// on windows-amd64-2016 builder, where a.rc is a text file with
|
||||
// the following content:
|
||||
//
|
||||
// resname RCDATA {
|
||||
// "Hello Gophers!\0",
|
||||
// "This is a test.\0",
|
||||
// }
|
||||
|
||||
package main
|
||||
|
||||
func main() {}
|
||||
BIN
src/cmd/link/testdata/testPErsrc/rsrc.syso
vendored
Normal file
BIN
src/cmd/link/testdata/testPErsrc/rsrc.syso
vendored
Normal file
Binary file not shown.
9
src/cmd/vendor/golang.org/x/tools/go/analysis/doc.go
generated
vendored
9
src/cmd/vendor/golang.org/x/tools/go/analysis/doc.go
generated
vendored
|
|
@ -170,6 +170,15 @@ Diagnostic is defined as:
|
|||
The optional Category field is a short identifier that classifies the
|
||||
kind of message when an analysis produces several kinds of diagnostic.
|
||||
|
||||
Many analyses want to associate diagnostics with a severity level.
|
||||
Because Diagnostic does not have a severity level field, an Analyzer's
|
||||
diagnostics effectively all have the same severity level. To separate which
|
||||
diagnostics are high severity and which are low severity, expose multiple
|
||||
Analyzers instead. Analyzers should also be separated when their
|
||||
diagnostics belong in different groups, or could be tagged differently
|
||||
before being shown to the end user. Analyzers should document their severity
|
||||
level to help downstream tools surface diagnostics properly.
|
||||
|
||||
Most Analyzers inspect typed Go syntax trees, but a few, such as asmdecl
|
||||
and buildtag, inspect the raw text of Go source files or even non-Go
|
||||
files such as assembly. To report a diagnostic against a line of a
|
||||
|
|
|
|||
2
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/string.go
generated
vendored
2
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/string.go
generated
vendored
|
|
@ -101,7 +101,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
|
|||
}
|
||||
diag := analysis.Diagnostic{
|
||||
Pos: n.Pos(),
|
||||
Message: fmt.Sprintf("conversion from %s to %s yields a string of one rune", source, target),
|
||||
Message: fmt.Sprintf("conversion from %s to %s yields a string of one rune, not a string of digits (did you mean fmt.Sprint(x)?)", source, target),
|
||||
SuggestedFixes: []analysis.SuggestedFix{
|
||||
{
|
||||
Message: "Did you mean to convert a rune to a string?",
|
||||
|
|
|
|||
2
src/cmd/vendor/modules.txt
vendored
2
src/cmd/vendor/modules.txt
vendored
|
|
@ -45,7 +45,7 @@ golang.org/x/mod/zip
|
|||
golang.org/x/sys/internal/unsafeheader
|
||||
golang.org/x/sys/unix
|
||||
golang.org/x/sys/windows
|
||||
# golang.org/x/tools v0.0.0-20200601175630-2caf76543d99
|
||||
# golang.org/x/tools v0.0.0-20200616133436-c1934b75d054
|
||||
## explicit
|
||||
golang.org/x/tools/go/analysis
|
||||
golang.org/x/tools/go/analysis/internal/analysisflags
|
||||
|
|
|
|||
|
|
@ -212,9 +212,6 @@ type decodeState struct {
|
|||
savedError error
|
||||
useNumber bool
|
||||
disallowUnknownFields bool
|
||||
// safeUnquote is the number of current string literal bytes that don't
|
||||
// need to be unquoted. When negative, no bytes need unquoting.
|
||||
safeUnquote int
|
||||
}
|
||||
|
||||
// readIndex returns the position of the last byte read.
|
||||
|
|
@ -316,27 +313,13 @@ func (d *decodeState) rescanLiteral() {
|
|||
Switch:
|
||||
switch data[i-1] {
|
||||
case '"': // string
|
||||
// safeUnquote is initialized at -1, which means that all bytes
|
||||
// checked so far can be unquoted at a later time with no work
|
||||
// at all. When reaching the closing '"', if safeUnquote is
|
||||
// still -1, all bytes can be unquoted with no work. Otherwise,
|
||||
// only those bytes up until the first '\\' or non-ascii rune
|
||||
// can be safely unquoted.
|
||||
safeUnquote := -1
|
||||
for ; i < len(data); i++ {
|
||||
if c := data[i]; c == '\\' {
|
||||
if safeUnquote < 0 { // first unsafe byte
|
||||
safeUnquote = int(i - d.off)
|
||||
}
|
||||
switch data[i] {
|
||||
case '\\':
|
||||
i++ // escaped char
|
||||
} else if c == '"' {
|
||||
d.safeUnquote = safeUnquote
|
||||
case '"':
|
||||
i++ // tokenize the closing quote too
|
||||
break Switch
|
||||
} else if c >= utf8.RuneSelf {
|
||||
if safeUnquote < 0 { // first unsafe byte
|
||||
safeUnquote = int(i - d.off)
|
||||
}
|
||||
}
|
||||
}
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-': // number
|
||||
|
|
@ -695,7 +678,7 @@ func (d *decodeState) object(v reflect.Value) error {
|
|||
start := d.readIndex()
|
||||
d.rescanLiteral()
|
||||
item := d.data[start:d.readIndex()]
|
||||
key, ok := d.unquoteBytes(item)
|
||||
key, ok := unquoteBytes(item)
|
||||
if !ok {
|
||||
panic(phasePanicMsg)
|
||||
}
|
||||
|
|
@ -896,7 +879,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
|||
d.saveError(&UnmarshalTypeError{Value: val, Type: v.Type(), Offset: int64(d.readIndex())})
|
||||
return nil
|
||||
}
|
||||
s, ok := d.unquoteBytes(item)
|
||||
s, ok := unquoteBytes(item)
|
||||
if !ok {
|
||||
if fromQuoted {
|
||||
return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())
|
||||
|
|
@ -947,7 +930,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
|||
}
|
||||
|
||||
case '"': // string
|
||||
s, ok := d.unquoteBytes(item)
|
||||
s, ok := unquoteBytes(item)
|
||||
if !ok {
|
||||
if fromQuoted {
|
||||
return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())
|
||||
|
|
@ -1107,7 +1090,7 @@ func (d *decodeState) objectInterface() map[string]interface{} {
|
|||
start := d.readIndex()
|
||||
d.rescanLiteral()
|
||||
item := d.data[start:d.readIndex()]
|
||||
key, ok := d.unquote(item)
|
||||
key, ok := unquote(item)
|
||||
if !ok {
|
||||
panic(phasePanicMsg)
|
||||
}
|
||||
|
|
@ -1156,7 +1139,7 @@ func (d *decodeState) literalInterface() interface{} {
|
|||
return c == 't'
|
||||
|
||||
case '"': // string
|
||||
s, ok := d.unquote(item)
|
||||
s, ok := unquote(item)
|
||||
if !ok {
|
||||
panic(phasePanicMsg)
|
||||
}
|
||||
|
|
@ -1199,33 +1182,40 @@ func getu4(s []byte) rune {
|
|||
|
||||
// unquote converts a quoted JSON string literal s into an actual string t.
|
||||
// The rules are different than for Go, so cannot use strconv.Unquote.
|
||||
// The first byte in s must be '"'.
|
||||
func (d *decodeState) unquote(s []byte) (t string, ok bool) {
|
||||
s, ok = d.unquoteBytes(s)
|
||||
func unquote(s []byte) (t string, ok bool) {
|
||||
s, ok = unquoteBytes(s)
|
||||
t = string(s)
|
||||
return
|
||||
}
|
||||
|
||||
func (d *decodeState) unquoteBytes(s []byte) (t []byte, ok bool) {
|
||||
// We already know that s[0] == '"'. However, we don't know that the
|
||||
// closing quote exists in all cases, such as when the string is nested
|
||||
// via the ",string" option.
|
||||
if len(s) < 2 || s[len(s)-1] != '"' {
|
||||
func unquoteBytes(s []byte) (t []byte, ok bool) {
|
||||
if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' {
|
||||
return
|
||||
}
|
||||
s = s[1 : len(s)-1]
|
||||
|
||||
// If there are no unusual characters, no unquoting is needed, so return
|
||||
// a slice of the original bytes.
|
||||
r := d.safeUnquote
|
||||
if r == -1 {
|
||||
// Check for unusual characters. If there are none,
|
||||
// then no unquoting is needed, so return a slice of the
|
||||
// original bytes.
|
||||
r := 0
|
||||
for r < len(s) {
|
||||
c := s[r]
|
||||
if c == '\\' || c == '"' || c < ' ' {
|
||||
break
|
||||
}
|
||||
if c < utf8.RuneSelf {
|
||||
r++
|
||||
continue
|
||||
}
|
||||
rr, size := utf8.DecodeRune(s[r:])
|
||||
if rr == utf8.RuneError && size == 1 {
|
||||
break
|
||||
}
|
||||
r += size
|
||||
}
|
||||
if r == len(s) {
|
||||
return s, true
|
||||
}
|
||||
// Only perform up to one safe unquote for each re-scanned string
|
||||
// literal. In some edge cases, the decoder unquotes a literal a second
|
||||
// time, even after another literal has been re-scanned. Thus, only the
|
||||
// first unquote can safely use safeUnquote.
|
||||
d.safeUnquote = 0
|
||||
|
||||
b := make([]byte, len(s)+2*utf8.UTFMax)
|
||||
w := copy(b, s[0:r])
|
||||
|
|
|
|||
|
|
@ -2472,6 +2472,22 @@ func TestUnmarshalRescanLiteralMangledUnquote(t *testing.T) {
|
|||
if t1 != t2 {
|
||||
t.Errorf("Marshal and Unmarshal roundtrip mismatch: want %q got %q", t1, t2)
|
||||
}
|
||||
|
||||
// See golang.org/issues/39555.
|
||||
input := map[textUnmarshalerString]string{"FOO": "", `"`: ""}
|
||||
|
||||
encoded, err := Marshal(input)
|
||||
if err != nil {
|
||||
t.Fatalf("Marshal unexpected error: %v", err)
|
||||
}
|
||||
var got map[textUnmarshalerString]string
|
||||
if err := Unmarshal(encoded, &got); err != nil {
|
||||
t.Fatalf("Unmarshal unexpected error: %v", err)
|
||||
}
|
||||
want := map[textUnmarshalerString]string{"foo": "", `"`: ""}
|
||||
if !reflect.DeepEqual(want, got) {
|
||||
t.Fatalf("Unexpected roundtrip result:\nwant: %q\ngot: %q", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalMaxDepth(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -58,8 +58,11 @@ func (pos Position) String() string {
|
|||
// larger, representation.
|
||||
//
|
||||
// The Pos value for a given file is a number in the range [base, base+size],
|
||||
// where base and size are specified when adding the file to the file set via
|
||||
// AddFile.
|
||||
// where base and size are specified when a file is added to the file set.
|
||||
// The difference between a Pos value and the corresponding file base
|
||||
// corresponds to the byte offset of that position (represented by the Pos value)
|
||||
// from the beginning of the file. Thus, the file base offset is the Pos value
|
||||
// representing the first byte in the file.
|
||||
//
|
||||
// To create the Pos value for a specific source offset (measured in bytes),
|
||||
// first add the respective file to the current file set using FileSet.AddFile
|
||||
|
|
@ -364,6 +367,22 @@ func (f *File) Position(p Pos) (pos Position) {
|
|||
// Methods of file sets are synchronized; multiple goroutines
|
||||
// may invoke them concurrently.
|
||||
//
|
||||
// The byte offsets for each file in a file set are mapped into
|
||||
// distinct (integer) intervals, one interval [base, base+size]
|
||||
// per file. Base represents the first byte in the file, and size
|
||||
// is the corresponding file size. A Pos value is a value in such
|
||||
// an interval. By determining the interval a Pos value belongs
|
||||
// to, the file, its file base, and thus the byte offset (position)
|
||||
// the Pos value is representing can be computed.
|
||||
//
|
||||
// When adding a new file, a file base must be provided. That can
|
||||
// be any integer value that is past the end of any interval of any
|
||||
// file already in the file set. For convenience, FileSet.Base provides
|
||||
// such a value, which is simply the end of the Pos interval of the most
|
||||
// recently added file, plus one. Unless there is a need to extend an
|
||||
// interval later, using the FileSet.Base should be used as argument
|
||||
// for FileSet.AddFile.
|
||||
//
|
||||
type FileSet struct {
|
||||
mutex sync.RWMutex // protects the file set
|
||||
base int // base offset for the next file
|
||||
|
|
|
|||
|
|
@ -657,7 +657,6 @@ func TestEncodeWrappedImage(t *testing.T) {
|
|||
}
|
||||
|
||||
func BenchmarkEncode(b *testing.B) {
|
||||
bo := image.Rect(0, 0, 640, 480)
|
||||
rnd := rand.New(rand.NewSource(123))
|
||||
|
||||
// Restrict to a 256-color paletted image to avoid quantization path.
|
||||
|
|
@ -671,10 +670,8 @@ func BenchmarkEncode(b *testing.B) {
|
|||
}
|
||||
}
|
||||
img := image.NewPaletted(image.Rect(0, 0, 640, 480), palette)
|
||||
for y := bo.Min.Y; y < bo.Max.Y; y++ {
|
||||
for x := bo.Min.X; x < bo.Max.X; x++ {
|
||||
img.Set(x, y, palette[rnd.Intn(256)])
|
||||
}
|
||||
for i := range img.Pix {
|
||||
img.Pix[i] = uint8(rnd.Intn(256))
|
||||
}
|
||||
|
||||
b.SetBytes(640 * 480 * 4)
|
||||
|
|
|
|||
|
|
@ -511,6 +511,7 @@ func (t *Transport) roundTrip(req *Request) (*Response, error) {
|
|||
}
|
||||
}
|
||||
|
||||
origReq := req
|
||||
req = setupRewindBody(req)
|
||||
|
||||
if altRT := t.alternateRoundTripper(req); altRT != nil {
|
||||
|
|
@ -572,6 +573,7 @@ func (t *Transport) roundTrip(req *Request) (*Response, error) {
|
|||
resp, err = pconn.roundTrip(treq)
|
||||
}
|
||||
if err == nil {
|
||||
resp.Request = origReq
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3511,7 +3511,8 @@ func TestRetryRequestsOnError(t *testing.T) {
|
|||
|
||||
for i := 0; i < 3; i++ {
|
||||
t0 := time.Now()
|
||||
res, err := c.Do(tc.req())
|
||||
req := tc.req()
|
||||
res, err := c.Do(req)
|
||||
if err != nil {
|
||||
if time.Since(t0) < MaxWriteWaitBeforeConnReuse/2 {
|
||||
mu.Lock()
|
||||
|
|
@ -3522,6 +3523,9 @@ func TestRetryRequestsOnError(t *testing.T) {
|
|||
t.Skipf("connection likely wasn't recycled within %d, interfering with actual test; skipping", MaxWriteWaitBeforeConnReuse)
|
||||
}
|
||||
res.Body.Close()
|
||||
if res.Request != req {
|
||||
t.Errorf("Response.Request != original request; want identical Request")
|
||||
}
|
||||
}
|
||||
|
||||
mu.Lock()
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ type Call struct {
|
|||
Args interface{} // The argument to the function (*struct).
|
||||
Reply interface{} // The reply from the function (*struct).
|
||||
Error error // After completion, the error status.
|
||||
Done chan *Call // Strobes when call is complete.
|
||||
Done chan *Call // Receives *Call when Go is complete.
|
||||
}
|
||||
|
||||
// Client represents an RPC Client.
|
||||
|
|
|
|||
|
|
@ -824,6 +824,11 @@ var loop1, loop2 Loop
|
|||
var loopy1, loopy2 Loopy
|
||||
var cycleMap1, cycleMap2, cycleMap3 map[string]interface{}
|
||||
|
||||
type structWithSelfPtr struct {
|
||||
p *structWithSelfPtr
|
||||
s string
|
||||
}
|
||||
|
||||
func init() {
|
||||
loop1 = &loop2
|
||||
loop2 = &loop1
|
||||
|
|
@ -880,6 +885,7 @@ var deepEqualTests = []DeepEqualTest{
|
|||
{[]float64{math.NaN()}, self{}, true},
|
||||
{map[float64]float64{math.NaN(): 1}, map[float64]float64{1: 2}, false},
|
||||
{map[float64]float64{math.NaN(): 1}, self{}, true},
|
||||
{&structWithSelfPtr{p: &structWithSelfPtr{s: "a"}}, &structWithSelfPtr{p: &structWithSelfPtr{s: "b"}}, false},
|
||||
|
||||
// Nil vs empty: not the same.
|
||||
{[]int{}, []int(nil), false},
|
||||
|
|
|
|||
|
|
@ -45,8 +45,20 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool {
|
|||
}
|
||||
|
||||
if hard(v1, v2) {
|
||||
addr1 := v1.ptr
|
||||
addr2 := v2.ptr
|
||||
// For a Ptr or Map value, we need to check flagIndir,
|
||||
// which we do by calling the pointer method.
|
||||
// For Slice or Interface, flagIndir is always set,
|
||||
// and using v.ptr suffices.
|
||||
ptrval := func(v Value) unsafe.Pointer {
|
||||
switch v.Kind() {
|
||||
case Ptr, Map:
|
||||
return v.pointer()
|
||||
default:
|
||||
return v.ptr
|
||||
}
|
||||
}
|
||||
addr1 := ptrval(v1)
|
||||
addr2 := ptrval(v2)
|
||||
if uintptr(addr1) > uintptr(addr2) {
|
||||
// Canonicalize order to reduce number of entries in visited.
|
||||
// Assumes non-moving garbage collector.
|
||||
|
|
|
|||
|
|
@ -3068,6 +3068,7 @@ func ifaceIndir(t *rtype) bool {
|
|||
return t.kind&kindDirectIface == 0
|
||||
}
|
||||
|
||||
// Note: this type must agree with runtime.bitvector.
|
||||
type bitVector struct {
|
||||
n uint32 // number of bits
|
||||
data []byte
|
||||
|
|
|
|||
|
|
@ -589,6 +589,13 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer, retValid *bool) {
|
|||
// Convert v to type typ if v is assignable to a variable
|
||||
// of type t in the language spec.
|
||||
// See issue 28761.
|
||||
if typ.Kind() == Interface {
|
||||
// We must clear the destination before calling assignTo,
|
||||
// in case assignTo writes (with memory barriers) to the
|
||||
// target location used as scratch space. See issue 39541.
|
||||
*(*uintptr)(addr) = 0
|
||||
*(*uintptr)(add(addr, ptrSize, "typ.size == 2*ptrSize")) = 0
|
||||
}
|
||||
v = v.assignTo("reflect.MakeFunc", typ, addr)
|
||||
|
||||
// We are writing to stack. No write barrier.
|
||||
|
|
@ -2381,6 +2388,7 @@ func NewAt(typ Type, p unsafe.Pointer) Value {
|
|||
// assignTo returns a value v that can be assigned directly to typ.
|
||||
// It panics if v is not assignable to typ.
|
||||
// For a conversion to an interface type, target is a suggested scratch space to use.
|
||||
// target must be initialized memory (or nil).
|
||||
func (v Value) assignTo(context string, dst *rtype, target unsafe.Pointer) Value {
|
||||
if v.flag&flagMethod != 0 {
|
||||
v = makeMethodValue(context, v)
|
||||
|
|
|
|||
|
|
@ -12,57 +12,47 @@ import "unicode"
|
|||
// See https://swtch.com/~rsc/regexp/regexp1.html for inspiration.
|
||||
//
|
||||
// These aren't really pointers: they're integers, so we can reinterpret them
|
||||
// this way without using package unsafe. A value l denotes
|
||||
// p.inst[l>>1].Out (l&1==0) or .Arg (l&1==1).
|
||||
// l == 0 denotes the empty list, okay because we start every program
|
||||
// this way without using package unsafe. A value l.head denotes
|
||||
// p.inst[l.head>>1].Out (l.head&1==0) or .Arg (l.head&1==1).
|
||||
// head == 0 denotes the empty list, okay because we start every program
|
||||
// with a fail instruction, so we'll never want to point at its output link.
|
||||
type patchList uint32
|
||||
type patchList struct {
|
||||
head, tail uint32
|
||||
}
|
||||
|
||||
func (l patchList) next(p *Prog) patchList {
|
||||
i := &p.Inst[l>>1]
|
||||
if l&1 == 0 {
|
||||
return patchList(i.Out)
|
||||
}
|
||||
return patchList(i.Arg)
|
||||
func makePatchList(n uint32) patchList {
|
||||
return patchList{n, n}
|
||||
}
|
||||
|
||||
func (l patchList) patch(p *Prog, val uint32) {
|
||||
for l != 0 {
|
||||
i := &p.Inst[l>>1]
|
||||
if l&1 == 0 {
|
||||
l = patchList(i.Out)
|
||||
head := l.head
|
||||
for head != 0 {
|
||||
i := &p.Inst[head>>1]
|
||||
if head&1 == 0 {
|
||||
head = i.Out
|
||||
i.Out = val
|
||||
} else {
|
||||
l = patchList(i.Arg)
|
||||
head = i.Arg
|
||||
i.Arg = val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l1 patchList) append(p *Prog, l2 patchList) patchList {
|
||||
if l1 == 0 {
|
||||
if l1.head == 0 {
|
||||
return l2
|
||||
}
|
||||
if l2 == 0 {
|
||||
if l2.head == 0 {
|
||||
return l1
|
||||
}
|
||||
|
||||
last := l1
|
||||
for {
|
||||
next := last.next(p)
|
||||
if next == 0 {
|
||||
break
|
||||
}
|
||||
last = next
|
||||
}
|
||||
|
||||
i := &p.Inst[last>>1]
|
||||
if last&1 == 0 {
|
||||
i.Out = uint32(l2)
|
||||
i := &p.Inst[l1.tail>>1]
|
||||
if l1.tail&1 == 0 {
|
||||
i.Out = l2.head
|
||||
} else {
|
||||
i.Arg = uint32(l2)
|
||||
i.Arg = l2.head
|
||||
}
|
||||
return l1
|
||||
return patchList{l1.head, l2.tail}
|
||||
}
|
||||
|
||||
// A frag represents a compiled program fragment.
|
||||
|
|
@ -176,7 +166,7 @@ func (c *compiler) inst(op InstOp) frag {
|
|||
|
||||
func (c *compiler) nop() frag {
|
||||
f := c.inst(InstNop)
|
||||
f.out = patchList(f.i << 1)
|
||||
f.out = makePatchList(f.i << 1)
|
||||
return f
|
||||
}
|
||||
|
||||
|
|
@ -186,7 +176,7 @@ func (c *compiler) fail() frag {
|
|||
|
||||
func (c *compiler) cap(arg uint32) frag {
|
||||
f := c.inst(InstCapture)
|
||||
f.out = patchList(f.i << 1)
|
||||
f.out = makePatchList(f.i << 1)
|
||||
c.p.Inst[f.i].Arg = arg
|
||||
|
||||
if c.p.NumCap < int(arg)+1 {
|
||||
|
|
@ -229,10 +219,10 @@ func (c *compiler) quest(f1 frag, nongreedy bool) frag {
|
|||
i := &c.p.Inst[f.i]
|
||||
if nongreedy {
|
||||
i.Arg = f1.i
|
||||
f.out = patchList(f.i << 1)
|
||||
f.out = makePatchList(f.i << 1)
|
||||
} else {
|
||||
i.Out = f1.i
|
||||
f.out = patchList(f.i<<1 | 1)
|
||||
f.out = makePatchList(f.i<<1 | 1)
|
||||
}
|
||||
f.out = f.out.append(c.p, f1.out)
|
||||
return f
|
||||
|
|
@ -243,10 +233,10 @@ func (c *compiler) star(f1 frag, nongreedy bool) frag {
|
|||
i := &c.p.Inst[f.i]
|
||||
if nongreedy {
|
||||
i.Arg = f1.i
|
||||
f.out = patchList(f.i << 1)
|
||||
f.out = makePatchList(f.i << 1)
|
||||
} else {
|
||||
i.Out = f1.i
|
||||
f.out = patchList(f.i<<1 | 1)
|
||||
f.out = makePatchList(f.i<<1 | 1)
|
||||
}
|
||||
f1.out.patch(c.p, f.i)
|
||||
return f
|
||||
|
|
@ -259,7 +249,7 @@ func (c *compiler) plus(f1 frag, nongreedy bool) frag {
|
|||
func (c *compiler) empty(op EmptyOp) frag {
|
||||
f := c.inst(InstEmptyWidth)
|
||||
c.p.Inst[f.i].Arg = uint32(op)
|
||||
f.out = patchList(f.i << 1)
|
||||
f.out = makePatchList(f.i << 1)
|
||||
return f
|
||||
}
|
||||
|
||||
|
|
@ -273,7 +263,7 @@ func (c *compiler) rune(r []rune, flags Flags) frag {
|
|||
flags &^= FoldCase
|
||||
}
|
||||
i.Arg = uint32(flags)
|
||||
f.out = patchList(f.i << 1)
|
||||
f.out = makePatchList(f.i << 1)
|
||||
|
||||
// Special cases for exec machine.
|
||||
switch {
|
||||
|
|
|
|||
|
|
@ -6,45 +6,117 @@ package runtime
|
|||
|
||||
import "unsafe"
|
||||
|
||||
var tracebackbuf [128]byte
|
||||
const (
|
||||
// Plan 9 environment device
|
||||
envDir = "/env/"
|
||||
// size of buffer to read from a directory
|
||||
dirBufSize = 4096
|
||||
// size of buffer to read an environment variable (may grow)
|
||||
envBufSize = 128
|
||||
// offset of the name field in a 9P directory entry - see syscall.UnmarshalDir()
|
||||
nameOffset = 39
|
||||
)
|
||||
|
||||
func gogetenv(key string) string {
|
||||
var file [128]byte
|
||||
if len(key) > len(file)-6 {
|
||||
return ""
|
||||
// Goenvs caches the Plan 9 environment variables at start of execution into
|
||||
// string array envs, to supply the initial contents for os.Environ.
|
||||
// Subsequent calls to os.Setenv will change this cache, without writing back
|
||||
// to the (possibly shared) Plan 9 environment, so that Setenv and Getenv
|
||||
// conform to the same Posix semantics as on other operating systems.
|
||||
// For Plan 9 shared environment semantics, instead of Getenv(key) and
|
||||
// Setenv(key, value), one can use ioutil.ReadFile("/env/" + key) and
|
||||
// ioutil.WriteFile("/env/" + key, value, 0666) respectively.
|
||||
//go:nosplit
|
||||
func goenvs() {
|
||||
buf := make([]byte, envBufSize)
|
||||
copy(buf, envDir)
|
||||
dirfd := open(&buf[0], _OREAD, 0)
|
||||
if dirfd < 0 {
|
||||
return
|
||||
}
|
||||
|
||||
copy(file[:], "/env/")
|
||||
copy(file[5:], key)
|
||||
|
||||
fd := open(&file[0], _OREAD, 0)
|
||||
defer closefd(dirfd)
|
||||
dofiles(dirfd, func(name []byte) {
|
||||
name = append(name, 0)
|
||||
buf = buf[:len(envDir)]
|
||||
copy(buf, envDir)
|
||||
buf = append(buf, name...)
|
||||
fd := open(&buf[0], _OREAD, 0)
|
||||
if fd < 0 {
|
||||
return ""
|
||||
return
|
||||
}
|
||||
n := seek(fd, 0, 2)
|
||||
if n <= 0 {
|
||||
closefd(fd)
|
||||
return ""
|
||||
defer closefd(fd)
|
||||
n := len(buf)
|
||||
r := 0
|
||||
for {
|
||||
r = int(pread(fd, unsafe.Pointer(&buf[0]), int32(n), 0))
|
||||
if r < n {
|
||||
break
|
||||
}
|
||||
|
||||
p := make([]byte, n)
|
||||
|
||||
r := pread(fd, unsafe.Pointer(&p[0]), int32(n), 0)
|
||||
closefd(fd)
|
||||
if r < 0 {
|
||||
return ""
|
||||
n = int(seek(fd, 0, 2)) + 1
|
||||
if len(buf) < n {
|
||||
buf = make([]byte, n)
|
||||
}
|
||||
|
||||
if p[r-1] == 0 {
|
||||
}
|
||||
if r <= 0 {
|
||||
r = 0
|
||||
} else if buf[r-1] == 0 {
|
||||
r--
|
||||
}
|
||||
|
||||
var s string
|
||||
sp := stringStructOf(&s)
|
||||
sp.str = unsafe.Pointer(&p[0])
|
||||
sp.len = int(r)
|
||||
return s
|
||||
name[len(name)-1] = '='
|
||||
env := make([]byte, len(name)+r)
|
||||
copy(env, name)
|
||||
copy(env[len(name):], buf[:r])
|
||||
envs = append(envs, string(env))
|
||||
})
|
||||
}
|
||||
|
||||
var _cgo_setenv unsafe.Pointer // pointer to C function
|
||||
var _cgo_unsetenv unsafe.Pointer // pointer to C function
|
||||
// Dofiles reads the directory opened with file descriptor fd, applying function f
|
||||
// to each filename in it.
|
||||
//go:nosplit
|
||||
func dofiles(dirfd int32, f func([]byte)) {
|
||||
dirbuf := new([dirBufSize]byte)
|
||||
|
||||
var off int64 = 0
|
||||
for {
|
||||
n := pread(dirfd, unsafe.Pointer(&dirbuf[0]), int32(dirBufSize), off)
|
||||
if n <= 0 {
|
||||
return
|
||||
}
|
||||
for b := dirbuf[:n]; len(b) > 0; {
|
||||
var name []byte
|
||||
name, b = gdirname(b)
|
||||
if name == nil {
|
||||
return
|
||||
}
|
||||
f(name)
|
||||
}
|
||||
off += int64(n)
|
||||
}
|
||||
}
|
||||
|
||||
// Gdirname returns the first filename from a buffer of directory entries,
|
||||
// and a slice containing the remaining directory entries.
|
||||
// If the buffer doesn't start with a valid directory entry, the returned name is nil.
|
||||
//go:nosplit
|
||||
func gdirname(buf []byte) (name []byte, rest []byte) {
|
||||
if 2+nameOffset+2 > len(buf) {
|
||||
return
|
||||
}
|
||||
entryLen, buf := gbit16(buf)
|
||||
if entryLen > len(buf) {
|
||||
return
|
||||
}
|
||||
n, b := gbit16(buf[nameOffset:])
|
||||
if n > len(b) {
|
||||
return
|
||||
}
|
||||
name = b[:n]
|
||||
rest = buf[entryLen:]
|
||||
return
|
||||
}
|
||||
|
||||
// Gbit16 reads a 16-bit little-endian binary number from b and returns it
|
||||
// with the remaining slice of b.
|
||||
//go:nosplit
|
||||
func gbit16(b []byte) (int, []byte) {
|
||||
return int(b[0]) | int(b[1])<<8, b[2:]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows
|
||||
// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows plan9
|
||||
|
||||
package runtime
|
||||
|
||||
|
|
|
|||
|
|
@ -11,10 +11,6 @@ import (
|
|||
)
|
||||
|
||||
func TestFixedGOROOT(t *testing.T) {
|
||||
if runtime.GOOS == "plan9" {
|
||||
t.Skipf("skipping plan9, it is inconsistent by allowing GOROOT to be updated by Setenv")
|
||||
}
|
||||
|
||||
// Restore both the real GOROOT environment variable, and runtime's copies:
|
||||
if orig, ok := syscall.Getenv("GOROOT"); ok {
|
||||
defer syscall.Setenv("GOROOT", orig)
|
||||
|
|
|
|||
|
|
@ -152,14 +152,13 @@ func (s *HashSet) addS_seed(x string, seed uintptr) {
|
|||
s.add(StringHash(x, seed))
|
||||
}
|
||||
func (s *HashSet) check(t *testing.T) {
|
||||
const SLOP = 10.0
|
||||
const SLOP = 50.0
|
||||
collisions := s.n - len(s.m)
|
||||
//fmt.Printf("%d/%d\n", len(s.m), s.n)
|
||||
pairs := int64(s.n) * int64(s.n-1) / 2
|
||||
expected := float64(pairs) / math.Pow(2.0, float64(hashSize))
|
||||
stddev := math.Sqrt(expected)
|
||||
if float64(collisions) > expected+SLOP*(3*stddev+1) {
|
||||
t.Errorf("unexpected number of collisions: got=%d mean=%f stddev=%f", collisions, expected, stddev)
|
||||
t.Errorf("unexpected number of collisions: got=%d mean=%f stddev=%f threshold=%f", collisions, expected, stddev, expected+SLOP*(3*stddev+1))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -564,8 +563,11 @@ func avalancheTest1(t *testing.T, k Key) {
|
|||
|
||||
// All bit rotations of a set of distinct keys
|
||||
func TestSmhasherWindowed(t *testing.T) {
|
||||
t.Logf("32 bit keys")
|
||||
windowed(t, &Int32Key{})
|
||||
t.Logf("64 bit keys")
|
||||
windowed(t, &Int64Key{})
|
||||
t.Logf("string keys")
|
||||
windowed(t, &BytesKey{make([]byte, 128)})
|
||||
}
|
||||
func windowed(t *testing.T, k Key) {
|
||||
|
|
|
|||
|
|
@ -49,6 +49,9 @@ func netpoll(delay int64) gList {
|
|||
|
||||
notetsleep(&netpollNote, delay)
|
||||
unlock(&netpollStubLock)
|
||||
// Guard against starvation in case the lock is contended
|
||||
// (eg when running TestNetpollBreak).
|
||||
osyield()
|
||||
}
|
||||
return gList{}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -306,9 +306,6 @@ func getRandomData(r []byte) {
|
|||
extendRandom(r, 0)
|
||||
}
|
||||
|
||||
func goenvs() {
|
||||
}
|
||||
|
||||
func initsig(preinit bool) {
|
||||
if !preinit {
|
||||
notify(unsafe.Pointer(funcPC(sigtramp)))
|
||||
|
|
|
|||
|
|
@ -432,6 +432,8 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
|
|||
return
|
||||
}
|
||||
|
||||
setg(g.m.gsignal)
|
||||
|
||||
// If some non-Go code called sigaltstack, adjust.
|
||||
var gsignalStack gsignalStack
|
||||
setStack := adjustSignalStack(sig, g.m, &gsignalStack)
|
||||
|
|
@ -439,8 +441,6 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
|
|||
g.m.gsignal.stktopsp = getcallersp()
|
||||
}
|
||||
|
||||
setg(g.m.gsignal)
|
||||
|
||||
if g.stackguard0 == stackFork {
|
||||
signalDuringFork(sig)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -556,6 +556,7 @@ func adjustpointer(adjinfo *adjustinfo, vpp unsafe.Pointer) {
|
|||
}
|
||||
|
||||
// Information from the compiler about the layout of stack frames.
|
||||
// Note: this type must agree with reflect.bitVector.
|
||||
type bitvector struct {
|
||||
n int32 // # of bits
|
||||
bytedata *uint8
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
// command runs the test in the current directory and writes the trace
|
||||
// file (trace.out).
|
||||
//
|
||||
// go test -trace=test.out
|
||||
// go test -trace=trace.out
|
||||
//
|
||||
// This runtime/trace package provides APIs to add equivalent tracing
|
||||
// support to a standalone program. See the Example that demonstrates
|
||||
|
|
|
|||
|
|
@ -1,122 +0,0 @@
|
|||
// Copyright 2011 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.
|
||||
|
||||
// Plan 9 environment variables.
|
||||
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
var (
|
||||
errZeroLengthKey = errors.New("zero length key")
|
||||
errShortWrite = errors.New("i/o count too small")
|
||||
)
|
||||
|
||||
func readenv(key string) (string, error) {
|
||||
fd, err := open("/env/"+key, O_RDONLY)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer Close(fd)
|
||||
l, _ := Seek(fd, 0, 2)
|
||||
Seek(fd, 0, 0)
|
||||
buf := make([]byte, l)
|
||||
n, err := Read(fd, buf)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if n > 0 && buf[n-1] == 0 {
|
||||
buf = buf[:n-1]
|
||||
}
|
||||
return string(buf), nil
|
||||
}
|
||||
|
||||
func writeenv(key, value string) error {
|
||||
fd, err := create("/env/"+key, O_RDWR, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer Close(fd)
|
||||
b := []byte(value)
|
||||
n, err := Write(fd, b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n != len(b) {
|
||||
return errShortWrite
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Getenv(key string) (value string, found bool) {
|
||||
if len(key) == 0 {
|
||||
return "", false
|
||||
}
|
||||
v, err := readenv(key)
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
return v, true
|
||||
}
|
||||
|
||||
func Setenv(key, value string) error {
|
||||
if len(key) == 0 {
|
||||
return errZeroLengthKey
|
||||
}
|
||||
err := writeenv(key, value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Clearenv() {
|
||||
// Creating a new environment group using rfork(RFCENVG) can race
|
||||
// with access to files in /env (e.g. from Setenv or Getenv).
|
||||
// Remove all environment variables in current environment group instead.
|
||||
fd, err := open("/env", O_RDONLY)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer Close(fd)
|
||||
files, err := readdirnames(fd)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, key := range files {
|
||||
Remove("/env/" + key)
|
||||
}
|
||||
}
|
||||
|
||||
func Unsetenv(key string) error {
|
||||
if len(key) == 0 {
|
||||
return errZeroLengthKey
|
||||
}
|
||||
Remove("/env/" + key)
|
||||
return nil
|
||||
}
|
||||
|
||||
func Environ() []string {
|
||||
fd, err := open("/env", O_RDONLY)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer Close(fd)
|
||||
files, err := readdirnames(fd)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
ret := make([]string, 0, len(files))
|
||||
|
||||
for _, key := range files {
|
||||
v, err := readenv(key)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
ret = append(ret, key+"="+v)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
|
@ -2,13 +2,16 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris
|
||||
// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris plan9
|
||||
|
||||
// Unix environment variables.
|
||||
|
||||
package syscall
|
||||
|
||||
import "sync"
|
||||
import (
|
||||
"runtime"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
// envOnce guards initialization by copyenv, which populates env.
|
||||
|
|
@ -100,11 +103,14 @@ func Setenv(key, value string) error {
|
|||
return EINVAL
|
||||
}
|
||||
}
|
||||
// On Plan 9, null is used as a separator, eg in $path.
|
||||
if runtime.GOOS != "plan9" {
|
||||
for i := 0; i < len(value); i++ {
|
||||
if value[i] == 0 {
|
||||
return EINVAL
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
envLock.Lock()
|
||||
defer envLock.Unlock()
|
||||
|
|
|
|||
33
test/fixedbugs/issue39541.go
Normal file
33
test/fixedbugs/issue39541.go
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
// run
|
||||
|
||||
// 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 main
|
||||
|
||||
import "reflect"
|
||||
|
||||
func sub(args []reflect.Value) []reflect.Value {
|
||||
type A struct {
|
||||
s int
|
||||
t int
|
||||
}
|
||||
return []reflect.Value{reflect.ValueOf(A{1, 2})}
|
||||
}
|
||||
|
||||
func main() {
|
||||
f := reflect.MakeFunc(reflect.TypeOf((func() interface{})(nil)), sub).Interface().(func() interface{})
|
||||
c := make(chan bool, 100)
|
||||
for i := 0; i < 100; i++ {
|
||||
go func() {
|
||||
for j := 0; j < 10000; j++ {
|
||||
f()
|
||||
}
|
||||
c <- true
|
||||
}()
|
||||
}
|
||||
for i := 0; i < 100; i++ {
|
||||
<-c
|
||||
}
|
||||
}
|
||||
26
test/fixedbugs/issue39651.go
Normal file
26
test/fixedbugs/issue39651.go
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// run
|
||||
|
||||
// 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 float -> integer conversion doesn't clobber
|
||||
// flags.
|
||||
|
||||
package main
|
||||
|
||||
//go:noinline
|
||||
func f(x, y float64, a, b *bool, r *int64) {
|
||||
*a = x < y // set flags
|
||||
*r = int64(x) // clobber flags
|
||||
*b = x == y // use flags
|
||||
}
|
||||
|
||||
func main() {
|
||||
var a, b bool
|
||||
var r int64
|
||||
f(1, 1, &a, &b, &r)
|
||||
if a || !b {
|
||||
panic("comparison incorrect")
|
||||
}
|
||||
}
|
||||
|
|
@ -12,22 +12,65 @@ import "fmt"
|
|||
|
||||
func main() {
|
||||
type A [2]interface{}
|
||||
type A2 [6]interface{}
|
||||
type S struct{ x, y interface{} }
|
||||
type S2 struct{ x, y, z, a, b, c interface{} }
|
||||
type T1 struct {
|
||||
i interface{}
|
||||
a int64
|
||||
j interface{}
|
||||
}
|
||||
type T2 struct {
|
||||
i interface{}
|
||||
a, b, c int64
|
||||
j interface{}
|
||||
}
|
||||
type T3 struct {
|
||||
i interface{}
|
||||
s string
|
||||
j interface{}
|
||||
}
|
||||
b := []byte{1}
|
||||
|
||||
for _, test := range []struct {
|
||||
panic bool
|
||||
a, b interface{}
|
||||
}{
|
||||
{false, A{1, []byte{1}}, A{2, []byte{1}}},
|
||||
{true, A{[]byte{1}, 1}, A{[]byte{1}, 2}},
|
||||
{false, S{1, []byte{1}}, S{2, []byte{1}}},
|
||||
{true, S{[]byte{1}, 1}, S{[]byte{1}, 2}},
|
||||
{false, A{1, []byte{1}}, A{"2", []byte{1}}},
|
||||
{true, A{[]byte{1}, 1}, A{[]byte{1}, "2"}},
|
||||
{false, S{1, []byte{1}}, S{"2", []byte{1}}},
|
||||
{true, S{[]byte{1}, 1}, S{[]byte{1}, "2"}},
|
||||
{false, A{1, b}, A{2, b}},
|
||||
{true, A{b, 1}, A{b, 2}},
|
||||
{false, A{1, b}, A{"2", b}},
|
||||
{true, A{b, 1}, A{b, "2"}},
|
||||
|
||||
{false, A2{1, b}, A2{2, b}},
|
||||
{true, A2{b, 1}, A2{b, 2}},
|
||||
{false, A2{1, b}, A2{"2", b}},
|
||||
{true, A2{b, 1}, A2{b, "2"}},
|
||||
|
||||
{false, S{1, b}, S{2, b}},
|
||||
{true, S{b, 1}, S{b, 2}},
|
||||
{false, S{1, b}, S{"2", b}},
|
||||
{true, S{b, 1}, S{b, "2"}},
|
||||
|
||||
{false, S2{x: 1, y: b}, S2{x: 2, y: b}},
|
||||
{true, S2{x: b, y: 1}, S2{x: b, y: 2}},
|
||||
{false, S2{x: 1, y: b}, S2{x: "2", y: b}},
|
||||
{true, S2{x: b, y: 1}, S2{x: b, y: "2"}},
|
||||
|
||||
{true, T1{i: b, a: 1}, T1{i: b, a: 2}},
|
||||
{false, T1{a: 1, j: b}, T1{a: 2, j: b}},
|
||||
{true, T2{i: b, a: 1}, T2{i: b, a: 2}},
|
||||
{false, T2{a: 1, j: b}, T2{a: 2, j: b}},
|
||||
{true, T3{i: b, s: "foo"}, T3{i: b, s: "bar"}},
|
||||
{false, T3{s: "foo", j: b}, T3{s: "bar", j: b}},
|
||||
{true, T3{i: b, s: "fooz"}, T3{i: b, s: "bar"}},
|
||||
{false, T3{s: "fooz", j: b}, T3{s: "bar", j: b}},
|
||||
} {
|
||||
f := func() {
|
||||
defer func() {
|
||||
if recover() != nil {
|
||||
panic(fmt.Sprintf("comparing %#v and %#v panicked", test.a, test.b))
|
||||
}
|
||||
}()
|
||||
if test.a == test.b {
|
||||
panic(fmt.Sprintf("values %#v and %#v should not be equal", test.a, test.b))
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue