mirror of https://github.com/golang/go.git
[dev.boringcrypto] all: merge master into dev.boringcrypto
Change-Id: Iaf618444dd2d99721c19708df9ce2c1f35854efd
This commit is contained in:
commit
4739b353bb
1
AUTHORS
1
AUTHORS
|
|
@ -829,6 +829,7 @@ Liberty Fund Inc
|
|||
Linaro Limited
|
||||
Lion Yang <lion@aosc.xyz>
|
||||
Lloyd Dewolf <foolswisdom@gmail.com>
|
||||
Loongson Technology Corporation Limited
|
||||
Lorenzo Masini <rugginoso@develer.com>
|
||||
Lorenzo Stoakes <lstoakes@gmail.com>
|
||||
Luan Santos <cfcluan@gmail.com>
|
||||
|
|
|
|||
|
|
@ -505,3 +505,5 @@ pkg unicode, const Version = "6.3.0"
|
|||
pkg unicode, const Version = "7.0.0"
|
||||
pkg unicode, const Version = "8.0.0"
|
||||
pkg unicode, const Version = "9.0.0"
|
||||
pkg html/template, method (*Template) Funcs(FuncMap) *Template
|
||||
pkg html/template, type FuncMap map[string]interface{}
|
||||
|
|
|
|||
|
|
@ -371,7 +371,7 @@ pkg debug/elf, const ELFCLASSNONE = 0
|
|||
pkg debug/elf, const ELFDATA2LSB = 1
|
||||
pkg debug/elf, const ELFDATA2MSB = 2
|
||||
pkg debug/elf, const ELFDATANONE = 0
|
||||
pkg debug/elf, const ELFMAG = "\u007fELF"
|
||||
pkg debug/elf, const ELFMAG = "\x7fELF"
|
||||
pkg debug/elf, const ELFOSABI_86OPEN = 5
|
||||
pkg debug/elf, const ELFOSABI_AIX = 7
|
||||
pkg debug/elf, const ELFOSABI_ARM = 97
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
pkg crypto/x509, method (*CertPool) Equal(*CertPool) bool #46057
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
pkg html/template, method (*Template) Funcs(template.FuncMap) *Template #46121
|
||||
pkg html/template, type FuncMap = template.FuncMap #46121
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
pkg debug/elf, const EM_LOONGARCH = 258 #46229
|
||||
pkg debug/elf, const EM_LOONGARCH Machine #46229
|
||||
pkg debug/elf, const R_LARCH_32 = 1 #46229
|
||||
pkg debug/elf, const R_LARCH_32 R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_64 = 2 #46229
|
||||
pkg debug/elf, const R_LARCH_64 R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_ADD16 = 48 #46229
|
||||
pkg debug/elf, const R_LARCH_ADD16 R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_ADD24 = 49 #46229
|
||||
pkg debug/elf, const R_LARCH_ADD24 R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_ADD32 = 50 #46229
|
||||
pkg debug/elf, const R_LARCH_ADD32 R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_ADD64 = 51 #46229
|
||||
pkg debug/elf, const R_LARCH_ADD64 R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_ADD8 = 47 #46229
|
||||
pkg debug/elf, const R_LARCH_ADD8 R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_COPY = 4 #46229
|
||||
pkg debug/elf, const R_LARCH_COPY R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_IRELATIVE = 12 #46229
|
||||
pkg debug/elf, const R_LARCH_IRELATIVE R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_JUMP_SLOT = 5 #46229
|
||||
pkg debug/elf, const R_LARCH_JUMP_SLOT R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_MARK_LA = 20 #46229
|
||||
pkg debug/elf, const R_LARCH_MARK_LA R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_MARK_PCREL = 21 #46229
|
||||
pkg debug/elf, const R_LARCH_MARK_PCREL R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_NONE = 0 #46229
|
||||
pkg debug/elf, const R_LARCH_NONE R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_RELATIVE = 3 #46229
|
||||
pkg debug/elf, const R_LARCH_RELATIVE R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_ADD = 35 #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_ADD R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_AND = 36 #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_AND R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_ASSERT = 30 #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_ASSERT R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_IF_ELSE = 37 #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_IF_ELSE R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_NOT = 31 #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_NOT R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_POP_32_S_0_10_10_16_S2 = 45 #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_POP_32_S_0_10_10_16_S2 R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_POP_32_S_0_5_10_16_S2 = 44 #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_POP_32_S_0_5_10_16_S2 R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_POP_32_S_10_12 = 40 #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_POP_32_S_10_12 R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_POP_32_S_10_16 = 41 #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_POP_32_S_10_16 R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_POP_32_S_10_16_S2 = 42 #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_POP_32_S_10_16_S2 R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_POP_32_S_10_5 = 38 #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_POP_32_S_10_5 R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_POP_32_S_5_20 = 43 #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_POP_32_S_5_20 R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_POP_32_U = 46 #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_POP_32_U R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_POP_32_U_10_12 = 39 #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_POP_32_U_10_12 R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_PUSH_ABSOLUTE = 23 #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_PUSH_ABSOLUTE R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_PUSH_DUP = 24 #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_PUSH_DUP R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_PUSH_GPREL = 25 #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_PUSH_GPREL R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_PUSH_PCREL = 22 #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_PUSH_PCREL R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_PUSH_PLT_PCREL = 29 #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_PUSH_PLT_PCREL R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_PUSH_TLS_GD = 28 #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_PUSH_TLS_GD R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_PUSH_TLS_GOT = 27 #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_PUSH_TLS_GOT R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_PUSH_TLS_TPREL = 26 #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_PUSH_TLS_TPREL R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_SL = 33 #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_SL R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_SR = 34 #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_SR R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_SUB = 32 #46229
|
||||
pkg debug/elf, const R_LARCH_SOP_SUB R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SUB16 = 53 #46229
|
||||
pkg debug/elf, const R_LARCH_SUB16 R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SUB24 = 54 #46229
|
||||
pkg debug/elf, const R_LARCH_SUB24 R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SUB32 = 55 #46229
|
||||
pkg debug/elf, const R_LARCH_SUB32 R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SUB64 = 56 #46229
|
||||
pkg debug/elf, const R_LARCH_SUB64 R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_SUB8 = 52 #46229
|
||||
pkg debug/elf, const R_LARCH_SUB8 R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_TLS_DTPMOD32 = 6 #46229
|
||||
pkg debug/elf, const R_LARCH_TLS_DTPMOD32 R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_TLS_DTPMOD64 = 7 #46229
|
||||
pkg debug/elf, const R_LARCH_TLS_DTPMOD64 R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_TLS_DTPREL32 = 8 #46229
|
||||
pkg debug/elf, const R_LARCH_TLS_DTPREL32 R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_TLS_DTPREL64 = 9 #46229
|
||||
pkg debug/elf, const R_LARCH_TLS_DTPREL64 R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_TLS_TPREL32 = 10 #46229
|
||||
pkg debug/elf, const R_LARCH_TLS_TPREL32 R_LARCH #46229
|
||||
pkg debug/elf, const R_LARCH_TLS_TPREL64 = 11 #46229
|
||||
pkg debug/elf, const R_LARCH_TLS_TPREL64 R_LARCH #46229
|
||||
pkg debug/elf, method (R_LARCH) GoString() string #46229
|
||||
pkg debug/elf, method (R_LARCH) String() string #46229
|
||||
pkg debug/elf, type R_LARCH int #46229
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
pkg debug/pe, const IMAGE_COMDAT_SELECT_ANY = 2 #51686
|
||||
pkg debug/pe, const IMAGE_COMDAT_SELECT_ANY ideal-int #51686
|
||||
pkg debug/pe, const IMAGE_COMDAT_SELECT_ASSOCIATIVE = 5 #51686
|
||||
pkg debug/pe, const IMAGE_COMDAT_SELECT_ASSOCIATIVE ideal-int #51686
|
||||
pkg debug/pe, const IMAGE_COMDAT_SELECT_EXACT_MATCH = 4 #51686
|
||||
pkg debug/pe, const IMAGE_COMDAT_SELECT_EXACT_MATCH ideal-int #51686
|
||||
pkg debug/pe, const IMAGE_COMDAT_SELECT_LARGEST = 6 #51686
|
||||
pkg debug/pe, const IMAGE_COMDAT_SELECT_LARGEST ideal-int #51686
|
||||
pkg debug/pe, const IMAGE_COMDAT_SELECT_NODUPLICATES = 1 #51686
|
||||
pkg debug/pe, const IMAGE_COMDAT_SELECT_NODUPLICATES ideal-int #51686
|
||||
pkg debug/pe, const IMAGE_COMDAT_SELECT_SAME_SIZE = 3 #51686
|
||||
pkg debug/pe, const IMAGE_COMDAT_SELECT_SAME_SIZE ideal-int #51686
|
||||
pkg debug/pe, const IMAGE_SCN_CNT_CODE = 32 #51686
|
||||
pkg debug/pe, const IMAGE_SCN_CNT_CODE ideal-int #51686
|
||||
pkg debug/pe, const IMAGE_SCN_CNT_INITIALIZED_DATA = 64 #51686
|
||||
pkg debug/pe, const IMAGE_SCN_CNT_INITIALIZED_DATA ideal-int #51686
|
||||
pkg debug/pe, const IMAGE_SCN_CNT_UNINITIALIZED_DATA = 128 #51686
|
||||
pkg debug/pe, const IMAGE_SCN_CNT_UNINITIALIZED_DATA ideal-int #51686
|
||||
pkg debug/pe, const IMAGE_SCN_LNK_COMDAT = 4096 #51686
|
||||
pkg debug/pe, const IMAGE_SCN_LNK_COMDAT ideal-int #51686
|
||||
pkg debug/pe, const IMAGE_SCN_MEM_DISCARDABLE = 33554432 #51686
|
||||
pkg debug/pe, const IMAGE_SCN_MEM_DISCARDABLE ideal-int #51686
|
||||
pkg debug/pe, const IMAGE_SCN_MEM_EXECUTE = 536870912 #51686
|
||||
pkg debug/pe, const IMAGE_SCN_MEM_EXECUTE ideal-int #51686
|
||||
pkg debug/pe, const IMAGE_SCN_MEM_READ = 1073741824 #51686
|
||||
pkg debug/pe, const IMAGE_SCN_MEM_READ ideal-int #51686
|
||||
pkg debug/pe, const IMAGE_SCN_MEM_WRITE = 2147483648 #51686
|
||||
pkg debug/pe, const IMAGE_SCN_MEM_WRITE ideal-int #51686
|
||||
pkg debug/pe, method (*File) COFFSymbolReadSectionDefAux(int) (*COFFSymbolAuxFormat5, error) #51686
|
||||
pkg debug/pe, type COFFSymbolAuxFormat5 struct #51686
|
||||
pkg debug/pe, type COFFSymbolAuxFormat5 struct, Checksum uint32 #51686
|
||||
pkg debug/pe, type COFFSymbolAuxFormat5 struct, NumLineNumbers uint16 #51686
|
||||
pkg debug/pe, type COFFSymbolAuxFormat5 struct, NumRelocs uint16 #51686
|
||||
pkg debug/pe, type COFFSymbolAuxFormat5 struct, SecNum uint16 #51686
|
||||
pkg debug/pe, type COFFSymbolAuxFormat5 struct, Selection uint8 #51686
|
||||
pkg debug/pe, type COFFSymbolAuxFormat5 struct, Size uint32 #51686
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
pkg regexp/syntax, const ErrInvalidDepth = "invalid nesting depth" #0
|
||||
pkg regexp/syntax, const ErrInvalidDepth ErrorCode #0
|
||||
|
||||
|
|
@ -34,6 +34,23 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
<p>
|
||||
TODO: complete this section, or delete if not needed
|
||||
</p>
|
||||
|
||||
<h4 id="go-unix">New <code>unix</code> build constraint</h4>
|
||||
|
||||
<p><!-- CL 389934 -->
|
||||
The build constraint <code>unix</code> is now recognized
|
||||
in <code>//go:build</code> lines. The constraint is satisfied
|
||||
if the target operating system, also known as <code>GOOS</code>, is
|
||||
a Unix or Unix-like system. For the 1.19 release it is satisfied
|
||||
if <code>GOOS</code> is one of
|
||||
<code>aix</code>, <code>android</code>, <code>darwin</code>,
|
||||
<code>dragonfly</code>, <code>freebsd</code>, <code>hurd</code>,
|
||||
<code>illumos</code>, <code>ios</code>, <code>linux</code>,
|
||||
<code>netbsd</code>, <code>openbsd</code>, or <code>solaris</code>.
|
||||
In future releases the <code>unix</code> constraint may match
|
||||
additional newly supported operating systems.
|
||||
</p>
|
||||
|
||||
<h2 id="runtime">Runtime</h2>
|
||||
<p>
|
||||
TODO: complete this section, or delete if not needed
|
||||
|
|
@ -72,5 +89,27 @@ Do not send CLs removing the interior tags from such phrases.
|
|||
Please report any such problems on <a href="/issue/new">the
|
||||
issue tracker</a>.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 396877 -->
|
||||
When a net package function or method returns an "I/O timeout"
|
||||
error, the error will now satisfy <code>errors.Is(err,
|
||||
context.Canceled)</code>. When a net package function returns
|
||||
an "operation was canceled" error, the error will now satisfy
|
||||
<code>errors.Is(err, context.DeadlineExceeded)</code>.
|
||||
These changes are intended to make it easier for code to test
|
||||
for cases in which a context cancelation or timeout causes a net
|
||||
package function or method to return an error, while preserving
|
||||
backward compatibility for error messages.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</dl><!-- net -->
|
||||
|
||||
<dl id="strconv"><dt><a href="/pkg/strconv/">strconv</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 397255 -->
|
||||
<a href="/pkg/strconv/#strconv.Quote"><code>strconv.Quote</code></a>
|
||||
and related functions now quote the rune 007F as <code>\x7f</code>,
|
||||
not <code>\u007f</code>.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- strconv -->
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<!--{
|
||||
"Title": "The Go Programming Language Specification",
|
||||
"Subtitle": "Version of March 10, 2022",
|
||||
"Subtitle": "Version of March 30, 2022",
|
||||
"Path": "/ref/spec"
|
||||
}-->
|
||||
|
||||
|
|
@ -529,6 +529,7 @@ escaped_char = `\` ( "a" | "b" | "f" | "n" | "r" | "t" | "v" | `\` | "'" | `
|
|||
'aa' // illegal: too many characters
|
||||
'\xa' // illegal: too few hexadecimal digits
|
||||
'\0' // illegal: too few octal digits
|
||||
'\400' // illegal: octal value over 255
|
||||
'\uDFFF' // illegal: surrogate half
|
||||
'\U00110000' // illegal: invalid Unicode code point
|
||||
</pre>
|
||||
|
|
@ -1454,7 +1455,8 @@ type Float interface {
|
|||
</pre>
|
||||
|
||||
<p>
|
||||
In a union, a term cannot be a <a href="#Type_parameter_declarations">type parameter</a>, and the type sets of all
|
||||
The type <code>T</code> in a term of the form <code>T</code> or <code>~T</code> cannot
|
||||
be a <a href="#Type_parameter_declarations">type parameter</a>, and the type sets of all
|
||||
non-interface terms must be pairwise disjoint (the pairwise intersection of the type sets must be empty).
|
||||
Given a type parameter <code>P</code>:
|
||||
</p>
|
||||
|
|
@ -1462,7 +1464,7 @@ Given a type parameter <code>P</code>:
|
|||
<pre>
|
||||
interface {
|
||||
P // illegal: P is a type parameter
|
||||
int | P // illegal: P is a type parameter
|
||||
int | ~P // illegal: P is a type parameter
|
||||
~int | MyInt // illegal: the type sets for ~int and MyInt are not disjoint (~int includes MyInt)
|
||||
float32 | Float // overlapping type sets but Float is an interface
|
||||
}
|
||||
|
|
@ -1878,7 +1880,7 @@ A4, func(int, float64) *[]string, and A5
|
|||
B0 and C0
|
||||
D0[int, string] and E0
|
||||
[]int and []int
|
||||
struct{ a, b *T5 } and struct{ a, b *T5 }
|
||||
struct{ a, b *B5 } and struct{ a, b *B5 }
|
||||
func(x int, y float64) *[]string, func(int, float64) (result *[]string), and A5
|
||||
</pre>
|
||||
|
||||
|
|
@ -4195,7 +4197,7 @@ type parameter list type arguments after substitution
|
|||
<p>
|
||||
For a generic function, type arguments may be provided explicitly, or they
|
||||
may be partially or completely <a href="#Type_inference">inferred</a>.
|
||||
A generic function that is is <i>not</i> <a href="#Calls">called</a> requires a
|
||||
A generic function that is <i>not</i> <a href="#Calls">called</a> requires a
|
||||
type argument list for instantiation; if the list is partial, all
|
||||
remaining type arguments must be inferrable.
|
||||
A generic function that is called may provide a (possibly partial) type
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
|
@ -58,9 +59,32 @@ func TestGoDefs(t *testing.T) {
|
|||
t.Fatalf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, cmd.Stderr)
|
||||
}
|
||||
|
||||
if err := os.WriteFile(filepath.Join(dir, fp+"_defs.go"), out, 0644); err != nil {
|
||||
fn := fp + "_defs.go"
|
||||
if err := os.WriteFile(filepath.Join(dir, fn), out, 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Verify that command line arguments are not rewritten in the generated comment,
|
||||
// see go.dev/issue/52063
|
||||
hasGeneratedByComment := false
|
||||
for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") {
|
||||
cgoExe := "cgo"
|
||||
if runtime.GOOS == "windows" {
|
||||
cgoExe = "cgo.exe"
|
||||
}
|
||||
if !strings.HasPrefix(line, "// "+cgoExe+" -godefs") {
|
||||
continue
|
||||
}
|
||||
if want := "// " + cgoExe + " " + strings.Join(cmd.Args[3:], " "); line != want {
|
||||
t.Errorf("%s: got generated comment %q, want %q", fn, line, want)
|
||||
}
|
||||
hasGeneratedByComment = true
|
||||
break
|
||||
}
|
||||
|
||||
if !hasGeneratedByComment {
|
||||
t.Errorf("%s: comment with generating cgo -godefs command not found", fn)
|
||||
}
|
||||
}
|
||||
|
||||
main, err := os.ReadFile(filepath.Join("testdata", "main.go"))
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build aix || linux || darwin || dragonfly || freebsd || openbsd || netbsd || solaris
|
||||
//go:build unix
|
||||
|
||||
package tar
|
||||
|
||||
|
|
|
|||
|
|
@ -865,7 +865,6 @@ func returnRecursiveZip() (r io.ReaderAt, size int64) {
|
|||
//
|
||||
// It's here in hex for the same reason as rZipBytes above: to avoid
|
||||
// problems with on-disk virus scanners or other zip processors.
|
||||
//
|
||||
func biggestZipBytes() []byte {
|
||||
s := `
|
||||
0000000 50 4b 03 04 14 00 08 00 08 00 00 00 00 00 00 00
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ import (
|
|||
// advanced arbitrarily far past the last token. Programs that need more
|
||||
// control over error handling or large tokens, or must run sequential scans
|
||||
// on a reader, should use bufio.Reader instead.
|
||||
//
|
||||
type Scanner struct {
|
||||
r io.Reader // The reader provided by the client.
|
||||
split SplitFunc // The function to split the tokens.
|
||||
|
|
|
|||
|
|
@ -278,46 +278,7 @@ func archArm64() *Arch {
|
|||
}
|
||||
|
||||
register["LR"] = arm64.REGLINK
|
||||
register["DAIFSet"] = arm64.REG_DAIFSet
|
||||
register["DAIFClr"] = arm64.REG_DAIFClr
|
||||
register["PLDL1KEEP"] = arm64.REG_PLDL1KEEP
|
||||
register["PLDL1STRM"] = arm64.REG_PLDL1STRM
|
||||
register["PLDL2KEEP"] = arm64.REG_PLDL2KEEP
|
||||
register["PLDL2STRM"] = arm64.REG_PLDL2STRM
|
||||
register["PLDL3KEEP"] = arm64.REG_PLDL3KEEP
|
||||
register["PLDL3STRM"] = arm64.REG_PLDL3STRM
|
||||
register["PLIL1KEEP"] = arm64.REG_PLIL1KEEP
|
||||
register["PLIL1STRM"] = arm64.REG_PLIL1STRM
|
||||
register["PLIL2KEEP"] = arm64.REG_PLIL2KEEP
|
||||
register["PLIL2STRM"] = arm64.REG_PLIL2STRM
|
||||
register["PLIL3KEEP"] = arm64.REG_PLIL3KEEP
|
||||
register["PLIL3STRM"] = arm64.REG_PLIL3STRM
|
||||
register["PSTL1KEEP"] = arm64.REG_PSTL1KEEP
|
||||
register["PSTL1STRM"] = arm64.REG_PSTL1STRM
|
||||
register["PSTL2KEEP"] = arm64.REG_PSTL2KEEP
|
||||
register["PSTL2STRM"] = arm64.REG_PSTL2STRM
|
||||
register["PSTL3KEEP"] = arm64.REG_PSTL3KEEP
|
||||
register["PSTL3STRM"] = arm64.REG_PSTL3STRM
|
||||
|
||||
// Conditional operators, like EQ, NE, etc.
|
||||
register["EQ"] = arm64.COND_EQ
|
||||
register["NE"] = arm64.COND_NE
|
||||
register["HS"] = arm64.COND_HS
|
||||
register["CS"] = arm64.COND_HS
|
||||
register["LO"] = arm64.COND_LO
|
||||
register["CC"] = arm64.COND_LO
|
||||
register["MI"] = arm64.COND_MI
|
||||
register["PL"] = arm64.COND_PL
|
||||
register["VS"] = arm64.COND_VS
|
||||
register["VC"] = arm64.COND_VC
|
||||
register["HI"] = arm64.COND_HI
|
||||
register["LS"] = arm64.COND_LS
|
||||
register["GE"] = arm64.COND_GE
|
||||
register["LT"] = arm64.COND_LT
|
||||
register["GT"] = arm64.COND_GT
|
||||
register["LE"] = arm64.COND_LE
|
||||
register["AL"] = arm64.COND_AL
|
||||
register["NV"] = arm64.COND_NV
|
||||
// Pseudo-registers.
|
||||
register["SB"] = RSB
|
||||
register["FP"] = RFP
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import (
|
|||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/arm64"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var arm64LS = map[string]uint8{
|
||||
|
|
@ -52,7 +53,35 @@ func jumpArm64(word string) bool {
|
|||
return arm64Jump[word]
|
||||
}
|
||||
|
||||
// IsARM64CMP reports whether the op (as defined by an arm.A* constant) is
|
||||
var arm64SpecialOperand map[string]arm64.SpecialOperand
|
||||
|
||||
// GetARM64SpecialOperand returns the internal representation of a special operand.
|
||||
func GetARM64SpecialOperand(name string) arm64.SpecialOperand {
|
||||
if arm64SpecialOperand == nil {
|
||||
// Generate the mapping automatically when the first time the function is called.
|
||||
arm64SpecialOperand = map[string]arm64.SpecialOperand{}
|
||||
for opd := arm64.SPOP_BEGIN; opd < arm64.SPOP_END; opd++ {
|
||||
s := fmt.Sprintf("%s", opd)
|
||||
arm64SpecialOperand[s] = opd
|
||||
}
|
||||
|
||||
// Handle some special cases.
|
||||
specialMapping := map[string]arm64.SpecialOperand{
|
||||
// The internal representation of CS(CC) and HS(LO) are the same.
|
||||
"CS": arm64.SPOP_HS,
|
||||
"CC": arm64.SPOP_LO,
|
||||
}
|
||||
for s, opd := range specialMapping {
|
||||
arm64SpecialOperand[s] = opd
|
||||
}
|
||||
}
|
||||
if opd, ok := arm64SpecialOperand[name]; ok {
|
||||
return opd
|
||||
}
|
||||
return arm64.SPOP_END
|
||||
}
|
||||
|
||||
// IsARM64CMP reports whether the op (as defined by an arm64.A* constant) is
|
||||
// one of the comparison instructions that require special handling.
|
||||
func IsARM64CMP(op obj.As) bool {
|
||||
switch op {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import (
|
|||
"cmd/asm/internal/flags"
|
||||
"cmd/asm/internal/lex"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/arm64"
|
||||
"cmd/internal/obj/x86"
|
||||
"cmd/internal/src"
|
||||
"cmd/internal/sys"
|
||||
|
|
@ -389,8 +390,19 @@ func (p *Parser) operand(a *obj.Addr) {
|
|||
tok := p.next()
|
||||
name := tok.String()
|
||||
if tok.ScanToken == scanner.Ident && !p.atStartOfRegister(name) {
|
||||
// We have a symbol. Parse $sym±offset(symkind)
|
||||
p.symbolReference(a, name, prefix)
|
||||
switch p.arch.Family {
|
||||
case sys.ARM64:
|
||||
// arm64 special operands.
|
||||
if opd := arch.GetARM64SpecialOperand(name); opd != arm64.SPOP_END {
|
||||
a.Type = obj.TYPE_SPECIAL
|
||||
a.Offset = int64(opd)
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
// We have a symbol. Parse $sym±offset(symkind)
|
||||
p.symbolReference(a, name, prefix)
|
||||
}
|
||||
// fmt.Printf("SYM %s\n", obj.Dconv(&emptyProg, 0, a))
|
||||
if p.peek() == scanner.EOF {
|
||||
return
|
||||
|
|
@ -843,7 +855,6 @@ func (p *Parser) setPseudoRegister(addr *obj.Addr, reg string, isStatic bool, pr
|
|||
//
|
||||
// Anything else beginning with "<" logs an error if issueError is
|
||||
// true, otherwise returns (false, obj.ABI0).
|
||||
//
|
||||
func (p *Parser) symRefAttrs(name string, issueError bool) (bool, obj.ABI) {
|
||||
abi := obj.ABI0
|
||||
isStatic := false
|
||||
|
|
|
|||
|
|
@ -628,7 +628,8 @@ again:
|
|||
CSELW LT, R2, R3, R4 // 44b0831a
|
||||
CSINC GT, R1, ZR, R3 // 23c49f9a
|
||||
CSNEG MI, R1, R2, R3 // 234482da
|
||||
CSINV CS, R1, R2, R3 // CSINV HS, R1, R2, R3 // 232082da
|
||||
CSINV CS, R1, R2, R3 // CSINV HS, R1, R2, R3 // 232082da
|
||||
CSINV HS, R1, R2, R3 // 232082da
|
||||
CSINVW MI, R2, ZR, R2 // 42409f5a
|
||||
CINC EQ, R4, R9 // 8914849a
|
||||
CINCW PL, R2, ZR // 5f44821a
|
||||
|
|
@ -1627,4 +1628,116 @@ again:
|
|||
MSR R13, ZCR_EL1 // 0d1218d5
|
||||
MRS ZCR_EL1, R23 // 171238d5
|
||||
MSR R17, ZCR_EL1 // 111218d5
|
||||
SYS $32768, R1 // 018008d5
|
||||
SYS $32768 // 1f8008d5
|
||||
|
||||
// TLBI instruction
|
||||
TLBI VMALLE1IS // 1f8308d5
|
||||
TLBI VMALLE1 // 1f8708d5
|
||||
TLBI ALLE2IS // 1f830cd5
|
||||
TLBI ALLE1IS // 9f830cd5
|
||||
TLBI VMALLS12E1IS // df830cd5
|
||||
TLBI ALLE2 // 1f870cd5
|
||||
TLBI ALLE1 // 9f870cd5
|
||||
TLBI VMALLS12E1 // df870cd5
|
||||
TLBI ALLE3IS // 1f830ed5
|
||||
TLBI ALLE3 // 1f870ed5
|
||||
TLBI VMALLE1OS // 1f8108d5
|
||||
TLBI ALLE2OS // 1f810cd5
|
||||
TLBI ALLE1OS // 9f810cd5
|
||||
TLBI VMALLS12E1OS // df810cd5
|
||||
TLBI ALLE3OS // 1f810ed5
|
||||
TLBI VAE1IS, R0 // 208308d5
|
||||
TLBI ASIDE1IS, R1 // 418308d5
|
||||
TLBI VAAE1IS, R2 // 628308d5
|
||||
TLBI VALE1IS, R3 // a38308d5
|
||||
TLBI VAALE1IS, R4 // e48308d5
|
||||
TLBI VAE1, R5 // 258708d5
|
||||
TLBI ASIDE1, R6 // 468708d5
|
||||
TLBI VAAE1, R7 // 678708d5
|
||||
TLBI VALE1, R8 // a88708d5
|
||||
TLBI VAALE1, R9 // e98708d5
|
||||
TLBI IPAS2E1IS, R10 // 2a800cd5
|
||||
TLBI IPAS2LE1IS, R11 // ab800cd5
|
||||
TLBI VAE2IS, R12 // 2c830cd5
|
||||
TLBI VALE2IS, R13 // ad830cd5
|
||||
TLBI IPAS2E1, R14 // 2e840cd5
|
||||
TLBI IPAS2LE1, R15 // af840cd5
|
||||
TLBI VAE2, R16 // 30870cd5
|
||||
TLBI VALE2, R17 // b1870cd5
|
||||
TLBI VAE3IS, ZR // 3f830ed5
|
||||
TLBI VALE3IS, R19 // b3830ed5
|
||||
TLBI VAE3, R20 // 34870ed5
|
||||
TLBI VALE3, R21 // b5870ed5
|
||||
TLBI VAE1OS, R22 // 368108d5
|
||||
TLBI ASIDE1OS, R23 // 578108d5
|
||||
TLBI VAAE1OS, R24 // 788108d5
|
||||
TLBI VALE1OS, R25 // b98108d5
|
||||
TLBI VAALE1OS, R26 // fa8108d5
|
||||
TLBI RVAE1IS, R27 // 3b8208d5
|
||||
TLBI RVAAE1IS, ZR // 7f8208d5
|
||||
TLBI RVALE1IS, R29 // bd8208d5
|
||||
TLBI RVAALE1IS, R30 // fe8208d5
|
||||
TLBI RVAE1OS, ZR // 3f8508d5
|
||||
TLBI RVAAE1OS, R0 // 608508d5
|
||||
TLBI RVALE1OS, R1 // a18508d5
|
||||
TLBI RVAALE1OS, R2 // e28508d5
|
||||
TLBI RVAE1, R3 // 238608d5
|
||||
TLBI RVAAE1, R4 // 648608d5
|
||||
TLBI RVALE1, R5 // a58608d5
|
||||
TLBI RVAALE1, R6 // e68608d5
|
||||
TLBI RIPAS2E1IS, R7 // 47800cd5
|
||||
TLBI RIPAS2LE1IS, R8 // c8800cd5
|
||||
TLBI VAE2OS, R9 // 29810cd5
|
||||
TLBI VALE2OS, R10 // aa810cd5
|
||||
TLBI RVAE2IS, R11 // 2b820cd5
|
||||
TLBI RVALE2IS, R12 // ac820cd5
|
||||
TLBI IPAS2E1OS, R13 // 0d840cd5
|
||||
TLBI RIPAS2E1, R14 // 4e840cd5
|
||||
TLBI RIPAS2E1OS, R15 // 6f840cd5
|
||||
TLBI IPAS2LE1OS, R16 // 90840cd5
|
||||
TLBI RIPAS2LE1, R17 // d1840cd5
|
||||
TLBI RIPAS2LE1OS, ZR // ff840cd5
|
||||
TLBI RVAE2OS, R19 // 33850cd5
|
||||
TLBI RVALE2OS, R20 // b4850cd5
|
||||
TLBI RVAE2, R21 // 35860cd5
|
||||
TLBI RVALE2, R22 // b6860cd5
|
||||
TLBI VAE3OS, R23 // 37810ed5
|
||||
TLBI VALE3OS, R24 // b8810ed5
|
||||
TLBI RVAE3IS, R25 // 39820ed5
|
||||
TLBI RVALE3IS, R26 // ba820ed5
|
||||
TLBI RVAE3OS, R27 // 3b850ed5
|
||||
TLBI RVALE3OS, ZR // bf850ed5
|
||||
TLBI RVAE3, R29 // 3d860ed5
|
||||
TLBI RVALE3, R30 // be860ed5
|
||||
|
||||
// DC instruction
|
||||
DC IVAC, R0 // 207608d5
|
||||
DC ISW, R1 // 417608d5
|
||||
DC CSW, R2 // 427a08d5
|
||||
DC CISW, R3 // 437e08d5
|
||||
DC ZVA, R4 // 24740bd5
|
||||
DC CVAC, R5 // 257a0bd5
|
||||
DC CVAU, R6 // 267b0bd5
|
||||
DC CIVAC, R7 // 277e0bd5
|
||||
DC IGVAC, R8 // 687608d5
|
||||
DC IGSW, R9 // 897608d5
|
||||
DC IGDVAC, R10 // aa7608d5
|
||||
DC IGDSW, R11 // cb7608d5
|
||||
DC CGSW, R12 // 8c7a08d5
|
||||
DC CGDSW, R13 // cd7a08d5
|
||||
DC CIGSW, R14 // 8e7e08d5
|
||||
DC CIGDSW, R15 // cf7e08d5
|
||||
DC GVA, R16 // 70740bd5
|
||||
DC GZVA, R17 // 91740bd5
|
||||
DC CGVAC, ZR // 7f7a0bd5
|
||||
DC CGDVAC, R19 // b37a0bd5
|
||||
DC CGVAP, R20 // 747c0bd5
|
||||
DC CGDVAP, R21 // b57c0bd5
|
||||
DC CGVADP, R22 // 767d0bd5
|
||||
DC CGDVADP, R23 // b77d0bd5
|
||||
DC CIGVAC, R24 // 787e0bd5
|
||||
DC CIGDVAC, R25 // b97e0bd5
|
||||
DC CVAP, R26 // 3a7c0bd5
|
||||
DC CVADP, R27 // 3b7d0bd5
|
||||
END
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
|
|||
CSINV LO, R2, R11, R14 // 4e308bda
|
||||
CSNEGW HS, R16, R29, R10 // 0a269d5a
|
||||
CSNEG NE, R21, R19, R11 // ab1693da
|
||||
//TODO DC
|
||||
DC IVAC, R1 // 217608d5
|
||||
DCPS1 $11378 // 418ea5d4
|
||||
DCPS2 $10699 // 6239a5d4
|
||||
DCPS3 $24415 // e3ebabd4
|
||||
|
|
@ -397,7 +397,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
|
|||
SXTH R17, R25 // 393e4093
|
||||
SXTW R0, R27 // 1b7c4093
|
||||
SYSL $285440, R12 // 0c5b2cd5
|
||||
//TODO TLBI
|
||||
TLBI VAE1IS, R1 // 218308d5
|
||||
TSTW $0x80000007, R9 // TSTW $2147483655, R9 // 3f0d0172
|
||||
TST $0xfffffff0, LR // TST $4294967280, R30 // df6f7cf2
|
||||
TSTW R10@>21, R2 // 5f54ca6a
|
||||
|
|
|
|||
|
|
@ -432,4 +432,14 @@ TEXT errors(SB),$0
|
|||
STP (R26, R27), 700(R2) // ERROR "cannot use REGTMP as source"
|
||||
MOVK $0, R10 // ERROR "zero shifts cannot be handled correctly"
|
||||
MOVK $(0<<32), R10 // ERROR "zero shifts cannot be handled correctly"
|
||||
TLBI PLDL1KEEP // ERROR "illegal argument"
|
||||
TLBI VMALLE1IS, R0 // ERROR "extraneous register at operand 2"
|
||||
TLBI ALLE3OS, ZR // ERROR "extraneous register at operand 2"
|
||||
TLBI VAE1IS // ERROR "missing register at operand 2"
|
||||
TLBI RVALE3 // ERROR "missing register at operand 2"
|
||||
DC PLDL1KEEP // ERROR "illegal argument"
|
||||
DC VMALLE1IS // ERROR "illegal argument"
|
||||
DC VAE1IS // ERROR "illegal argument"
|
||||
DC VAE1IS, R0 // ERROR "illegal argument"
|
||||
DC IVAC // ERROR "missing register at operand 2"
|
||||
RET
|
||||
|
|
|
|||
|
|
@ -145,6 +145,19 @@ start:
|
|||
SRLW X5, X6, X7 // bb535300
|
||||
SUBW X5, X6, X7 // bb035340
|
||||
SRAW X5, X6, X7 // bb535340
|
||||
ADDIW $1, X6 // 1b031300
|
||||
SLLIW $1, X6 // 1b131300
|
||||
SRLIW $1, X6 // 1b531300
|
||||
SRAIW $1, X6 // 1b531340
|
||||
ADDW X5, X7 // bb835300
|
||||
SLLW X5, X7 // bb935300
|
||||
SRLW X5, X7 // bbd35300
|
||||
SUBW X5, X7 // bb835340
|
||||
SRAW X5, X7 // bbd35340
|
||||
ADDW $1, X6 // 1b031300
|
||||
SLLW $1, X6 // 1b131300
|
||||
SRLW $1, X6 // 1b531300
|
||||
SRAW $1, X6 // 1b531340
|
||||
|
||||
// 5.3: Load and Store Instructions (RV64I)
|
||||
LD (X5), X6 // 03b30200
|
||||
|
|
|
|||
|
|
@ -22,5 +22,9 @@ TEXT errors(SB),$0
|
|||
MOVBU X5, (X6) // ERROR "unsupported unsigned store"
|
||||
MOVHU X5, (X6) // ERROR "unsupported unsigned store"
|
||||
MOVWU X5, (X6) // ERROR "unsupported unsigned store"
|
||||
MOVF F0, F1, F2 // ERROR "illegal MOV instruction"
|
||||
MOVD F0, F1, F2 // ERROR "illegal MOV instruction"
|
||||
MOV X10, X11, X12 // ERROR "illegal MOV instruction"
|
||||
MOVW X10, X11, X12 // ERROR "illegal MOV instruction"
|
||||
|
||||
RET
|
||||
|
|
|
|||
|
|
@ -119,7 +119,6 @@ func (p *Package) addToFlag(flag string, args []string) {
|
|||
// Would be parsed as:
|
||||
//
|
||||
// []string{"a", "b:c d", "ef", `g"`}
|
||||
//
|
||||
func splitQuoted(s string) (r []string, err error) {
|
||||
var args []string
|
||||
arg := make([]rune, len(s))
|
||||
|
|
|
|||
|
|
@ -16,11 +16,11 @@ import (
|
|||
)
|
||||
|
||||
// godefs returns the output for -godefs mode.
|
||||
func (p *Package) godefs(f *File) string {
|
||||
func (p *Package) godefs(f *File, args []string) string {
|
||||
var buf bytes.Buffer
|
||||
|
||||
fmt.Fprintf(&buf, "// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n")
|
||||
fmt.Fprintf(&buf, "// %s %s\n", filepath.Base(os.Args[0]), strings.Join(os.Args[1:], " "))
|
||||
fmt.Fprintf(&buf, "// %s %s\n", filepath.Base(args[0]), strings.Join(args[1:], " "))
|
||||
fmt.Fprintf(&buf, "\n")
|
||||
|
||||
override := make(map[string]string)
|
||||
|
|
|
|||
|
|
@ -291,6 +291,10 @@ func main() {
|
|||
usage()
|
||||
}
|
||||
|
||||
// Save original command line arguments for the godefs generated comment. Relative file
|
||||
// paths in os.Args will be rewritten to absolute file paths in the loop below.
|
||||
osArgs := make([]string, len(os.Args))
|
||||
copy(osArgs, os.Args[:])
|
||||
goFiles := args[i:]
|
||||
|
||||
for _, arg := range args[:i] {
|
||||
|
|
@ -390,7 +394,7 @@ func main() {
|
|||
p.PackagePath = f.Package
|
||||
p.Record(f)
|
||||
if *godefs {
|
||||
os.Stdout.WriteString(p.godefs(f))
|
||||
os.Stdout.WriteString(p.godefs(f, osArgs))
|
||||
} else {
|
||||
p.writeOutput(f, input)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,18 +57,19 @@ func (p *Package) writeDefs() {
|
|||
fflg.Close()
|
||||
|
||||
// Write C main file for using gcc to resolve imports.
|
||||
fmt.Fprintf(fm, "#include <stddef.h>\n") // For size_t below.
|
||||
fmt.Fprintf(fm, "int main() { return 0; }\n")
|
||||
if *importRuntimeCgo {
|
||||
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*) __attribute__((unused)), void *a __attribute__((unused)), int c __attribute__((unused)), __SIZE_TYPE__ ctxt __attribute__((unused))) { }\n")
|
||||
fmt.Fprintf(fm, "__SIZE_TYPE__ _cgo_wait_runtime_init_done(void) { return 0; }\n")
|
||||
fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__ ctxt __attribute__((unused))) { }\n")
|
||||
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*) __attribute__((unused)), void *a __attribute__((unused)), int c __attribute__((unused)), size_t ctxt __attribute__((unused))) { }\n")
|
||||
fmt.Fprintf(fm, "size_t _cgo_wait_runtime_init_done(void) { return 0; }\n")
|
||||
fmt.Fprintf(fm, "void _cgo_release_context(size_t ctxt __attribute__((unused))) { }\n")
|
||||
fmt.Fprintf(fm, "char* _cgo_topofstack(void) { return (char*)0; }\n")
|
||||
} else {
|
||||
// If we're not importing runtime/cgo, we *are* runtime/cgo,
|
||||
// which provides these functions. We just need a prototype.
|
||||
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*), void *a, int c, __SIZE_TYPE__ ctxt);\n")
|
||||
fmt.Fprintf(fm, "__SIZE_TYPE__ _cgo_wait_runtime_init_done(void);\n")
|
||||
fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__);\n")
|
||||
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*), void *a, int c, size_t ctxt);\n")
|
||||
fmt.Fprintf(fm, "size_t _cgo_wait_runtime_init_done(void);\n")
|
||||
fmt.Fprintf(fm, "void _cgo_release_context(size_t);\n")
|
||||
}
|
||||
fmt.Fprintf(fm, "void _cgo_allocate(void *a __attribute__((unused)), int c __attribute__((unused))) { }\n")
|
||||
fmt.Fprintf(fm, "void _cgo_panic(void *a __attribute__((unused)), int c __attribute__((unused))) { }\n")
|
||||
|
|
@ -886,9 +887,9 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
|||
fmt.Fprintf(fgcc, "#pragma GCC diagnostic ignored \"-Wpragmas\"\n")
|
||||
fmt.Fprintf(fgcc, "#pragma GCC diagnostic ignored \"-Waddress-of-packed-member\"\n")
|
||||
|
||||
fmt.Fprintf(fgcc, "extern void crosscall2(void (*fn)(void *), void *, int, __SIZE_TYPE__);\n")
|
||||
fmt.Fprintf(fgcc, "extern __SIZE_TYPE__ _cgo_wait_runtime_init_done(void);\n")
|
||||
fmt.Fprintf(fgcc, "extern void _cgo_release_context(__SIZE_TYPE__);\n\n")
|
||||
fmt.Fprintf(fgcc, "extern void crosscall2(void (*fn)(void *), void *, int, size_t);\n")
|
||||
fmt.Fprintf(fgcc, "extern size_t _cgo_wait_runtime_init_done(void);\n")
|
||||
fmt.Fprintf(fgcc, "extern void _cgo_release_context(size_t);\n\n")
|
||||
fmt.Fprintf(fgcc, "extern char* _cgo_topofstack(void);")
|
||||
fmt.Fprintf(fgcc, "%s\n", tsanProlog)
|
||||
fmt.Fprintf(fgcc, "%s\n", msanProlog)
|
||||
|
|
@ -992,7 +993,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
|||
fmt.Fprintf(fgcc, "\nCGO_NO_SANITIZE_THREAD")
|
||||
fmt.Fprintf(fgcc, "\n%s\n", s)
|
||||
fmt.Fprintf(fgcc, "{\n")
|
||||
fmt.Fprintf(fgcc, "\t__SIZE_TYPE__ _cgo_ctxt = _cgo_wait_runtime_init_done();\n")
|
||||
fmt.Fprintf(fgcc, "\tsize_t _cgo_ctxt = _cgo_wait_runtime_init_done();\n")
|
||||
// The results part of the argument structure must be
|
||||
// initialized to 0 so the write barriers generated by
|
||||
// the assignments to these fields in Go are safe.
|
||||
|
|
@ -1561,7 +1562,7 @@ var msanProlog = noMsanProlog
|
|||
|
||||
const builtinProlog = `
|
||||
#line 1 "cgo-builtin-prolog"
|
||||
#include <stddef.h> /* for ptrdiff_t and size_t below */
|
||||
#include <stddef.h>
|
||||
|
||||
/* Define intgo when compiling with GCC. */
|
||||
typedef ptrdiff_t intgo;
|
||||
|
|
@ -1604,6 +1605,7 @@ const goStringDef = `
|
|||
//go:linkname _cgo_runtime_gostring runtime.gostring
|
||||
func _cgo_runtime_gostring(*_Ctype_char) string
|
||||
|
||||
// GoString converts the C string p into a Go string.
|
||||
func _Cfunc_GoString(p *_Ctype_char) string {
|
||||
return _cgo_runtime_gostring(p)
|
||||
}
|
||||
|
|
@ -1613,6 +1615,7 @@ const goStringNDef = `
|
|||
//go:linkname _cgo_runtime_gostringn runtime.gostringn
|
||||
func _cgo_runtime_gostringn(*_Ctype_char, int) string
|
||||
|
||||
// GoStringN converts the C data p with explicit length l to a Go string.
|
||||
func _Cfunc_GoStringN(p *_Ctype_char, l _Ctype_int) string {
|
||||
return _cgo_runtime_gostringn(p, int(l))
|
||||
}
|
||||
|
|
@ -1622,12 +1625,19 @@ const goBytesDef = `
|
|||
//go:linkname _cgo_runtime_gobytes runtime.gobytes
|
||||
func _cgo_runtime_gobytes(unsafe.Pointer, int) []byte
|
||||
|
||||
// GoBytes converts the C data p with explicit length l to a Go []byte.
|
||||
func _Cfunc_GoBytes(p unsafe.Pointer, l _Ctype_int) []byte {
|
||||
return _cgo_runtime_gobytes(p, int(l))
|
||||
}
|
||||
`
|
||||
|
||||
const cStringDef = `
|
||||
// CString converts the Go string s to a C string.
|
||||
//
|
||||
// The C string is allocated in the C heap using malloc.
|
||||
// It is the caller's responsibility to arrange for it to be
|
||||
// freed, such as by calling C.free (be sure to include stdlib.h
|
||||
// if C.free is needed).
|
||||
func _Cfunc_CString(s string) *_Ctype_char {
|
||||
p := _cgo_cmalloc(uint64(len(s)+1))
|
||||
pp := (*[1<<30]byte)(p)
|
||||
|
|
@ -1638,6 +1648,12 @@ func _Cfunc_CString(s string) *_Ctype_char {
|
|||
`
|
||||
|
||||
const cBytesDef = `
|
||||
// CBytes converts the Go []byte slice b to a C array.
|
||||
//
|
||||
// The C array is allocated in the C heap using malloc.
|
||||
// It is the caller's responsibility to arrange for it to be
|
||||
// freed, such as by calling C.free (be sure to include stdlib.h
|
||||
// if C.free is needed).
|
||||
func _Cfunc_CBytes(b []byte) unsafe.Pointer {
|
||||
p := _cgo_cmalloc(uint64(len(b)))
|
||||
pp := (*[1<<30]byte)(p)
|
||||
|
|
@ -1830,7 +1846,7 @@ void localCgoCheckResult(Eface val) {
|
|||
const builtinExportProlog = `
|
||||
#line 1 "cgo-builtin-export-prolog"
|
||||
|
||||
#include <stddef.h> /* for ptrdiff_t below */
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef GO_CGO_EXPORT_PROLOGUE_H
|
||||
#define GO_CGO_EXPORT_PROLOGUE_H
|
||||
|
|
@ -1876,7 +1892,7 @@ typedef long long GoInt64;
|
|||
typedef unsigned long long GoUint64;
|
||||
typedef GoIntGOINTBITS GoInt;
|
||||
typedef GoUintGOINTBITS GoUint;
|
||||
typedef __SIZE_TYPE__ GoUintptr;
|
||||
typedef size_t GoUintptr;
|
||||
typedef float GoFloat32;
|
||||
typedef double GoFloat64;
|
||||
typedef float _Complex GoComplex64;
|
||||
|
|
@ -1926,5 +1942,5 @@ static void GoInit(void) {
|
|||
runtime_iscgo = 1;
|
||||
}
|
||||
|
||||
extern __SIZE_TYPE__ _cgo_wait_runtime_init_done(void) __attribute__ ((weak));
|
||||
extern size_t _cgo_wait_runtime_init_done(void) __attribute__ ((weak));
|
||||
`
|
||||
|
|
|
|||
|
|
@ -788,12 +788,12 @@ func (state *assignState) assignParamOrReturn(pt *types.Type, n types.Object, is
|
|||
// field. For things that are not structs (or structs without padding)
|
||||
// it returns a list of zeros. Example:
|
||||
//
|
||||
// type small struct {
|
||||
// x uint16
|
||||
// y uint8
|
||||
// z int32
|
||||
// w int32
|
||||
// }
|
||||
// type small struct {
|
||||
// x uint16
|
||||
// y uint8
|
||||
// z int32
|
||||
// w int32
|
||||
// }
|
||||
//
|
||||
// For this struct we would return a list [0, 1, 0, 0], meaning that
|
||||
// we have one byte of padding after the second field, and no bytes of
|
||||
|
|
|
|||
|
|
@ -265,8 +265,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
|||
|
||||
case ssa.OpAMD64BLSIQ, ssa.OpAMD64BLSIL,
|
||||
ssa.OpAMD64BLSMSKQ, ssa.OpAMD64BLSMSKL,
|
||||
ssa.OpAMD64BLSRQ, ssa.OpAMD64BLSRL,
|
||||
ssa.OpAMD64TZCNTQ, ssa.OpAMD64TZCNTL:
|
||||
ssa.OpAMD64BLSRQ, ssa.OpAMD64BLSRL:
|
||||
p := s.Prog(v.Op.Asm())
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = v.Args[0].Reg()
|
||||
|
|
@ -281,6 +280,23 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
|||
p.To.Reg = v.Reg()
|
||||
p.SetFrom3Reg(v.Args[1].Reg())
|
||||
|
||||
case ssa.OpAMD64SHLXLload, ssa.OpAMD64SHLXQload,
|
||||
ssa.OpAMD64SHRXLload, ssa.OpAMD64SHRXQload:
|
||||
p := opregreg(s, v.Op.Asm(), v.Reg(), v.Args[1].Reg())
|
||||
m := obj.Addr{Type: obj.TYPE_MEM, Reg: v.Args[0].Reg()}
|
||||
ssagen.AddAux(&m, v)
|
||||
p.SetFrom3(m)
|
||||
|
||||
case ssa.OpAMD64SHLXLloadidx1, ssa.OpAMD64SHLXLloadidx4, ssa.OpAMD64SHLXLloadidx8,
|
||||
ssa.OpAMD64SHRXLloadidx1, ssa.OpAMD64SHRXLloadidx4, ssa.OpAMD64SHRXLloadidx8,
|
||||
ssa.OpAMD64SHLXQloadidx1, ssa.OpAMD64SHLXQloadidx8,
|
||||
ssa.OpAMD64SHRXQloadidx1, ssa.OpAMD64SHRXQloadidx8:
|
||||
p := opregreg(s, v.Op.Asm(), v.Reg(), v.Args[2].Reg())
|
||||
m := obj.Addr{Type: obj.TYPE_MEM}
|
||||
memIdx(&m, v)
|
||||
ssagen.AddAux(&m, v)
|
||||
p.SetFrom3(m)
|
||||
|
||||
case ssa.OpAMD64DIVQU, ssa.OpAMD64DIVLU, ssa.OpAMD64DIVWU:
|
||||
// Arg[0] (the dividend) is in AX.
|
||||
// Arg[1] (the divisor) can be in any other register.
|
||||
|
|
@ -289,11 +305,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
|||
r := v.Args[1].Reg()
|
||||
|
||||
// Zero extend dividend.
|
||||
c := s.Prog(x86.AXORL)
|
||||
c.From.Type = obj.TYPE_REG
|
||||
c.From.Reg = x86.REG_DX
|
||||
c.To.Type = obj.TYPE_REG
|
||||
c.To.Reg = x86.REG_DX
|
||||
opregreg(s, x86.AXORL, x86.REG_DX, x86.REG_DX)
|
||||
|
||||
// Issue divide.
|
||||
p := s.Prog(v.Op.Asm())
|
||||
|
|
@ -363,11 +375,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
|||
n1.To.Reg = x86.REG_AX
|
||||
|
||||
// n % -1 == 0
|
||||
n2 := s.Prog(x86.AXORL)
|
||||
n2.From.Type = obj.TYPE_REG
|
||||
n2.From.Reg = x86.REG_DX
|
||||
n2.To.Type = obj.TYPE_REG
|
||||
n2.To.Reg = x86.REG_DX
|
||||
opregreg(s, x86.AXORL, x86.REG_DX, x86.REG_DX)
|
||||
|
||||
// TODO(khr): issue only the -1 fixup code we need.
|
||||
// For instance, if only the quotient is used, no point in zeroing the remainder.
|
||||
|
|
@ -745,11 +753,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
|||
// If flags aren't live (indicated by v.Aux == nil),
|
||||
// then we can rewrite MOV $0, AX into XOR AX, AX.
|
||||
if v.AuxInt == 0 && v.Aux == nil {
|
||||
p := s.Prog(x86.AXORL)
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = x
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = x
|
||||
opregreg(s, x86.AXORL, x, x)
|
||||
break
|
||||
}
|
||||
|
||||
|
|
@ -791,7 +795,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
|||
case ssa.OpAMD64MOVQstore, ssa.OpAMD64MOVSSstore, ssa.OpAMD64MOVSDstore, ssa.OpAMD64MOVLstore, ssa.OpAMD64MOVWstore, ssa.OpAMD64MOVBstore, ssa.OpAMD64MOVOstore,
|
||||
ssa.OpAMD64ADDQmodify, ssa.OpAMD64SUBQmodify, ssa.OpAMD64ANDQmodify, ssa.OpAMD64ORQmodify, ssa.OpAMD64XORQmodify,
|
||||
ssa.OpAMD64ADDLmodify, ssa.OpAMD64SUBLmodify, ssa.OpAMD64ANDLmodify, ssa.OpAMD64ORLmodify, ssa.OpAMD64XORLmodify,
|
||||
ssa.OpAMD64MOVBEQstore, ssa.OpAMD64MOVBELstore:
|
||||
ssa.OpAMD64MOVBEQstore, ssa.OpAMD64MOVBELstore, ssa.OpAMD64MOVBEWstore:
|
||||
p := s.Prog(v.Op.Asm())
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = v.Args[1].Reg()
|
||||
|
|
@ -1137,15 +1141,14 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
|||
p.SetFrom3Reg(v.Args[0].Reg())
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = v.Reg()
|
||||
case ssa.OpAMD64POPCNTQ, ssa.OpAMD64POPCNTL:
|
||||
case ssa.OpAMD64POPCNTQ, ssa.OpAMD64POPCNTL,
|
||||
ssa.OpAMD64TZCNTQ, ssa.OpAMD64TZCNTL,
|
||||
ssa.OpAMD64LZCNTQ, ssa.OpAMD64LZCNTL:
|
||||
if v.Args[0].Reg() != v.Reg() {
|
||||
// POPCNT on Intel has a false dependency on the destination register.
|
||||
// POPCNT/TZCNT/LZCNT have a false dependency on the destination register on Intel cpus.
|
||||
// TZCNT/LZCNT problem affects pre-Skylake models. See discussion at https://gcc.gnu.org/bugzilla/show_bug.cgi?id=62011#c7.
|
||||
// Xor register with itself to break the dependency.
|
||||
p := s.Prog(x86.AXORL)
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = v.Reg()
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = v.Reg()
|
||||
opregreg(s, x86.AXORL, v.Reg(), v.Reg())
|
||||
}
|
||||
p := s.Prog(v.Op.Asm())
|
||||
p.From.Type = obj.TYPE_REG
|
||||
|
|
|
|||
|
|
@ -244,6 +244,7 @@ var featureToOpcodes = map[string][]string{
|
|||
"sse41": {"roundsd"},
|
||||
"fma": {"vfmadd231sd"},
|
||||
"movbe": {"movbeqq", "movbeq", "movbell", "movbel", "movbe"},
|
||||
"lzcnt": {"lzcntq", "lzcntl", "lzcnt"},
|
||||
}
|
||||
|
||||
// Test to use POPCNT instruction, if available
|
||||
|
|
|
|||
|
|
@ -728,8 +728,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
|||
p4.To.Type = obj.TYPE_BRANCH
|
||||
p4.To.SetTarget(p)
|
||||
p5 := s.Prog(arm64.ACSET)
|
||||
p5.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg
|
||||
p5.From.Reg = arm64.COND_EQ
|
||||
p5.From.Type = obj.TYPE_SPECIAL // assembler encodes conditional bits in Offset
|
||||
p5.From.Offset = int64(arm64.SPOP_EQ)
|
||||
p5.To.Type = obj.TYPE_REG
|
||||
p5.To.Reg = out
|
||||
p2.To.SetTarget(p5)
|
||||
|
|
@ -778,8 +778,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
|||
|
||||
// CSET EQ, Rout
|
||||
p3 := s.Prog(arm64.ACSET)
|
||||
p3.From.Type = obj.TYPE_REG
|
||||
p3.From.Reg = arm64.COND_EQ
|
||||
p3.From.Type = obj.TYPE_SPECIAL // assembler encodes conditional bits in Offset
|
||||
p3.From.Offset = int64(arm64.SPOP_EQ)
|
||||
p3.To.Type = obj.TYPE_REG
|
||||
p3.To.Reg = out
|
||||
|
||||
|
|
@ -978,24 +978,27 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
|||
r1 = v.Args[1].Reg()
|
||||
}
|
||||
p := s.Prog(v.Op.Asm())
|
||||
p.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg
|
||||
p.From.Reg = condBits[ssa.Op(v.AuxInt)]
|
||||
p.From.Type = obj.TYPE_SPECIAL // assembler encodes conditional bits in Offset
|
||||
condCode := condBits[ssa.Op(v.AuxInt)]
|
||||
p.From.Offset = int64(condCode)
|
||||
p.Reg = v.Args[0].Reg()
|
||||
p.SetFrom3Reg(r1)
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = v.Reg()
|
||||
case ssa.OpARM64CSINC, ssa.OpARM64CSINV, ssa.OpARM64CSNEG:
|
||||
p := s.Prog(v.Op.Asm())
|
||||
p.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg
|
||||
p.From.Reg = condBits[ssa.Op(v.AuxInt)]
|
||||
p.From.Type = obj.TYPE_SPECIAL // assembler encodes conditional bits in Offset
|
||||
condCode := condBits[ssa.Op(v.AuxInt)]
|
||||
p.From.Offset = int64(condCode)
|
||||
p.Reg = v.Args[0].Reg()
|
||||
p.SetFrom3Reg(v.Args[1].Reg())
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = v.Reg()
|
||||
case ssa.OpARM64CSETM:
|
||||
p := s.Prog(arm64.ACSETM)
|
||||
p.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg
|
||||
p.From.Reg = condBits[ssa.Op(v.AuxInt)]
|
||||
p.From.Type = obj.TYPE_SPECIAL // assembler encodes conditional bits in Offset
|
||||
condCode := condBits[ssa.Op(v.AuxInt)]
|
||||
p.From.Offset = int64(condCode)
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = v.Reg()
|
||||
case ssa.OpARM64DUFFZERO:
|
||||
|
|
@ -1107,8 +1110,9 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
|||
ssa.OpARM64NotGreaterEqualF:
|
||||
// generate boolean values using CSET
|
||||
p := s.Prog(arm64.ACSET)
|
||||
p.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg
|
||||
p.From.Reg = condBits[v.Op]
|
||||
p.From.Type = obj.TYPE_SPECIAL // assembler encodes conditional bits in Offset
|
||||
condCode := condBits[v.Op]
|
||||
p.From.Offset = int64(condCode)
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = v.Reg()
|
||||
case ssa.OpARM64PRFM:
|
||||
|
|
@ -1173,27 +1177,27 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
|||
}
|
||||
}
|
||||
|
||||
var condBits = map[ssa.Op]int16{
|
||||
ssa.OpARM64Equal: arm64.COND_EQ,
|
||||
ssa.OpARM64NotEqual: arm64.COND_NE,
|
||||
ssa.OpARM64LessThan: arm64.COND_LT,
|
||||
ssa.OpARM64LessThanU: arm64.COND_LO,
|
||||
ssa.OpARM64LessEqual: arm64.COND_LE,
|
||||
ssa.OpARM64LessEqualU: arm64.COND_LS,
|
||||
ssa.OpARM64GreaterThan: arm64.COND_GT,
|
||||
ssa.OpARM64GreaterThanU: arm64.COND_HI,
|
||||
ssa.OpARM64GreaterEqual: arm64.COND_GE,
|
||||
ssa.OpARM64GreaterEqualU: arm64.COND_HS,
|
||||
ssa.OpARM64LessThanF: arm64.COND_MI, // Less than
|
||||
ssa.OpARM64LessEqualF: arm64.COND_LS, // Less than or equal to
|
||||
ssa.OpARM64GreaterThanF: arm64.COND_GT, // Greater than
|
||||
ssa.OpARM64GreaterEqualF: arm64.COND_GE, // Greater than or equal to
|
||||
var condBits = map[ssa.Op]arm64.SpecialOperand{
|
||||
ssa.OpARM64Equal: arm64.SPOP_EQ,
|
||||
ssa.OpARM64NotEqual: arm64.SPOP_NE,
|
||||
ssa.OpARM64LessThan: arm64.SPOP_LT,
|
||||
ssa.OpARM64LessThanU: arm64.SPOP_LO,
|
||||
ssa.OpARM64LessEqual: arm64.SPOP_LE,
|
||||
ssa.OpARM64LessEqualU: arm64.SPOP_LS,
|
||||
ssa.OpARM64GreaterThan: arm64.SPOP_GT,
|
||||
ssa.OpARM64GreaterThanU: arm64.SPOP_HI,
|
||||
ssa.OpARM64GreaterEqual: arm64.SPOP_GE,
|
||||
ssa.OpARM64GreaterEqualU: arm64.SPOP_HS,
|
||||
ssa.OpARM64LessThanF: arm64.SPOP_MI, // Less than
|
||||
ssa.OpARM64LessEqualF: arm64.SPOP_LS, // Less than or equal to
|
||||
ssa.OpARM64GreaterThanF: arm64.SPOP_GT, // Greater than
|
||||
ssa.OpARM64GreaterEqualF: arm64.SPOP_GE, // Greater than or equal to
|
||||
|
||||
// The following condition codes have unordered to handle comparisons related to NaN.
|
||||
ssa.OpARM64NotLessThanF: arm64.COND_PL, // Greater than, equal to, or unordered
|
||||
ssa.OpARM64NotLessEqualF: arm64.COND_HI, // Greater than or unordered
|
||||
ssa.OpARM64NotGreaterThanF: arm64.COND_LE, // Less than, equal to or unordered
|
||||
ssa.OpARM64NotGreaterEqualF: arm64.COND_LT, // Less than or unordered
|
||||
ssa.OpARM64NotLessThanF: arm64.SPOP_PL, // Greater than, equal to, or unordered
|
||||
ssa.OpARM64NotLessEqualF: arm64.SPOP_HI, // Greater than or unordered
|
||||
ssa.OpARM64NotGreaterThanF: arm64.SPOP_LE, // Less than, equal to or unordered
|
||||
ssa.OpARM64NotGreaterEqualF: arm64.SPOP_LT, // Less than or unordered
|
||||
}
|
||||
|
||||
var blockJump = map[ssa.BlockKind]struct {
|
||||
|
|
|
|||
|
|
@ -41,7 +41,9 @@ func readGopackHeader(r *bufio.Reader) (name string, size int, err error) {
|
|||
// start of the file before calling this function. The hdr result
|
||||
// is the string before the export data, either "$$" or "$$B".
|
||||
//
|
||||
func FindExportData(r *bufio.Reader) (hdr string, err error) {
|
||||
// If size is non-negative, it's the number of bytes of export data
|
||||
// still available to read from r.
|
||||
func FindExportData(r *bufio.Reader) (hdr string, size int, err error) {
|
||||
// Read first line to make sure this is an object file.
|
||||
line, err := r.ReadSlice('\n')
|
||||
if err != nil {
|
||||
|
|
@ -52,7 +54,7 @@ func FindExportData(r *bufio.Reader) (hdr string, err error) {
|
|||
if string(line) == "!<arch>\n" {
|
||||
// Archive file. Scan to __.PKGDEF.
|
||||
var name string
|
||||
if name, _, err = readGopackHeader(r); err != nil {
|
||||
if name, size, err = readGopackHeader(r); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -76,6 +78,7 @@ func FindExportData(r *bufio.Reader) (hdr string, err error) {
|
|||
err = fmt.Errorf("not a Go object file")
|
||||
return
|
||||
}
|
||||
size -= len(line)
|
||||
|
||||
// Skip over object header to export data.
|
||||
// Begins after first line starting with $$.
|
||||
|
|
@ -84,6 +87,7 @@ func FindExportData(r *bufio.Reader) (hdr string, err error) {
|
|||
err = fmt.Errorf("can't find export data (%v)", err)
|
||||
return
|
||||
}
|
||||
size -= len(line)
|
||||
}
|
||||
hdr = string(line)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
"cmd/compile/internal/types2"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"internal/pkgbits"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
|
@ -27,7 +28,6 @@ var pkgExts = [...]string{".a", ".o"}
|
|||
// the build.Default build.Context). A relative srcDir is interpreted
|
||||
// relative to the current working directory.
|
||||
// If no file was found, an empty filename is returned.
|
||||
//
|
||||
func FindPkg(path, srcDir string) (filename, id string) {
|
||||
if path == "" {
|
||||
return
|
||||
|
|
@ -83,7 +83,6 @@ func FindPkg(path, srcDir string) (filename, id string) {
|
|||
// Import imports a gc-generated package given its import path and srcDir, adds
|
||||
// the corresponding package object to the packages map, and returns the object.
|
||||
// The packages map must contain all packages already imported.
|
||||
//
|
||||
func Import(packages map[string]*types2.Package, path, srcDir string, lookup func(path string) (io.ReadCloser, error)) (pkg *types2.Package, err error) {
|
||||
var rc io.ReadCloser
|
||||
var id string
|
||||
|
|
@ -134,9 +133,9 @@ func Import(packages map[string]*types2.Package, path, srcDir string, lookup fun
|
|||
}
|
||||
defer rc.Close()
|
||||
|
||||
var hdr string
|
||||
buf := bufio.NewReader(rc)
|
||||
if hdr, err = FindExportData(buf); err != nil {
|
||||
hdr, size, err := FindExportData(buf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -146,17 +145,33 @@ func Import(packages map[string]*types2.Package, path, srcDir string, lookup fun
|
|||
|
||||
case "$$B\n":
|
||||
var data []byte
|
||||
data, err = ioutil.ReadAll(buf)
|
||||
var r io.Reader = buf
|
||||
if size >= 0 {
|
||||
r = io.LimitReader(r, int64(size))
|
||||
}
|
||||
data, err = ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
if len(data) == 0 {
|
||||
err = fmt.Errorf("import %q: missing export data", path)
|
||||
break
|
||||
}
|
||||
exportFormat := data[0]
|
||||
s := string(data[1:])
|
||||
|
||||
// The indexed export format starts with an 'i'; the older
|
||||
// binary export format starts with a 'c', 'd', or 'v'
|
||||
// (from "version"). Select appropriate importer.
|
||||
if len(data) > 0 && data[0] == 'i' {
|
||||
pkg, err = ImportData(packages, string(data[1:]), id)
|
||||
} else {
|
||||
switch exportFormat {
|
||||
case 'u':
|
||||
s = s[:strings.Index(s, "\n$$\n")]
|
||||
input := pkgbits.NewPkgDecoder(id, s)
|
||||
pkg = ReadPackage(nil, packages, input)
|
||||
case 'i':
|
||||
pkg, err = ImportData(packages, s, id)
|
||||
default:
|
||||
err = fmt.Errorf("import %q: old binary export format no longer supported (recompile library)", path)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -115,10 +115,14 @@ func TestImportTestdata(t *testing.T) {
|
|||
}
|
||||
|
||||
testfiles := map[string][]string{
|
||||
"exports.go": {"go/ast", "go/token"},
|
||||
"exports.go": {"go/ast", "go/token"},
|
||||
"generics.go": nil,
|
||||
}
|
||||
if !goexperiment.Unified {
|
||||
testfiles["generics.go"] = nil
|
||||
if goexperiment.Unified {
|
||||
// TODO(mdempsky): Fix test below to flatten the transitive
|
||||
// Package.Imports graph. Unified IR is more precise about
|
||||
// recreating the package import graph.
|
||||
testfiles["exports.go"] = []string{"go/ast"}
|
||||
}
|
||||
|
||||
for testfile, wantImports := range testfiles {
|
||||
|
|
@ -326,6 +330,14 @@ func verifyInterfaceMethodRecvs(t *testing.T, named *types2.Named, level int) {
|
|||
return // not an interface
|
||||
}
|
||||
|
||||
// The unified IR importer always sets interface method receiver
|
||||
// parameters to point to the Interface type, rather than the Named.
|
||||
// See #49906.
|
||||
var want types2.Type = named
|
||||
if goexperiment.Unified {
|
||||
want = iface
|
||||
}
|
||||
|
||||
// check explicitly declared methods
|
||||
for i := 0; i < iface.NumExplicitMethods(); i++ {
|
||||
m := iface.ExplicitMethod(i)
|
||||
|
|
@ -334,7 +346,7 @@ func verifyInterfaceMethodRecvs(t *testing.T, named *types2.Named, level int) {
|
|||
t.Errorf("%s: missing receiver type", m)
|
||||
continue
|
||||
}
|
||||
if recv.Type() != named {
|
||||
if recv.Type() != want {
|
||||
t.Errorf("%s: got recv type %s; want %s", m, recv.Type(), named)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -951,11 +951,11 @@ var IsIntrinsicCall = func(*CallExpr) bool { return false }
|
|||
// instead of computing both. SameSafeExpr assumes that l and r are
|
||||
// used in the same statement or expression. In order for it to be
|
||||
// safe to reuse l or r, they must:
|
||||
// * be the same expression
|
||||
// * not have side-effects (no function calls, no channel ops);
|
||||
// however, panics are ok
|
||||
// * not cause inappropriate aliasing; e.g. two string to []byte
|
||||
// conversions, must result in two distinct slices
|
||||
// * be the same expression
|
||||
// * not have side-effects (no function calls, no channel ops);
|
||||
// however, panics are ok
|
||||
// * not cause inappropriate aliasing; e.g. two string to []byte
|
||||
// conversions, must result in two distinct slices
|
||||
//
|
||||
// The handling of OINDEXMAP is subtle. OINDEXMAP can occur both
|
||||
// as an lvalue (map assignment) and an rvalue (map access). This is
|
||||
|
|
|
|||
|
|
@ -105,7 +105,6 @@ func (o Op) GoString() string {
|
|||
//
|
||||
// %v Go syntax ("+", "<-", "print")
|
||||
// %+v Debug syntax ("ADD", "RECV", "PRINT")
|
||||
//
|
||||
func (o Op) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
default:
|
||||
|
|
@ -129,7 +128,6 @@ func (o Op) Format(s fmt.State, verb rune) {
|
|||
// %v Go syntax
|
||||
// %L Go syntax followed by " (type T)" if type is known.
|
||||
// %+v Debug syntax, as in Dump.
|
||||
//
|
||||
func fmtNode(n Node, s fmt.State, verb rune) {
|
||||
// %+v prints Dump.
|
||||
// Otherwise we print Go syntax.
|
||||
|
|
@ -926,7 +924,6 @@ func ellipsisIf(b bool) string {
|
|||
// %v Go syntax, semicolon-separated
|
||||
// %.v Go syntax, comma-separated
|
||||
// %+v Debug syntax, as in DumpList.
|
||||
//
|
||||
func (l Nodes) Format(s fmt.State, verb rune) {
|
||||
if s.Flag('+') && verb == 'v' {
|
||||
// %+v is DumpList output
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ import (
|
|||
// The embedding struct should also fill in n.op in its constructor,
|
||||
// for more useful panic messages when invalid methods are called,
|
||||
// instead of implementing Op itself.
|
||||
//
|
||||
type miniNode struct {
|
||||
pos src.XPos // uint32
|
||||
op Op // uint8
|
||||
|
|
|
|||
|
|
@ -14,52 +14,22 @@ import (
|
|||
"cmd/internal/bio"
|
||||
)
|
||||
|
||||
// writeNewExportFunc is a hook that can be added to append extra
|
||||
// export data after the normal export data section. It allows
|
||||
// experimenting with new export data format designs without requiring
|
||||
// immediate support in the go/internal or x/tools importers.
|
||||
var writeNewExportFunc func(out io.Writer)
|
||||
|
||||
func WriteExports(out *bio.Writer) {
|
||||
// When unified IR exports are enable, we simply append it to the
|
||||
// end of the normal export data (with compiler extensions
|
||||
// disabled), and write an extra header giving its size.
|
||||
//
|
||||
// If the compiler sees this header, it knows to read the new data
|
||||
// instead; meanwhile the go/types importers will silently ignore it
|
||||
// and continue processing the old export instead.
|
||||
//
|
||||
// This allows us to experiment with changes to the new export data
|
||||
// format without needing to update the go/internal/gcimporter or
|
||||
// (worse) x/tools/go/gcexportdata.
|
||||
var data bytes.Buffer
|
||||
|
||||
useNewExport := writeNewExportFunc != nil
|
||||
|
||||
var old, new bytes.Buffer
|
||||
|
||||
typecheck.WriteExports(&old, !useNewExport)
|
||||
|
||||
if useNewExport {
|
||||
writeNewExportFunc(&new)
|
||||
}
|
||||
|
||||
oldLen := old.Len()
|
||||
newLen := new.Len()
|
||||
|
||||
if useNewExport {
|
||||
fmt.Fprintf(out, "\nnewexportsize %v\n", newLen)
|
||||
if base.Debug.Unified != 0 {
|
||||
data.WriteByte('u')
|
||||
writeUnifiedExport(&data)
|
||||
} else {
|
||||
typecheck.WriteExports(&data, true)
|
||||
}
|
||||
|
||||
// The linker also looks for the $$ marker - use char after $$ to distinguish format.
|
||||
out.WriteString("\n$$B\n") // indicate binary export format
|
||||
io.Copy(out, &old)
|
||||
io.Copy(out, &data)
|
||||
out.WriteString("\n$$\n")
|
||||
io.Copy(out, &new)
|
||||
|
||||
if base.Debug.Export != 0 {
|
||||
fmt.Printf("BenchmarkExportSize:%s 1 %d bytes\n", base.Ctxt.Pkgpath, oldLen)
|
||||
if useNewExport {
|
||||
fmt.Printf("BenchmarkNewExportSize:%s 1 %d bytes\n", base.Ctxt.Pkgpath, newLen)
|
||||
}
|
||||
fmt.Printf("BenchmarkExportSize:%s 1 %d bytes\n", base.Ctxt.Pkgpath, data.Len())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"internal/buildcfg"
|
||||
"internal/pkgbits"
|
||||
"os"
|
||||
pathpkg "path"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
|
@ -28,22 +28,6 @@ import (
|
|||
"cmd/internal/objabi"
|
||||
)
|
||||
|
||||
// haveLegacyImports records whether we've imported any packages
|
||||
// without a new export data section. This is useful for experimenting
|
||||
// with new export data format designs, when you need to support
|
||||
// existing tests that manually compile files with inconsistent
|
||||
// compiler flags.
|
||||
var haveLegacyImports = false
|
||||
|
||||
// newReadImportFunc is an extension hook for experimenting with new
|
||||
// export data formats. If a new export data payload was written out
|
||||
// for an imported package by overloading writeNewExportFunc, then
|
||||
// that payload will be mapped into memory and passed to
|
||||
// newReadImportFunc.
|
||||
var newReadImportFunc = func(data string, pkg1 *types.Pkg, env *types2.Context, packages map[string]*types2.Package) (pkg2 *types2.Package, err error) {
|
||||
panic("unexpected new export data payload")
|
||||
}
|
||||
|
||||
type gcimports struct {
|
||||
ctxt *types2.Context
|
||||
packages map[string]*types2.Package
|
||||
|
|
@ -220,7 +204,7 @@ func readImportFile(path string, target *ir.Package, env *types2.Context, packag
|
|||
}
|
||||
defer f.Close()
|
||||
|
||||
r, end, newsize, err := findExportData(f)
|
||||
r, end, err := findExportData(f)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
@ -229,41 +213,40 @@ func readImportFile(path string, target *ir.Package, env *types2.Context, packag
|
|||
fmt.Printf("importing %s (%s)\n", path, f.Name())
|
||||
}
|
||||
|
||||
if newsize != 0 {
|
||||
// We have unified IR data. Map it, and feed to the importers.
|
||||
end -= newsize
|
||||
var data string
|
||||
data, err = base.MapFile(r.File(), end, newsize)
|
||||
if err != nil {
|
||||
return
|
||||
c, err := r.ReadByte()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
pos := r.Offset()
|
||||
|
||||
// Map export data section into memory as a single large
|
||||
// string. This reduces heap fragmentation and allows returning
|
||||
// individual substrings very efficiently.
|
||||
var data string
|
||||
data, err = base.MapFile(r.File(), pos, end-pos)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch c {
|
||||
case 'u':
|
||||
if !buildcfg.Experiment.Unified {
|
||||
base.Fatalf("unexpected export data format")
|
||||
}
|
||||
|
||||
pkg2, err = newReadImportFunc(data, pkg1, env, packages)
|
||||
} else {
|
||||
// We only have old data. Oh well, fall back to the legacy importers.
|
||||
haveLegacyImports = true
|
||||
// TODO(mdempsky): This seems a bit clunky.
|
||||
data = strings.TrimSuffix(data, "\n$$\n")
|
||||
|
||||
var c byte
|
||||
switch c, err = r.ReadByte(); {
|
||||
case err != nil:
|
||||
return
|
||||
pr := pkgbits.NewPkgDecoder(pkg1.Path, data)
|
||||
|
||||
case c != 'i':
|
||||
// Indexed format is distinguished by an 'i' byte,
|
||||
// whereas previous export formats started with 'c', 'd', or 'v'.
|
||||
err = fmt.Errorf("unexpected package format byte: %v", c)
|
||||
return
|
||||
}
|
||||
// Read package descriptors for both types2 and compiler backend.
|
||||
readPackage(newPkgReader(pr), pkg1)
|
||||
pkg2 = importer.ReadPackage(env, packages, pr)
|
||||
|
||||
pos := r.Offset()
|
||||
|
||||
// Map string (and data) section into memory as a single large
|
||||
// string. This reduces heap fragmentation and allows
|
||||
// returning individual substrings very efficiently.
|
||||
var data string
|
||||
data, err = base.MapFile(r.File(), pos, end-pos)
|
||||
if err != nil {
|
||||
return
|
||||
case 'i':
|
||||
if buildcfg.Experiment.Unified {
|
||||
base.Fatalf("unexpected export data format")
|
||||
}
|
||||
|
||||
typecheck.ReadImports(pkg1, data)
|
||||
|
|
@ -274,6 +257,12 @@ func readImportFile(path string, target *ir.Package, env *types2.Context, packag
|
|||
return
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
// Indexed format is distinguished by an 'i' byte,
|
||||
// whereas previous export formats started with 'c', 'd', or 'v'.
|
||||
err = fmt.Errorf("unexpected package format byte: %v", c)
|
||||
return
|
||||
}
|
||||
|
||||
err = addFingerprint(path, f, end)
|
||||
|
|
@ -283,7 +272,7 @@ func readImportFile(path string, target *ir.Package, env *types2.Context, packag
|
|||
// findExportData returns a *bio.Reader positioned at the start of the
|
||||
// binary export data section, and a file offset for where to stop
|
||||
// reading.
|
||||
func findExportData(f *os.File) (r *bio.Reader, end, newsize int64, err error) {
|
||||
func findExportData(f *os.File) (r *bio.Reader, end int64, err error) {
|
||||
r = bio.NewReader(f)
|
||||
|
||||
// check object header
|
||||
|
|
@ -326,14 +315,6 @@ func findExportData(f *os.File) (r *bio.Reader, end, newsize int64, err error) {
|
|||
|
||||
// process header lines
|
||||
for !strings.HasPrefix(line, "$$") {
|
||||
if strings.HasPrefix(line, "newexportsize ") {
|
||||
fields := strings.Fields(line)
|
||||
newsize, err = strconv.ParseInt(fields[1], 10, 64)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
line, err = r.ReadString('\n')
|
||||
if err != nil {
|
||||
return
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import (
|
|||
func LoadPackage(filenames []string) {
|
||||
base.Timer.Start("fe", "parse")
|
||||
|
||||
mode := syntax.CheckBranches | syntax.AllowGenerics
|
||||
mode := syntax.CheckBranches
|
||||
|
||||
// Limit the number of simultaneously open files.
|
||||
sem := make(chan struct{}, runtime.GOMAXPROCS(0)+10)
|
||||
|
|
|
|||
|
|
@ -442,9 +442,21 @@ func (r *reader) doTyp() *types.Type {
|
|||
return r.structType()
|
||||
case pkgbits.TypeInterface:
|
||||
return r.interfaceType()
|
||||
case pkgbits.TypeUnion:
|
||||
return r.unionType()
|
||||
}
|
||||
}
|
||||
|
||||
func (r *reader) unionType() *types.Type {
|
||||
terms := make([]*types.Type, r.Len())
|
||||
tildes := make([]bool, len(terms))
|
||||
for i := range terms {
|
||||
tildes[i] = r.Bool()
|
||||
terms[i] = r.typ()
|
||||
}
|
||||
return types.NewUnion(terms, tildes)
|
||||
}
|
||||
|
||||
func (r *reader) interfaceType() *types.Type {
|
||||
tpkg := types.LocalPkg // TODO(mdempsky): Remove after iexport is gone.
|
||||
|
||||
|
|
@ -577,10 +589,6 @@ func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node
|
|||
if pri, ok := objReader[sym]; ok {
|
||||
return pri.pr.objIdx(pri.idx, nil, explicits)
|
||||
}
|
||||
if haveLegacyImports {
|
||||
assert(len(explicits) == 0)
|
||||
return typecheck.Resolve(ir.NewIdent(src.NoXPos, sym))
|
||||
}
|
||||
base.Fatalf("unresolved stub: %v", sym)
|
||||
}
|
||||
|
||||
|
|
@ -1960,12 +1968,6 @@ func InlineCall(call *ir.CallExpr, fn *ir.Func, inlIndex int) *ir.InlinedCallExp
|
|||
|
||||
pri, ok := bodyReader[fn]
|
||||
if !ok {
|
||||
// Assume it's an imported function or something that we don't
|
||||
// have access to in quirks mode.
|
||||
if haveLegacyImports {
|
||||
return nil
|
||||
}
|
||||
|
||||
base.FatalfAt(call.Pos(), "missing function body for call to %v", fn)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ import (
|
|||
"sort"
|
||||
|
||||
"cmd/compile/internal/base"
|
||||
"cmd/compile/internal/importer"
|
||||
"cmd/compile/internal/inline"
|
||||
"cmd/compile/internal/ir"
|
||||
"cmd/compile/internal/typecheck"
|
||||
|
|
@ -34,38 +33,38 @@ var localPkgReader *pkgReader
|
|||
//
|
||||
// The pipeline contains 2 steps:
|
||||
//
|
||||
// (1) Generate package export data "stub".
|
||||
// 1) Generate package export data "stub".
|
||||
//
|
||||
// (2) Generate package IR from package export data.
|
||||
// 2) Generate package IR from package export data.
|
||||
//
|
||||
// The package data "stub" at step (1) contains everything from the local package,
|
||||
// but nothing that have been imported. When we're actually writing out export data
|
||||
// to the output files (see writeNewExport function), we run the "linker", which does
|
||||
// a few things:
|
||||
//
|
||||
// + Updates compiler extensions data (e.g., inlining cost, escape analysis results).
|
||||
// + Updates compiler extensions data (e.g., inlining cost, escape analysis results).
|
||||
//
|
||||
// + Handles re-exporting any transitive dependencies.
|
||||
// + Handles re-exporting any transitive dependencies.
|
||||
//
|
||||
// + Prunes out any unnecessary details (e.g., non-inlineable functions, because any
|
||||
// downstream importers only care about inlinable functions).
|
||||
// + Prunes out any unnecessary details (e.g., non-inlineable functions, because any
|
||||
// downstream importers only care about inlinable functions).
|
||||
//
|
||||
// The source files are typechecked twice, once before writing export data
|
||||
// using types2 checker, once after read export data using gc/typecheck.
|
||||
// This duplication of work will go away once we always use types2 checker,
|
||||
// we can remove the gc/typecheck pass. The reason it is still here:
|
||||
//
|
||||
// + It reduces engineering costs in maintaining a fork of typecheck
|
||||
// (e.g., no need to backport fixes like CL 327651).
|
||||
// + It reduces engineering costs in maintaining a fork of typecheck
|
||||
// (e.g., no need to backport fixes like CL 327651).
|
||||
//
|
||||
// + It makes it easier to pass toolstash -cmp.
|
||||
// + It makes it easier to pass toolstash -cmp.
|
||||
//
|
||||
// + Historically, we would always re-run the typechecker after import, even though
|
||||
// we know the imported data is valid. It's not ideal, but also not causing any
|
||||
// problem either.
|
||||
// + Historically, we would always re-run the typechecker after import, even though
|
||||
// we know the imported data is valid. It's not ideal, but also not causing any
|
||||
// problem either.
|
||||
//
|
||||
// + There's still transformation that being done during gc/typecheck, like rewriting
|
||||
// multi-valued function call, or transform ir.OINDEX -> ir.OINDEXMAP.
|
||||
// + There's still transformation that being done during gc/typecheck, like rewriting
|
||||
// multi-valued function call, or transform ir.OINDEX -> ir.OINDEXMAP.
|
||||
//
|
||||
// Using syntax+types2 tree, which already has a complete representation of generics,
|
||||
// the unified IR has the full typed AST for doing introspection during step (1).
|
||||
|
|
@ -74,17 +73,6 @@ var localPkgReader *pkgReader
|
|||
func unified(noders []*noder) {
|
||||
inline.NewInline = InlineCall
|
||||
|
||||
writeNewExportFunc = writeNewExport
|
||||
|
||||
newReadImportFunc = func(data string, pkg1 *types.Pkg, ctxt *types2.Context, packages map[string]*types2.Package) (pkg2 *types2.Package, err error) {
|
||||
pr := pkgbits.NewPkgDecoder(pkg1.Path, data)
|
||||
|
||||
// Read package descriptors for both types2 and compiler backend.
|
||||
readPackage(newPkgReader(pr), pkg1)
|
||||
pkg2 = importer.ReadPackage(ctxt, packages, pr)
|
||||
return
|
||||
}
|
||||
|
||||
data := writePkgStub(noders)
|
||||
|
||||
// We already passed base.Flag.Lang to types2 to handle validating
|
||||
|
|
@ -266,7 +254,7 @@ func readPackage(pr *pkgReader, importpkg *types.Pkg) {
|
|||
}
|
||||
}
|
||||
|
||||
func writeNewExport(out io.Writer) {
|
||||
func writeUnifiedExport(out io.Writer) {
|
||||
l := linker{
|
||||
pw: pkgbits.NewPkgEncoder(base.Debug.SyncFrames),
|
||||
|
||||
|
|
@ -332,5 +320,5 @@ func writeNewExport(out io.Writer) {
|
|||
w.Flush()
|
||||
}
|
||||
|
||||
l.pw.DumpTo(out)
|
||||
base.Ctxt.Fingerprint = l.pw.DumpTo(out)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -733,6 +733,41 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
|||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = v.Reg()
|
||||
|
||||
case ssa.OpPPC64ADDC, ssa.OpPPC64ADDE, ssa.OpPPC64SUBC, ssa.OpPPC64SUBE:
|
||||
r := v.Reg0() // CA is the first, implied argument.
|
||||
r1 := v.Args[0].Reg()
|
||||
r2 := v.Args[1].Reg()
|
||||
p := s.Prog(v.Op.Asm())
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = r2
|
||||
p.Reg = r1
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = r
|
||||
|
||||
case ssa.OpPPC64ADDZEzero, ssa.OpPPC64SUBZEzero:
|
||||
p := s.Prog(v.Op.Asm())
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = ppc64.REG_R0
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = v.Reg()
|
||||
|
||||
case ssa.OpPPC64ADDCconst:
|
||||
p := s.Prog(v.Op.Asm())
|
||||
p.Reg = v.Args[0].Reg()
|
||||
p.From.Type = obj.TYPE_CONST
|
||||
p.From.Offset = v.AuxInt
|
||||
p.To.Type = obj.TYPE_REG
|
||||
// Output is a pair, the second is the CA, which is implied.
|
||||
p.To.Reg = v.Reg0()
|
||||
|
||||
case ssa.OpPPC64SUBCconst:
|
||||
p := s.Prog(v.Op.Asm())
|
||||
p.SetFrom3Const(v.AuxInt)
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = v.Args[0].Reg()
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = v.Reg0()
|
||||
|
||||
case ssa.OpPPC64SUBFCconst:
|
||||
p := s.Prog(v.Op.Asm())
|
||||
p.SetFrom3Const(v.AuxInt)
|
||||
|
|
|
|||
|
|
@ -667,10 +667,10 @@ var kinds = []int{
|
|||
// tflag is documented in reflect/type.go.
|
||||
//
|
||||
// tflag values must be kept in sync with copies in:
|
||||
// cmd/compile/internal/reflectdata/reflect.go
|
||||
// cmd/link/internal/ld/decodesym.go
|
||||
// reflect/type.go
|
||||
// runtime/type.go
|
||||
// - cmd/compile/internal/reflectdata/reflect.go
|
||||
// - cmd/link/internal/ld/decodesym.go
|
||||
// - reflect/type.go
|
||||
// - runtime/type.go
|
||||
const (
|
||||
tflagUncommon = 1 << 0
|
||||
tflagExtraStar = 1 << 1
|
||||
|
|
@ -1527,7 +1527,6 @@ func (a typesByString) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
|||
// use bitmaps for objects up to 64 kB in size.
|
||||
//
|
||||
// Also known to reflect/type.go.
|
||||
//
|
||||
const maxPtrmaskBytes = 2048
|
||||
|
||||
// GCSym returns a data symbol containing GC information for type t, along
|
||||
|
|
|
|||
|
|
@ -340,6 +340,22 @@ var combine = map[[2]Op]Op{
|
|||
[2]Op{OpAMD64DIVSDload, OpAMD64LEAQ1}: OpAMD64DIVSDloadidx1,
|
||||
[2]Op{OpAMD64DIVSDload, OpAMD64LEAQ8}: OpAMD64DIVSDloadidx8,
|
||||
|
||||
[2]Op{OpAMD64SHLXLload, OpAMD64ADDQ}: OpAMD64SHLXLloadidx1,
|
||||
[2]Op{OpAMD64SHLXQload, OpAMD64ADDQ}: OpAMD64SHLXQloadidx1,
|
||||
[2]Op{OpAMD64SHRXLload, OpAMD64ADDQ}: OpAMD64SHRXLloadidx1,
|
||||
[2]Op{OpAMD64SHRXQload, OpAMD64ADDQ}: OpAMD64SHRXQloadidx1,
|
||||
|
||||
[2]Op{OpAMD64SHLXLload, OpAMD64LEAQ1}: OpAMD64SHLXLloadidx1,
|
||||
[2]Op{OpAMD64SHLXLload, OpAMD64LEAQ4}: OpAMD64SHLXLloadidx4,
|
||||
[2]Op{OpAMD64SHLXLload, OpAMD64LEAQ8}: OpAMD64SHLXLloadidx8,
|
||||
[2]Op{OpAMD64SHLXQload, OpAMD64LEAQ1}: OpAMD64SHLXQloadidx1,
|
||||
[2]Op{OpAMD64SHLXQload, OpAMD64LEAQ8}: OpAMD64SHLXQloadidx8,
|
||||
[2]Op{OpAMD64SHRXLload, OpAMD64LEAQ1}: OpAMD64SHRXLloadidx1,
|
||||
[2]Op{OpAMD64SHRXLload, OpAMD64LEAQ4}: OpAMD64SHRXLloadidx4,
|
||||
[2]Op{OpAMD64SHRXLload, OpAMD64LEAQ8}: OpAMD64SHRXLloadidx8,
|
||||
[2]Op{OpAMD64SHRXQload, OpAMD64LEAQ1}: OpAMD64SHRXQloadidx1,
|
||||
[2]Op{OpAMD64SHRXQload, OpAMD64LEAQ8}: OpAMD64SHRXQloadidx8,
|
||||
|
||||
// 386
|
||||
[2]Op{Op386MOVBload, Op386ADDL}: Op386MOVBloadidx1,
|
||||
[2]Op{Op386MOVWload, Op386ADDL}: Op386MOVWloadidx1,
|
||||
|
|
|
|||
|
|
@ -76,10 +76,10 @@ type Block struct {
|
|||
// d.Preds = [?, {b,1}, ?]
|
||||
// These indexes allow us to edit the CFG in constant time.
|
||||
// In addition, it informs phi ops in degenerate cases like:
|
||||
// b:
|
||||
// if k then c else c
|
||||
// c:
|
||||
// v = Phi(x, y)
|
||||
// b:
|
||||
// if k then c else c
|
||||
// c:
|
||||
// v = Phi(x, y)
|
||||
// Then the indexes tell you whether x is chosen from
|
||||
// the if or else branch from b.
|
||||
// b.Succs = [{c,0},{c,1}]
|
||||
|
|
@ -105,6 +105,7 @@ func (e Edge) String() string {
|
|||
return fmt.Sprintf("{%v,%d}", e.b, e.i)
|
||||
}
|
||||
|
||||
// BlockKind is the kind of SSA block.
|
||||
// kind controls successors
|
||||
// ------------------------------------------
|
||||
// Exit [return mem] []
|
||||
|
|
|
|||
|
|
@ -11,11 +11,11 @@ import "cmd/internal/src"
|
|||
//
|
||||
// Search for basic blocks that look like
|
||||
//
|
||||
// bb0 bb0
|
||||
// | \ / \
|
||||
// | bb1 or bb1 bb2 <- trivial if/else blocks
|
||||
// | / \ /
|
||||
// bb2 bb3
|
||||
// bb0 bb0
|
||||
// | \ / \
|
||||
// | bb1 or bb1 bb2 <- trivial if/else blocks
|
||||
// | / \ /
|
||||
// bb2 bb3
|
||||
//
|
||||
// where the intermediate blocks are mostly empty (with no side-effects);
|
||||
// rewrite Phis in the postdominator as CondSelects.
|
||||
|
|
|
|||
|
|
@ -24,10 +24,10 @@ import (
|
|||
|
||||
// Compile is the main entry point for this package.
|
||||
// Compile modifies f so that on return:
|
||||
// · all Values in f map to 0 or 1 assembly instructions of the target architecture
|
||||
// · the order of f.Blocks is the order to emit the Blocks
|
||||
// · the order of b.Values is the order to emit the Values in each Block
|
||||
// · f has a non-nil regAlloc field
|
||||
// - all Values in f map to 0 or 1 assembly instructions of the target architecture
|
||||
// - the order of f.Blocks is the order to emit the Blocks
|
||||
// - the order of b.Values is the order to emit the Values in each Block
|
||||
// - f has a non-nil regAlloc field
|
||||
func Compile(f *Func) {
|
||||
// TODO: debugging - set flags to control verbosity of compiler,
|
||||
// which phases to dump IR before/after, etc.
|
||||
|
|
@ -250,8 +250,8 @@ var GenssaDump map[string]bool = make(map[string]bool) // names of functions to
|
|||
// version is used as a regular expression to match the phase name(s).
|
||||
//
|
||||
// Special cases that have turned out to be useful:
|
||||
// ssa/check/on enables checking after each phase
|
||||
// ssa/all/time enables time reporting for all phases
|
||||
// - ssa/check/on enables checking after each phase
|
||||
// - ssa/all/time enables time reporting for all phases
|
||||
//
|
||||
// See gc/lex.go for dissection of the option string.
|
||||
// Example uses:
|
||||
|
|
@ -259,7 +259,6 @@ var GenssaDump map[string]bool = make(map[string]bool) // names of functions to
|
|||
// GO_GCFLAGS=-d=ssa/generic_cse/time,ssa/generic_cse/stats,ssa/generic_cse/debug=3 ./make.bash
|
||||
//
|
||||
// BOOT_GO_GCFLAGS=-d='ssa/~^.*scc$/off' GO_GCFLAGS='-d=ssa/~^.*scc$/off' ./make.bash
|
||||
//
|
||||
func PhaseOption(phase, flag string, val int, valString string) string {
|
||||
switch phase {
|
||||
case "", "help":
|
||||
|
|
|
|||
|
|
@ -239,6 +239,7 @@ func NewConfig(arch string, types Types, ctxt *obj.Link, optimize, softfloat boo
|
|||
c.registers = registersPPC64[:]
|
||||
c.gpRegMask = gpRegMaskPPC64
|
||||
c.fpRegMask = fpRegMaskPPC64
|
||||
c.specialRegMask = specialRegMaskPPC64
|
||||
c.intParamRegs = paramIntRegPPC64
|
||||
c.floatParamRegs = paramFloatRegPPC64
|
||||
c.FPReg = framepointerRegPPC64
|
||||
|
|
|
|||
|
|
@ -428,7 +428,6 @@ func (sc *slotCanonicalizer) canonSlot(idx SlKeyIdx) LocalSlot {
|
|||
// This function examines the live OpArg{Int,Float}Reg values and
|
||||
// synthesizes new (dead) values for the non-live params or the
|
||||
// non-live pieces of partially live params.
|
||||
//
|
||||
func PopulateABIInRegArgOps(f *Func) {
|
||||
pri := f.ABISelf.ABIAnalyzeFuncType(f.Type.FuncType())
|
||||
|
||||
|
|
|
|||
|
|
@ -93,7 +93,6 @@ 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)
|
||||
|
||||
|
|
|
|||
|
|
@ -820,12 +820,12 @@ func (f *Func) invalidateCFG() {
|
|||
}
|
||||
|
||||
// DebugHashMatch reports whether environment variable evname
|
||||
// 1) is empty (this is a special more-quickly implemented case of 3)
|
||||
// 2) is "y" or "Y"
|
||||
// 3) is a suffix of the sha1 hash of name
|
||||
// 4) is a suffix of the environment variable
|
||||
// fmt.Sprintf("%s%d", evname, n)
|
||||
// provided that all such variables are nonempty for 0 <= i <= n
|
||||
// 1) is empty (this is a special more-quickly implemented case of 3)
|
||||
// 2) is "y" or "Y"
|
||||
// 3) is a suffix of the sha1 hash of name
|
||||
// 4) is a suffix of the environment variable
|
||||
// fmt.Sprintf("%s%d", evname, n)
|
||||
// provided that all such variables are nonempty for 0 <= i <= n
|
||||
// Otherwise it returns false.
|
||||
// When true is returned the message
|
||||
// "%s triggered %s\n", evname, name
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ package ssa
|
|||
|
||||
// TODO(matloob): Choose better names for Fun, Bloc, Goto, etc.
|
||||
// TODO(matloob): Write a parser for the Func disassembly. Maybe
|
||||
// the parser can be used instead of Fun.
|
||||
// the parser can be used instead of Fun.
|
||||
|
||||
import (
|
||||
"cmd/compile/internal/types"
|
||||
|
|
|
|||
|
|
@ -8,21 +8,21 @@ package ssa
|
|||
// of an If block can be derived from its predecessor If block, in
|
||||
// some such cases, we can redirect the predecessor If block to the
|
||||
// corresponding successor block directly. For example:
|
||||
// p:
|
||||
// v11 = Less64 <bool> v10 v8
|
||||
// If v11 goto b else u
|
||||
// b: <- p ...
|
||||
// v17 = Leq64 <bool> v10 v8
|
||||
// If v17 goto s else o
|
||||
// p:
|
||||
// v11 = Less64 <bool> v10 v8
|
||||
// If v11 goto b else u
|
||||
// b: <- p ...
|
||||
// v17 = Leq64 <bool> v10 v8
|
||||
// If v17 goto s else o
|
||||
// We can redirect p to s directly.
|
||||
//
|
||||
// The implementation here borrows the framework of the prove pass.
|
||||
// 1, Traverse all blocks of function f to find If blocks.
|
||||
// 2, For any If block b, traverse all its predecessors to find If blocks.
|
||||
// 3, For any If block predecessor p, update relationship p->b.
|
||||
// 4, Traverse all successors of b.
|
||||
// 5, For any successor s of b, try to update relationship b->s, if a
|
||||
// contradiction is found then redirect p to another successor of b.
|
||||
// 1, Traverse all blocks of function f to find If blocks.
|
||||
// 2, For any If block b, traverse all its predecessors to find If blocks.
|
||||
// 3, For any If block predecessor p, update relationship p->b.
|
||||
// 4, Traverse all successors of b.
|
||||
// 5, For any successor s of b, try to update relationship b->s, if a
|
||||
// contradiction is found then redirect p to another successor of b.
|
||||
func fuseBranchRedirect(f *Func) bool {
|
||||
ft := newFactsTable(f)
|
||||
ft.checkpoint()
|
||||
|
|
|
|||
|
|
@ -306,7 +306,7 @@ func init() {
|
|||
{name: "BSRL", argLength: 1, reg: gp11, asm: "BSRL", clobberFlags: true}, // arg0 # of high-order zeroes ; undef if zero
|
||||
{name: "BSRW", argLength: 1, reg: gp11, asm: "BSRW", clobberFlags: true}, // arg0 # of high-order zeroes ; undef if zero
|
||||
|
||||
{name: "BSWAPL", argLength: 1, reg: gp11, asm: "BSWAPL", resultInArg0: true, clobberFlags: true}, // arg0 swap bytes
|
||||
{name: "BSWAPL", argLength: 1, reg: gp11, asm: "BSWAPL", resultInArg0: true}, // arg0 swap bytes
|
||||
|
||||
{name: "SQRTSD", argLength: 1, reg: fp11, asm: "SQRTSD"}, // sqrt(arg0)
|
||||
{name: "SQRTSS", argLength: 1, reg: fp11, asm: "SQRTSS"}, // sqrt(arg0), float32
|
||||
|
|
|
|||
|
|
@ -98,10 +98,14 @@
|
|||
// However, for zero-extended values, we can cheat a bit, and calculate
|
||||
// BSR(x<<1 + 1), which is guaranteed to be non-zero, and which conveniently
|
||||
// places the index of the highest set bit where we want it.
|
||||
(BitLen64 <t> x) => (ADDQconst [1] (CMOVQEQ <t> (Select0 <t> (BSRQ x)) (MOVQconst <t> [-1]) (Select1 <types.TypeFlags> (BSRQ x))))
|
||||
(BitLen32 x) => (Select0 (BSRQ (LEAQ1 <typ.UInt64> [1] (MOVLQZX <typ.UInt64> x) (MOVLQZX <typ.UInt64> x))))
|
||||
(BitLen16 x) => (BSRL (LEAL1 <typ.UInt32> [1] (MOVWQZX <typ.UInt32> x) (MOVWQZX <typ.UInt32> x)))
|
||||
(BitLen8 x) => (BSRL (LEAL1 <typ.UInt32> [1] (MOVBQZX <typ.UInt32> x) (MOVBQZX <typ.UInt32> x)))
|
||||
// For GOAMD64>=3, BitLen can be calculated by OperandSize - LZCNT(x).
|
||||
(BitLen64 <t> x) && buildcfg.GOAMD64 < 3 => (ADDQconst [1] (CMOVQEQ <t> (Select0 <t> (BSRQ x)) (MOVQconst <t> [-1]) (Select1 <types.TypeFlags> (BSRQ x))))
|
||||
(BitLen32 x) && buildcfg.GOAMD64 < 3 => (Select0 (BSRQ (LEAQ1 <typ.UInt64> [1] (MOVLQZX <typ.UInt64> x) (MOVLQZX <typ.UInt64> x))))
|
||||
(BitLen16 x) && buildcfg.GOAMD64 < 3 => (BSRL (LEAL1 <typ.UInt32> [1] (MOVWQZX <typ.UInt32> x) (MOVWQZX <typ.UInt32> x)))
|
||||
(BitLen8 x) && buildcfg.GOAMD64 < 3 => (BSRL (LEAL1 <typ.UInt32> [1] (MOVBQZX <typ.UInt32> x) (MOVBQZX <typ.UInt32> x)))
|
||||
(BitLen64 <t> x) && buildcfg.GOAMD64 >= 3 => (NEGQ (ADDQconst <t> [-64] (LZCNTQ x)))
|
||||
// Use 64-bit version to allow const-fold remove unnecessary arithmetic.
|
||||
(BitLen(32|16|8) <t> x) && buildcfg.GOAMD64 >= 3 => (NEGQ (ADDQconst <t> [-32] (LZCNTL x)))
|
||||
|
||||
(Bswap(64|32) ...) => (BSWAP(Q|L) ...)
|
||||
|
||||
|
|
@ -2225,6 +2229,8 @@
|
|||
(BSWAP(Q|L) x:(MOV(Q|L)load [i] {s} p mem)) && x.Uses == 1 && buildcfg.GOAMD64 >= 3 => (MOVBE(Q|L)load [i] {s} p mem)
|
||||
(BSWAP(Q|L) (MOVBE(Q|L)load [i] {s} p m)) => (MOV(Q|L)load [i] {s} p m)
|
||||
(MOVBE(Q|L)store [i] {s} p (BSWAP(Q|L) x) m) => (MOV(Q|L)store [i] {s} p x m)
|
||||
(MOVWstore [i] {s} p x:(ROLWconst [8] w) mem) && x.Uses == 1 && buildcfg.GOAMD64 >= 3 => (MOVBEWstore [i] {s} p w mem)
|
||||
(MOVBEWstore [i] {s} p x:(ROLWconst [8] w) mem) && x.Uses == 1 => (MOVWstore [i] {s} p w mem)
|
||||
|
||||
(ORQ x0:(MOVBELload [i0] {s} p mem)
|
||||
sh:(SHLQconst [32] x1:(MOVBELload [i1] {s} p mem)))
|
||||
|
|
@ -2245,3 +2251,6 @@
|
|||
&& mergePoint(b,x0,x1) != nil
|
||||
&& clobber(x0, x1, sh)
|
||||
=> @mergePoint(b,x0,x1) (MOVBEQload [i] {s} p1 mem)
|
||||
|
||||
(SHL(Q|L) l:(MOV(Q|L)load [off] {sym} ptr mem) x) && buildcfg.GOAMD64 >= 3 && canMergeLoad(v, l) && clobber(l) => (SHLX(Q|L)load [off] {sym} ptr x mem)
|
||||
(SHR(Q|L) l:(MOV(Q|L)load [off] {sym} ptr mem) x) && buildcfg.GOAMD64 >= 3 && canMergeLoad(v, l) && clobber(l) => (SHRX(Q|L)load [off] {sym} ptr x mem)
|
||||
|
|
|
|||
|
|
@ -141,11 +141,13 @@ func init() {
|
|||
readflags = regInfo{inputs: nil, outputs: gponly}
|
||||
flagsgpax = regInfo{inputs: nil, clobbers: ax, outputs: []regMask{gp &^ ax}}
|
||||
|
||||
gpload = regInfo{inputs: []regMask{gpspsbg, 0}, outputs: gponly}
|
||||
gp21load = regInfo{inputs: []regMask{gp, gpspsbg, 0}, outputs: gponly}
|
||||
gploadidx = regInfo{inputs: []regMask{gpspsbg, gpsp, 0}, outputs: gponly}
|
||||
gp21loadidx = regInfo{inputs: []regMask{gp, gpspsbg, gpsp, 0}, outputs: gponly}
|
||||
gp21pax = regInfo{inputs: []regMask{gp &^ ax, gp}, outputs: []regMask{gp &^ ax}, clobbers: ax}
|
||||
gpload = regInfo{inputs: []regMask{gpspsbg, 0}, outputs: gponly}
|
||||
gp21load = regInfo{inputs: []regMask{gp, gpspsbg, 0}, outputs: gponly}
|
||||
gploadidx = regInfo{inputs: []regMask{gpspsbg, gpsp, 0}, outputs: gponly}
|
||||
gp21loadidx = regInfo{inputs: []regMask{gp, gpspsbg, gpsp, 0}, outputs: gponly}
|
||||
gp21pax = regInfo{inputs: []regMask{gp &^ ax, gp}, outputs: []regMask{gp &^ ax}, clobbers: ax}
|
||||
gp21shxload = regInfo{inputs: []regMask{gpspsbg, gp, 0}, outputs: gponly}
|
||||
gp21shxloadidx = regInfo{inputs: []regMask{gpspsbg, gpsp, gp, 0}, outputs: gponly}
|
||||
|
||||
gpstore = regInfo{inputs: []regMask{gpspsbg, gpsp, 0}}
|
||||
gpstoreconst = regInfo{inputs: []regMask{gpspsbg, 0}}
|
||||
|
|
@ -577,8 +579,8 @@ func init() {
|
|||
{name: "CMOVWGTF", argLength: 3, reg: gp21, asm: "CMOVWHI", resultInArg0: true},
|
||||
{name: "CMOVWGEF", argLength: 3, reg: gp21, asm: "CMOVWCC", resultInArg0: true},
|
||||
|
||||
{name: "BSWAPQ", argLength: 1, reg: gp11, asm: "BSWAPQ", resultInArg0: true, clobberFlags: true}, // arg0 swap bytes
|
||||
{name: "BSWAPL", argLength: 1, reg: gp11, asm: "BSWAPL", resultInArg0: true, clobberFlags: true}, // arg0 swap bytes
|
||||
{name: "BSWAPQ", argLength: 1, reg: gp11, asm: "BSWAPQ", resultInArg0: true}, // arg0 swap bytes
|
||||
{name: "BSWAPL", argLength: 1, reg: gp11, asm: "BSWAPL", resultInArg0: true}, // arg0 swap bytes
|
||||
|
||||
// POPCNT instructions aren't guaranteed to be on the target platform (they are SSE4).
|
||||
// Any use must be preceded by a successful check of runtime.x86HasPOPCNT.
|
||||
|
|
@ -923,11 +925,35 @@ func init() {
|
|||
{name: "TZCNTQ", argLength: 1, reg: gp11, asm: "TZCNTQ", clobberFlags: true},
|
||||
{name: "TZCNTL", argLength: 1, reg: gp11, asm: "TZCNTL", clobberFlags: true},
|
||||
|
||||
// CPUID feature: LZCNT.
|
||||
// count the number of leading zero bits.
|
||||
{name: "LZCNTQ", argLength: 1, reg: gp11, asm: "LZCNTQ", typ: "UInt64", clobberFlags: true},
|
||||
{name: "LZCNTL", argLength: 1, reg: gp11, asm: "LZCNTL", typ: "UInt32", clobberFlags: true},
|
||||
|
||||
// CPUID feature: MOVBE
|
||||
// MOVBEWload does not satisfy zero extended, so only use MOVBEWstore
|
||||
{name: "MOVBEWstore", argLength: 3, reg: gpstore, asm: "MOVBEW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // swap and store 2 bytes in arg1 to arg0+auxint+aux. arg2=mem
|
||||
{name: "MOVBELload", argLength: 2, reg: gpload, asm: "MOVBEL", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read"}, // load and swap 4 bytes from arg0+auxint+aux. arg1=mem. Zero extend.
|
||||
{name: "MOVBELstore", argLength: 3, reg: gpstore, asm: "MOVBEL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // swap and store 4 bytes in arg1 to arg0+auxint+aux. arg2=mem
|
||||
{name: "MOVBEQload", argLength: 2, reg: gpload, asm: "MOVBEQ", aux: "SymOff", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read"}, // load and swap 8 bytes from arg0+auxint+aux. arg1=mem
|
||||
{name: "MOVBEQstore", argLength: 3, reg: gpstore, asm: "MOVBEQ", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // swap and store 8 bytes in arg1 to arg0+auxint+aux. arg2=mem
|
||||
|
||||
// CPUID feature: BMI2.
|
||||
{name: "SHLXLload", argLength: 3, reg: gp21shxload, asm: "SHLXL", aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read"}, // *(arg0+auxint+aux) << arg1, arg2=mem, shift amount is mod 32
|
||||
{name: "SHLXQload", argLength: 3, reg: gp21shxload, asm: "SHLXQ", aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read"}, // *(arg0+auxint+aux) << arg1, arg2=mem, shift amount is mod 64
|
||||
{name: "SHRXLload", argLength: 3, reg: gp21shxload, asm: "SHRXL", aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read"}, // unsigned *(arg0+auxint+aux) >> arg1, arg2=mem, shift amount is mod 32
|
||||
{name: "SHRXQload", argLength: 3, reg: gp21shxload, asm: "SHRXQ", aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read"}, // unsigned *(arg0+auxint+aux) >> arg1, arg2=mem, shift amount is mod 64
|
||||
|
||||
{name: "SHLXLloadidx1", argLength: 4, reg: gp21shxloadidx, asm: "SHLXL", scale: 1, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read"}, // *(arg0+1*arg1+auxint+aux) << arg2, arg3=mem, shift amount is mod 32
|
||||
{name: "SHLXLloadidx4", argLength: 4, reg: gp21shxloadidx, asm: "SHLXL", scale: 4, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read"}, // *(arg0+4*arg1+auxint+aux) << arg2, arg3=mem, shift amount is mod 32
|
||||
{name: "SHLXLloadidx8", argLength: 4, reg: gp21shxloadidx, asm: "SHLXL", scale: 8, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read"}, // *(arg0+8*arg1+auxint+aux) << arg2, arg3=mem, shift amount is mod 32
|
||||
{name: "SHLXQloadidx1", argLength: 4, reg: gp21shxloadidx, asm: "SHLXQ", scale: 1, aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read"}, // *(arg0+1*arg1+auxint+aux) << arg2, arg3=mem, shift amount is mod 64
|
||||
{name: "SHLXQloadidx8", argLength: 4, reg: gp21shxloadidx, asm: "SHLXQ", scale: 8, aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read"}, // *(arg0+8*arg1+auxint+aux) << arg2, arg3=mem, shift amount is mod 64
|
||||
{name: "SHRXLloadidx1", argLength: 4, reg: gp21shxloadidx, asm: "SHRXL", scale: 1, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read"}, // unsigned *(arg0+1*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 32
|
||||
{name: "SHRXLloadidx4", argLength: 4, reg: gp21shxloadidx, asm: "SHRXL", scale: 4, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read"}, // unsigned *(arg0+4*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 32
|
||||
{name: "SHRXLloadidx8", argLength: 4, reg: gp21shxloadidx, asm: "SHRXL", scale: 8, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read"}, // unsigned *(arg0+8*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 32
|
||||
{name: "SHRXQloadidx1", argLength: 4, reg: gp21shxloadidx, asm: "SHRXQ", scale: 1, aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read"}, // unsigned *(arg0+1*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 64
|
||||
{name: "SHRXQloadidx8", argLength: 4, reg: gp21shxloadidx, asm: "SHRXQ", scale: 8, aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read"}, // unsigned *(arg0+8*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 64
|
||||
}
|
||||
|
||||
var AMD64blocks = []blockData{
|
||||
|
|
|
|||
|
|
@ -98,7 +98,6 @@ var regNamesPPC64 = []string{
|
|||
// "CR7",
|
||||
|
||||
// "CR",
|
||||
// "XER",
|
||||
// "LR",
|
||||
// "CTR",
|
||||
}
|
||||
|
|
@ -125,11 +124,12 @@ func init() {
|
|||
}
|
||||
|
||||
var (
|
||||
gp = buildReg("R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29")
|
||||
fp = buildReg("F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30")
|
||||
sp = buildReg("SP")
|
||||
sb = buildReg("SB")
|
||||
gr = buildReg("g")
|
||||
gp = buildReg("R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29")
|
||||
fp = buildReg("F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30")
|
||||
sp = buildReg("SP")
|
||||
sb = buildReg("SB")
|
||||
gr = buildReg("g")
|
||||
xer = buildReg("XER")
|
||||
// cr = buildReg("CR")
|
||||
// ctr = buildReg("CTR")
|
||||
// lr = buildReg("LR")
|
||||
|
|
@ -139,8 +139,14 @@ func init() {
|
|||
// tls = buildReg("R13")
|
||||
gp01 = regInfo{inputs: nil, outputs: []regMask{gp}}
|
||||
gp11 = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp}}
|
||||
xergp = regInfo{inputs: []regMask{xer}, outputs: []regMask{gp}, clobbers: xer}
|
||||
gp11cxer = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp}, clobbers: xer}
|
||||
gp11xer = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp, xer}}
|
||||
gp21 = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}, outputs: []regMask{gp}}
|
||||
gp21a0 = regInfo{inputs: []regMask{gp, gp | sp | sb}, outputs: []regMask{gp}}
|
||||
gp21cxer = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}, outputs: []regMask{gp}, clobbers: xer}
|
||||
gp21xer = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}, outputs: []regMask{gp, xer}, clobbers: xer}
|
||||
gp2xer1xer = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb, xer}, outputs: []regMask{gp, xer}, clobbers: xer}
|
||||
gp31 = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb, gp | sp | sb}, outputs: []regMask{gp}}
|
||||
gp22 = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}, outputs: []regMask{gp, gp}}
|
||||
gp32 = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb, gp | sp | sb}, outputs: []regMask{gp, gp}}
|
||||
|
|
@ -168,21 +174,21 @@ func init() {
|
|||
fploadidx = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}, outputs: []regMask{fp}}
|
||||
fpstore = regInfo{inputs: []regMask{gp | sp | sb, fp}}
|
||||
fpstoreidx = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb, fp}}
|
||||
callerSave = regMask(gp | fp | gr)
|
||||
callerSave = regMask(gp | fp | gr | xer)
|
||||
r3 = buildReg("R3")
|
||||
r4 = buildReg("R4")
|
||||
r5 = buildReg("R5")
|
||||
r6 = buildReg("R6")
|
||||
)
|
||||
ops := []opData{
|
||||
{name: "ADD", argLength: 2, reg: gp21, asm: "ADD", commutative: true}, // arg0 + arg1
|
||||
{name: "ADDconst", argLength: 1, reg: gp11, asm: "ADD", aux: "Int64"}, // arg0 + auxInt
|
||||
{name: "FADD", argLength: 2, reg: fp21, asm: "FADD", commutative: true}, // arg0+arg1
|
||||
{name: "FADDS", argLength: 2, reg: fp21, asm: "FADDS", commutative: true}, // arg0+arg1
|
||||
{name: "SUB", argLength: 2, reg: gp21, asm: "SUB"}, // arg0-arg1
|
||||
{name: "SUBFCconst", argLength: 1, reg: gp11, asm: "SUBC", aux: "Int64"}, // auxInt - arg0 (with carry)
|
||||
{name: "FSUB", argLength: 2, reg: fp21, asm: "FSUB"}, // arg0-arg1
|
||||
{name: "FSUBS", argLength: 2, reg: fp21, asm: "FSUBS"}, // arg0-arg1
|
||||
{name: "ADD", argLength: 2, reg: gp21, asm: "ADD", commutative: true}, // arg0 + arg1
|
||||
{name: "ADDconst", argLength: 1, reg: gp11, asm: "ADD", aux: "Int64"}, // arg0 + auxInt
|
||||
{name: "FADD", argLength: 2, reg: fp21, asm: "FADD", commutative: true}, // arg0+arg1
|
||||
{name: "FADDS", argLength: 2, reg: fp21, asm: "FADDS", commutative: true}, // arg0+arg1
|
||||
{name: "SUB", argLength: 2, reg: gp21, asm: "SUB"}, // arg0-arg1
|
||||
{name: "SUBFCconst", argLength: 1, reg: gp11cxer, asm: "SUBC", aux: "Int64"}, // auxInt - arg0 (carry is ignored)
|
||||
{name: "FSUB", argLength: 2, reg: fp21, asm: "FSUB"}, // arg0-arg1
|
||||
{name: "FSUBS", argLength: 2, reg: fp21, asm: "FSUBS"}, // arg0-arg1
|
||||
|
||||
{name: "MULLD", argLength: 2, reg: gp21, asm: "MULLD", typ: "Int64", commutative: true}, // arg0*arg1 (signed 64-bit)
|
||||
{name: "MULLW", argLength: 2, reg: gp21, asm: "MULLW", typ: "Int32", commutative: true}, // arg0*arg1 (signed 32-bit)
|
||||
|
|
@ -204,12 +210,12 @@ func init() {
|
|||
{name: "FMSUB", argLength: 3, reg: fp31, asm: "FMSUB"}, // arg0*arg1 - arg2
|
||||
{name: "FMSUBS", argLength: 3, reg: fp31, asm: "FMSUBS"}, // arg0*arg1 - arg2
|
||||
|
||||
{name: "SRAD", argLength: 2, reg: gp21, asm: "SRAD"}, // signed arg0 >> (arg1&127), 64 bit width (note: 127, not 63!)
|
||||
{name: "SRAW", argLength: 2, reg: gp21, asm: "SRAW"}, // signed arg0 >> (arg1&63), 32 bit width
|
||||
{name: "SRD", argLength: 2, reg: gp21, asm: "SRD"}, // unsigned arg0 >> (arg1&127), 64 bit width
|
||||
{name: "SRW", argLength: 2, reg: gp21, asm: "SRW"}, // unsigned arg0 >> (arg1&63), 32 bit width
|
||||
{name: "SLD", argLength: 2, reg: gp21, asm: "SLD"}, // arg0 << (arg1&127), 64 bit width
|
||||
{name: "SLW", argLength: 2, reg: gp21, asm: "SLW"}, // arg0 << (arg1&63), 32 bit width
|
||||
{name: "SRAD", argLength: 2, reg: gp21cxer, asm: "SRAD"}, // signed arg0 >> (arg1&127), 64 bit width (note: 127, not 63!)
|
||||
{name: "SRAW", argLength: 2, reg: gp21cxer, asm: "SRAW"}, // signed arg0 >> (arg1&63), 32 bit width
|
||||
{name: "SRD", argLength: 2, reg: gp21, asm: "SRD"}, // unsigned arg0 >> (arg1&127), 64 bit width
|
||||
{name: "SRW", argLength: 2, reg: gp21, asm: "SRW"}, // unsigned arg0 >> (arg1&63), 32 bit width
|
||||
{name: "SLD", argLength: 2, reg: gp21, asm: "SLD"}, // arg0 << (arg1&127), 64 bit width
|
||||
{name: "SLW", argLength: 2, reg: gp21, asm: "SLW"}, // arg0 << (arg1&63), 32 bit width
|
||||
|
||||
{name: "ROTL", argLength: 2, reg: gp21, asm: "ROTL"}, // arg0 rotate left by arg1 mod 64
|
||||
{name: "ROTLW", argLength: 2, reg: gp21, asm: "ROTLW"}, // uint32(arg0) rotate left by arg1 mod 32
|
||||
|
|
@ -221,12 +227,22 @@ func init() {
|
|||
|
||||
{name: "LoweredAdd64Carry", argLength: 3, reg: gp32, resultNotInArgs: true}, // arg0 + arg1 + carry, returns (sum, carry)
|
||||
|
||||
{name: "SRADconst", argLength: 1, reg: gp11, asm: "SRAD", aux: "Int64"}, // signed arg0 >> auxInt, 0 <= auxInt < 64, 64 bit width
|
||||
{name: "SRAWconst", argLength: 1, reg: gp11, asm: "SRAW", aux: "Int64"}, // signed arg0 >> auxInt, 0 <= auxInt < 32, 32 bit width
|
||||
{name: "SRDconst", argLength: 1, reg: gp11, asm: "SRD", aux: "Int64"}, // unsigned arg0 >> auxInt, 0 <= auxInt < 64, 64 bit width
|
||||
{name: "SRWconst", argLength: 1, reg: gp11, asm: "SRW", aux: "Int64"}, // unsigned arg0 >> auxInt, 0 <= auxInt < 32, 32 bit width
|
||||
{name: "SLDconst", argLength: 1, reg: gp11, asm: "SLD", aux: "Int64"}, // arg0 << auxInt, 0 <= auxInt < 64, 64 bit width
|
||||
{name: "SLWconst", argLength: 1, reg: gp11, asm: "SLW", aux: "Int64"}, // arg0 << auxInt, 0 <= auxInt < 32, 32 bit width
|
||||
// Operations which consume or generate the CA (xer)
|
||||
{name: "ADDC", argLength: 2, reg: gp21xer, asm: "ADDC", commutative: true, typ: "(UInt64, UInt64)"}, // arg0 + arg1 -> out, CA
|
||||
{name: "SUBC", argLength: 2, reg: gp21xer, asm: "SUBC", typ: "(UInt64, UInt64)"}, // arg0 - arg1 -> out, CA
|
||||
{name: "ADDCconst", argLength: 1, reg: gp11xer, asm: "ADDC", typ: "(UInt64, UInt64)", aux: "Int64"}, // arg0 + imm16 -> out, CA
|
||||
{name: "SUBCconst", argLength: 1, reg: gp11xer, asm: "SUBC", typ: "(UInt64, UInt64)", aux: "Int64"}, // imm16 - arg0 -> out, CA
|
||||
{name: "ADDE", argLength: 3, reg: gp2xer1xer, asm: "ADDE", typ: "(UInt64, UInt64)", commutative: true}, // arg0 + arg1 + CA (arg2) -> out, CA
|
||||
{name: "SUBE", argLength: 3, reg: gp2xer1xer, asm: "SUBE", typ: "(UInt64, UInt64)"}, // arg0 - arg1 - CA (arg2) -> out, CA
|
||||
{name: "ADDZEzero", argLength: 1, reg: xergp, asm: "ADDZE", typ: "UInt64"}, // CA (arg0) + $0 -> out
|
||||
{name: "SUBZEzero", argLength: 1, reg: xergp, asm: "SUBZE", typ: "UInt64"}, // $0 - CA (arg0) -> out
|
||||
|
||||
{name: "SRADconst", argLength: 1, reg: gp11cxer, asm: "SRAD", aux: "Int64"}, // signed arg0 >> auxInt, 0 <= auxInt < 64, 64 bit width
|
||||
{name: "SRAWconst", argLength: 1, reg: gp11cxer, asm: "SRAW", aux: "Int64"}, // signed arg0 >> auxInt, 0 <= auxInt < 32, 32 bit width
|
||||
{name: "SRDconst", argLength: 1, reg: gp11, asm: "SRD", aux: "Int64"}, // unsigned arg0 >> auxInt, 0 <= auxInt < 64, 64 bit width
|
||||
{name: "SRWconst", argLength: 1, reg: gp11, asm: "SRW", aux: "Int64"}, // unsigned arg0 >> auxInt, 0 <= auxInt < 32, 32 bit width
|
||||
{name: "SLDconst", argLength: 1, reg: gp11, asm: "SLD", aux: "Int64"}, // arg0 << auxInt, 0 <= auxInt < 64, 64 bit width
|
||||
{name: "SLWconst", argLength: 1, reg: gp11, asm: "SLW", aux: "Int64"}, // arg0 << auxInt, 0 <= auxInt < 32, 32 bit width
|
||||
|
||||
{name: "ROTLconst", argLength: 1, reg: gp11, asm: "ROTL", aux: "Int64"}, // arg0 rotate left by auxInt bits
|
||||
{name: "ROTLWconst", argLength: 1, reg: gp11, asm: "ROTLW", aux: "Int64"}, // uint32(arg0) rotate left by auxInt bits
|
||||
|
|
@ -722,6 +738,7 @@ func init() {
|
|||
ParamFloatRegNames: "F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12",
|
||||
gpregmask: gp,
|
||||
fpregmask: fp,
|
||||
specialregmask: xer,
|
||||
framepointerreg: -1,
|
||||
linkreg: -1, // not used
|
||||
})
|
||||
|
|
|
|||
|
|
@ -46,19 +46,19 @@ func (r *Register) GCNum() int16 {
|
|||
// variable that has been decomposed into multiple stack slots.
|
||||
// As an example, a string could have the following configurations:
|
||||
//
|
||||
// stack layout LocalSlots
|
||||
// stack layout LocalSlots
|
||||
//
|
||||
// Optimizations are disabled. s is on the stack and represented in its entirety.
|
||||
// [ ------- s string ---- ] { N: s, Type: string, Off: 0 }
|
||||
// Optimizations are disabled. s is on the stack and represented in its entirety.
|
||||
// [ ------- s string ---- ] { N: s, Type: string, Off: 0 }
|
||||
//
|
||||
// s was not decomposed, but the SSA operates on its parts individually, so
|
||||
// there is a LocalSlot for each of its fields that points into the single stack slot.
|
||||
// [ ------- s string ---- ] { N: s, Type: *uint8, Off: 0 }, {N: s, Type: int, Off: 8}
|
||||
// s was not decomposed, but the SSA operates on its parts individually, so
|
||||
// there is a LocalSlot for each of its fields that points into the single stack slot.
|
||||
// [ ------- s string ---- ] { N: s, Type: *uint8, Off: 0 }, {N: s, Type: int, Off: 8}
|
||||
//
|
||||
// s was decomposed. Each of its fields is in its own stack slot and has its own LocalSLot.
|
||||
// [ ptr *uint8 ] [ len int] { N: ptr, Type: *uint8, Off: 0, SplitOf: parent, SplitOffset: 0},
|
||||
// { N: len, Type: int, Off: 0, SplitOf: parent, SplitOffset: 8}
|
||||
// parent = &{N: s, Type: string}
|
||||
// s was decomposed. Each of its fields is in its own stack slot and has its own LocalSLot.
|
||||
// [ ptr *uint8 ] [ len int] { N: ptr, Type: *uint8, Off: 0, SplitOf: parent, SplitOffset: 0},
|
||||
// { N: len, Type: int, Off: 0, SplitOf: parent, SplitOffset: 8}
|
||||
// parent = &{N: s, Type: string}
|
||||
type LocalSlot struct {
|
||||
N *ir.Name // an ONAME *ir.Name representing a stack location.
|
||||
Type *types.Type // type of slot
|
||||
|
|
|
|||
|
|
@ -66,18 +66,18 @@ func parseIndVar(ind *Value) (min, inc, nxt *Value) {
|
|||
//
|
||||
// Look for variables and blocks that satisfy the following
|
||||
//
|
||||
// loop:
|
||||
// ind = (Phi min nxt),
|
||||
// if ind < max
|
||||
// then goto enter_loop
|
||||
// else goto exit_loop
|
||||
// loop:
|
||||
// ind = (Phi min nxt),
|
||||
// if ind < max
|
||||
// then goto enter_loop
|
||||
// else goto exit_loop
|
||||
//
|
||||
// enter_loop:
|
||||
// do something
|
||||
// nxt = inc + ind
|
||||
// goto loop
|
||||
// enter_loop:
|
||||
// do something
|
||||
// nxt = inc + ind
|
||||
// goto loop
|
||||
//
|
||||
// exit_loop:
|
||||
// exit_loop:
|
||||
//
|
||||
//
|
||||
// TODO: handle 32 bit operations
|
||||
|
|
|
|||
|
|
@ -1043,10 +1043,27 @@ const (
|
|||
OpAMD64BLSRL
|
||||
OpAMD64TZCNTQ
|
||||
OpAMD64TZCNTL
|
||||
OpAMD64LZCNTQ
|
||||
OpAMD64LZCNTL
|
||||
OpAMD64MOVBEWstore
|
||||
OpAMD64MOVBELload
|
||||
OpAMD64MOVBELstore
|
||||
OpAMD64MOVBEQload
|
||||
OpAMD64MOVBEQstore
|
||||
OpAMD64SHLXLload
|
||||
OpAMD64SHLXQload
|
||||
OpAMD64SHRXLload
|
||||
OpAMD64SHRXQload
|
||||
OpAMD64SHLXLloadidx1
|
||||
OpAMD64SHLXLloadidx4
|
||||
OpAMD64SHLXLloadidx8
|
||||
OpAMD64SHLXQloadidx1
|
||||
OpAMD64SHLXQloadidx8
|
||||
OpAMD64SHRXLloadidx1
|
||||
OpAMD64SHRXLloadidx4
|
||||
OpAMD64SHRXLloadidx8
|
||||
OpAMD64SHRXQloadidx1
|
||||
OpAMD64SHRXQloadidx8
|
||||
|
||||
OpARMADD
|
||||
OpARMADDconst
|
||||
|
|
@ -1911,6 +1928,14 @@ const (
|
|||
OpPPC64CLRLSLWI
|
||||
OpPPC64CLRLSLDI
|
||||
OpPPC64LoweredAdd64Carry
|
||||
OpPPC64ADDC
|
||||
OpPPC64SUBC
|
||||
OpPPC64ADDCconst
|
||||
OpPPC64SUBCconst
|
||||
OpPPC64ADDE
|
||||
OpPPC64SUBE
|
||||
OpPPC64ADDZEzero
|
||||
OpPPC64SUBZEzero
|
||||
OpPPC64SRADconst
|
||||
OpPPC64SRAWconst
|
||||
OpPPC64SRDconst
|
||||
|
|
@ -4807,7 +4832,6 @@ var opcodeTable = [...]opInfo{
|
|||
name: "BSWAPL",
|
||||
argLen: 1,
|
||||
resultInArg0: true,
|
||||
clobberFlags: true,
|
||||
asm: x86.ABSWAPL,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
|
|
@ -11498,7 +11522,6 @@ var opcodeTable = [...]opInfo{
|
|||
name: "BSWAPQ",
|
||||
argLen: 1,
|
||||
resultInArg0: true,
|
||||
clobberFlags: true,
|
||||
asm: x86.ABSWAPQ,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
|
|
@ -11513,7 +11536,6 @@ var opcodeTable = [...]opInfo{
|
|||
name: "BSWAPL",
|
||||
argLen: 1,
|
||||
resultInArg0: true,
|
||||
clobberFlags: true,
|
||||
asm: x86.ABSWAPL,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
|
|
@ -13786,6 +13808,48 @@ var opcodeTable = [...]opInfo{
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "LZCNTQ",
|
||||
argLen: 1,
|
||||
clobberFlags: true,
|
||||
asm: x86.ALZCNTQ,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
},
|
||||
outputs: []outputInfo{
|
||||
{0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "LZCNTL",
|
||||
argLen: 1,
|
||||
clobberFlags: true,
|
||||
asm: x86.ALZCNTL,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
},
|
||||
outputs: []outputInfo{
|
||||
{0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "MOVBEWstore",
|
||||
auxType: auxSymOff,
|
||||
argLen: 3,
|
||||
faultOnNilArg0: true,
|
||||
symEffect: SymWrite,
|
||||
asm: x86.AMOVBEW,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{1, 49151}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "MOVBELload",
|
||||
auxType: auxSymOff,
|
||||
|
|
@ -13846,6 +13910,264 @@ var opcodeTable = [...]opInfo{
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SHLXLload",
|
||||
auxType: auxSymOff,
|
||||
argLen: 3,
|
||||
faultOnNilArg0: true,
|
||||
symEffect: SymRead,
|
||||
asm: x86.ASHLXL,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{1, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB
|
||||
},
|
||||
outputs: []outputInfo{
|
||||
{0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SHLXQload",
|
||||
auxType: auxSymOff,
|
||||
argLen: 3,
|
||||
faultOnNilArg0: true,
|
||||
symEffect: SymRead,
|
||||
asm: x86.ASHLXQ,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{1, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB
|
||||
},
|
||||
outputs: []outputInfo{
|
||||
{0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SHRXLload",
|
||||
auxType: auxSymOff,
|
||||
argLen: 3,
|
||||
faultOnNilArg0: true,
|
||||
symEffect: SymRead,
|
||||
asm: x86.ASHRXL,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{1, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB
|
||||
},
|
||||
outputs: []outputInfo{
|
||||
{0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SHRXQload",
|
||||
auxType: auxSymOff,
|
||||
argLen: 3,
|
||||
faultOnNilArg0: true,
|
||||
symEffect: SymRead,
|
||||
asm: x86.ASHRXQ,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{1, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB
|
||||
},
|
||||
outputs: []outputInfo{
|
||||
{0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SHLXLloadidx1",
|
||||
auxType: auxSymOff,
|
||||
argLen: 4,
|
||||
faultOnNilArg0: true,
|
||||
symEffect: SymRead,
|
||||
asm: x86.ASHLXL,
|
||||
scale: 1,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{2, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
{1, 49151}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB
|
||||
},
|
||||
outputs: []outputInfo{
|
||||
{0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SHLXLloadidx4",
|
||||
auxType: auxSymOff,
|
||||
argLen: 4,
|
||||
faultOnNilArg0: true,
|
||||
symEffect: SymRead,
|
||||
asm: x86.ASHLXL,
|
||||
scale: 4,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{2, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
{1, 49151}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB
|
||||
},
|
||||
outputs: []outputInfo{
|
||||
{0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SHLXLloadidx8",
|
||||
auxType: auxSymOff,
|
||||
argLen: 4,
|
||||
faultOnNilArg0: true,
|
||||
symEffect: SymRead,
|
||||
asm: x86.ASHLXL,
|
||||
scale: 8,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{2, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
{1, 49151}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB
|
||||
},
|
||||
outputs: []outputInfo{
|
||||
{0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SHLXQloadidx1",
|
||||
auxType: auxSymOff,
|
||||
argLen: 4,
|
||||
faultOnNilArg0: true,
|
||||
symEffect: SymRead,
|
||||
asm: x86.ASHLXQ,
|
||||
scale: 1,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{2, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
{1, 49151}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB
|
||||
},
|
||||
outputs: []outputInfo{
|
||||
{0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SHLXQloadidx8",
|
||||
auxType: auxSymOff,
|
||||
argLen: 4,
|
||||
faultOnNilArg0: true,
|
||||
symEffect: SymRead,
|
||||
asm: x86.ASHLXQ,
|
||||
scale: 8,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{2, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
{1, 49151}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB
|
||||
},
|
||||
outputs: []outputInfo{
|
||||
{0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SHRXLloadidx1",
|
||||
auxType: auxSymOff,
|
||||
argLen: 4,
|
||||
faultOnNilArg0: true,
|
||||
symEffect: SymRead,
|
||||
asm: x86.ASHRXL,
|
||||
scale: 1,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{2, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
{1, 49151}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB
|
||||
},
|
||||
outputs: []outputInfo{
|
||||
{0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SHRXLloadidx4",
|
||||
auxType: auxSymOff,
|
||||
argLen: 4,
|
||||
faultOnNilArg0: true,
|
||||
symEffect: SymRead,
|
||||
asm: x86.ASHRXL,
|
||||
scale: 4,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{2, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
{1, 49151}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB
|
||||
},
|
||||
outputs: []outputInfo{
|
||||
{0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SHRXLloadidx8",
|
||||
auxType: auxSymOff,
|
||||
argLen: 4,
|
||||
faultOnNilArg0: true,
|
||||
symEffect: SymRead,
|
||||
asm: x86.ASHRXL,
|
||||
scale: 8,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{2, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
{1, 49151}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB
|
||||
},
|
||||
outputs: []outputInfo{
|
||||
{0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SHRXQloadidx1",
|
||||
auxType: auxSymOff,
|
||||
argLen: 4,
|
||||
faultOnNilArg0: true,
|
||||
symEffect: SymRead,
|
||||
asm: x86.ASHRXQ,
|
||||
scale: 1,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{2, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
{1, 49151}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB
|
||||
},
|
||||
outputs: []outputInfo{
|
||||
{0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SHRXQloadidx8",
|
||||
auxType: auxSymOff,
|
||||
argLen: 4,
|
||||
faultOnNilArg0: true,
|
||||
symEffect: SymRead,
|
||||
asm: x86.ASHRXQ,
|
||||
scale: 8,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{2, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
{1, 49151}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB
|
||||
},
|
||||
outputs: []outputInfo{
|
||||
{0, 49135}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "ADD",
|
||||
|
|
@ -25134,6 +25456,7 @@ var opcodeTable = [...]opInfo{
|
|||
inputs: []inputInfo{
|
||||
{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
},
|
||||
clobbers: 9223372036854775808, // XER
|
||||
outputs: []outputInfo{
|
||||
{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
},
|
||||
|
|
@ -25414,6 +25737,7 @@ var opcodeTable = [...]opInfo{
|
|||
{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
{1, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
},
|
||||
clobbers: 9223372036854775808, // XER
|
||||
outputs: []outputInfo{
|
||||
{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
},
|
||||
|
|
@ -25428,6 +25752,7 @@ var opcodeTable = [...]opInfo{
|
|||
{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
{1, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
},
|
||||
clobbers: 9223372036854775808, // XER
|
||||
outputs: []outputInfo{
|
||||
{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
},
|
||||
|
|
@ -25575,6 +25900,132 @@ var opcodeTable = [...]opInfo{
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ADDC",
|
||||
argLen: 2,
|
||||
commutative: true,
|
||||
asm: ppc64.AADDC,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
{1, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
},
|
||||
clobbers: 9223372036854775808, // XER
|
||||
outputs: []outputInfo{
|
||||
{1, 9223372036854775808}, // XER
|
||||
{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SUBC",
|
||||
argLen: 2,
|
||||
asm: ppc64.ASUBC,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
{1, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
},
|
||||
clobbers: 9223372036854775808, // XER
|
||||
outputs: []outputInfo{
|
||||
{1, 9223372036854775808}, // XER
|
||||
{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ADDCconst",
|
||||
auxType: auxInt64,
|
||||
argLen: 1,
|
||||
asm: ppc64.AADDC,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
},
|
||||
outputs: []outputInfo{
|
||||
{1, 9223372036854775808}, // XER
|
||||
{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SUBCconst",
|
||||
auxType: auxInt64,
|
||||
argLen: 1,
|
||||
asm: ppc64.ASUBC,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
},
|
||||
outputs: []outputInfo{
|
||||
{1, 9223372036854775808}, // XER
|
||||
{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ADDE",
|
||||
argLen: 3,
|
||||
commutative: true,
|
||||
asm: ppc64.AADDE,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{2, 9223372036854775808}, // XER
|
||||
{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
{1, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
},
|
||||
clobbers: 9223372036854775808, // XER
|
||||
outputs: []outputInfo{
|
||||
{1, 9223372036854775808}, // XER
|
||||
{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SUBE",
|
||||
argLen: 3,
|
||||
asm: ppc64.ASUBE,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{2, 9223372036854775808}, // XER
|
||||
{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
{1, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
},
|
||||
clobbers: 9223372036854775808, // XER
|
||||
outputs: []outputInfo{
|
||||
{1, 9223372036854775808}, // XER
|
||||
{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ADDZEzero",
|
||||
argLen: 1,
|
||||
asm: ppc64.AADDZE,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 9223372036854775808}, // XER
|
||||
},
|
||||
clobbers: 9223372036854775808, // XER
|
||||
outputs: []outputInfo{
|
||||
{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SUBZEzero",
|
||||
argLen: 1,
|
||||
asm: ppc64.ASUBZE,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 9223372036854775808}, // XER
|
||||
},
|
||||
clobbers: 9223372036854775808, // XER
|
||||
outputs: []outputInfo{
|
||||
{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SRADconst",
|
||||
auxType: auxInt64,
|
||||
|
|
@ -25584,6 +26035,7 @@ var opcodeTable = [...]opInfo{
|
|||
inputs: []inputInfo{
|
||||
{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
},
|
||||
clobbers: 9223372036854775808, // XER
|
||||
outputs: []outputInfo{
|
||||
{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
},
|
||||
|
|
@ -25598,6 +26050,7 @@ var opcodeTable = [...]opInfo{
|
|||
inputs: []inputInfo{
|
||||
{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
},
|
||||
clobbers: 9223372036854775808, // XER
|
||||
outputs: []outputInfo{
|
||||
{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
|
||||
},
|
||||
|
|
@ -27461,7 +27914,7 @@ var opcodeTable = [...]opInfo{
|
|||
clobberFlags: true,
|
||||
call: true,
|
||||
reg: regInfo{
|
||||
clobbers: 9223372034707283960, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 g F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30
|
||||
clobbers: 18446744071562059768, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 g F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 XER
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -27472,7 +27925,7 @@ var opcodeTable = [...]opInfo{
|
|||
call: true,
|
||||
tailCall: true,
|
||||
reg: regInfo{
|
||||
clobbers: 9223372034707283960, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 g F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30
|
||||
clobbers: 18446744071562059768, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 g F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 XER
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -27486,7 +27939,7 @@ var opcodeTable = [...]opInfo{
|
|||
{0, 4096}, // R12
|
||||
{1, 2048}, // R11
|
||||
},
|
||||
clobbers: 9223372034707283960, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 g F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30
|
||||
clobbers: 18446744071562059768, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 g F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 XER
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -27499,7 +27952,7 @@ var opcodeTable = [...]opInfo{
|
|||
inputs: []inputInfo{
|
||||
{0, 4096}, // R12
|
||||
},
|
||||
clobbers: 9223372034707283960, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 g F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30
|
||||
clobbers: 18446744071562059768, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 g F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 XER
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -27882,7 +28335,7 @@ var opcodeTable = [...]opInfo{
|
|||
{0, 1048576}, // R20
|
||||
{1, 2097152}, // R21
|
||||
},
|
||||
clobbers: 9223372035777632256, // R11 R12 R18 R19 R22 R23 R24 R25 R26 R27 R28 R29 R31 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30
|
||||
clobbers: 18446744072632408064, // R11 R12 R18 R19 R22 R23 R24 R25 R26 R27 R28 R29 R31 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 XER
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -37287,7 +37740,7 @@ var paramIntRegPPC64 = []int8{3, 4, 5, 6, 7, 8, 9, 10, 14, 15, 16, 17}
|
|||
var paramFloatRegPPC64 = []int8{33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44}
|
||||
var gpRegMaskPPC64 = regMask(1073733624)
|
||||
var fpRegMaskPPC64 = regMask(9223372032559808512)
|
||||
var specialRegMaskPPC64 = regMask(0)
|
||||
var specialRegMaskPPC64 = regMask(9223372036854775808)
|
||||
var framepointerRegPPC64 = int8(-1)
|
||||
var linkRegPPC64 = int8(-1)
|
||||
var registersRISCV64 = [...]Register{
|
||||
|
|
|
|||
|
|
@ -15,12 +15,12 @@ package ssa
|
|||
//
|
||||
// In SSA code this appears as
|
||||
//
|
||||
// b0
|
||||
// If b -> b1 b2
|
||||
// b1
|
||||
// Plain -> b2
|
||||
// b2
|
||||
// x = (OpPhi (ConstBool [true]) (ConstBool [false]))
|
||||
// b0
|
||||
// If b -> b1 b2
|
||||
// b1
|
||||
// Plain -> b2
|
||||
// b2
|
||||
// x = (OpPhi (ConstBool [true]) (ConstBool [false]))
|
||||
//
|
||||
// In this case we can replace x with a copy of b.
|
||||
func phiopt(f *Func) {
|
||||
|
|
|
|||
|
|
@ -145,7 +145,6 @@ type posetNode struct {
|
|||
// I extra
|
||||
// / \
|
||||
// J K
|
||||
//
|
||||
type poset struct {
|
||||
lastidx uint32 // last generated dense index
|
||||
flags uint8 // internal flags
|
||||
|
|
|
|||
|
|
@ -27,17 +27,17 @@ const (
|
|||
//
|
||||
// E.g.
|
||||
//
|
||||
// r := relation(...)
|
||||
// r := relation(...)
|
||||
//
|
||||
// if v < w {
|
||||
// newR := r & lt
|
||||
// }
|
||||
// if v >= w {
|
||||
// newR := r & (eq|gt)
|
||||
// }
|
||||
// if v != w {
|
||||
// newR := r & (lt|gt)
|
||||
// }
|
||||
// if v < w {
|
||||
// newR := r & lt
|
||||
// }
|
||||
// if v >= w {
|
||||
// newR := r & (eq|gt)
|
||||
// }
|
||||
// if v != w {
|
||||
// newR := r & (lt|gt)
|
||||
// }
|
||||
type relation uint
|
||||
|
||||
const (
|
||||
|
|
|
|||
|
|
@ -1237,7 +1237,7 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
desired.clobber(j.regs)
|
||||
desired.add(v.Args[j.idx].ID, pickReg(j.regs))
|
||||
}
|
||||
if opcodeTable[v.Op].resultInArg0 {
|
||||
if opcodeTable[v.Op].resultInArg0 || v.Op == OpAMD64ADDQconst || v.Op == OpAMD64ADDLconst || v.Op == OpSelect0 {
|
||||
if opcodeTable[v.Op].commutative {
|
||||
desired.addList(v.Args[1].ID, prefs)
|
||||
}
|
||||
|
|
@ -1598,11 +1598,13 @@ func (s *regAllocState) regalloc(f *Func) {
|
|||
}
|
||||
}
|
||||
}
|
||||
for _, r := range dinfo[idx].out {
|
||||
if r != noRegister && (mask&^s.used)>>r&1 != 0 {
|
||||
// Desired register is allowed and unused.
|
||||
mask = regMask(1) << r
|
||||
break
|
||||
if out.idx == 0 { // desired registers only apply to the first element of a tuple result
|
||||
for _, r := range dinfo[idx].out {
|
||||
if r != noRegister && (mask&^s.used)>>r&1 != 0 {
|
||||
// Desired register is allowed and unused.
|
||||
mask = regMask(1) << r
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// Avoid registers we're saving for other values.
|
||||
|
|
@ -2581,7 +2583,12 @@ func (s *regAllocState) computeLive() {
|
|||
desired.add(v.Args[j.idx].ID, pickReg(j.regs))
|
||||
}
|
||||
// Set desired register of input 0 if this is a 2-operand instruction.
|
||||
if opcodeTable[v.Op].resultInArg0 {
|
||||
if opcodeTable[v.Op].resultInArg0 || v.Op == OpAMD64ADDQconst || v.Op == OpAMD64ADDLconst || v.Op == OpSelect0 {
|
||||
// ADDQconst is added here because we want to treat it as resultInArg0 for
|
||||
// the purposes of desired registers, even though it is not an absolute requirement.
|
||||
// This is because we'd rather implement it as ADDQ instead of LEAQ.
|
||||
// Same for ADDLconst
|
||||
// Select0 is added here to propagate the desired register to the tuple-generating instruction.
|
||||
if opcodeTable[v.Op].commutative {
|
||||
desired.addList(v.Args[1].ID, prefs)
|
||||
}
|
||||
|
|
@ -2706,6 +2713,8 @@ type desiredStateEntry struct {
|
|||
ID ID
|
||||
// Registers it would like to be in, in priority order.
|
||||
// Unused slots are filled with noRegister.
|
||||
// For opcodes that return tuples, we track desired registers only
|
||||
// for the first element of the tuple.
|
||||
regs [4]register
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -226,6 +226,8 @@ func rewriteValueAMD64(v *Value) bool {
|
|||
return rewriteValueAMD64_OpAMD64MOVBELstore(v)
|
||||
case OpAMD64MOVBEQstore:
|
||||
return rewriteValueAMD64_OpAMD64MOVBEQstore(v)
|
||||
case OpAMD64MOVBEWstore:
|
||||
return rewriteValueAMD64_OpAMD64MOVBEWstore(v)
|
||||
case OpAMD64MOVBQSX:
|
||||
return rewriteValueAMD64_OpAMD64MOVBQSX(v)
|
||||
case OpAMD64MOVBQSXload:
|
||||
|
|
@ -9542,6 +9544,34 @@ func rewriteValueAMD64_OpAMD64MOVBEQstore(v *Value) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64_OpAMD64MOVBEWstore(v *Value) bool {
|
||||
v_2 := v.Args[2]
|
||||
v_1 := v.Args[1]
|
||||
v_0 := v.Args[0]
|
||||
// match: (MOVBEWstore [i] {s} p x:(ROLWconst [8] w) mem)
|
||||
// cond: x.Uses == 1
|
||||
// result: (MOVWstore [i] {s} p w mem)
|
||||
for {
|
||||
i := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
p := v_0
|
||||
x := v_1
|
||||
if x.Op != OpAMD64ROLWconst || auxIntToInt8(x.AuxInt) != 8 {
|
||||
break
|
||||
}
|
||||
w := x.Args[0]
|
||||
mem := v_2
|
||||
if !(x.Uses == 1) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64MOVWstore)
|
||||
v.AuxInt = int32ToAuxInt(i)
|
||||
v.Aux = symToAux(s)
|
||||
v.AddArg3(p, w, mem)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64_OpAMD64MOVBQSX(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
|
|
@ -14466,6 +14496,28 @@ func rewriteValueAMD64_OpAMD64MOVWstore(v *Value) bool {
|
|||
v.AddArg3(p, v0, mem)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWstore [i] {s} p x:(ROLWconst [8] w) mem)
|
||||
// cond: x.Uses == 1 && buildcfg.GOAMD64 >= 3
|
||||
// result: (MOVBEWstore [i] {s} p w mem)
|
||||
for {
|
||||
i := auxIntToInt32(v.AuxInt)
|
||||
s := auxToSym(v.Aux)
|
||||
p := v_0
|
||||
x := v_1
|
||||
if x.Op != OpAMD64ROLWconst || auxIntToInt8(x.AuxInt) != 8 {
|
||||
break
|
||||
}
|
||||
w := x.Args[0]
|
||||
mem := v_2
|
||||
if !(x.Uses == 1 && buildcfg.GOAMD64 >= 3) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64MOVBEWstore)
|
||||
v.AuxInt = int32ToAuxInt(i)
|
||||
v.Aux = symToAux(s)
|
||||
v.AddArg3(p, w, mem)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64_OpAMD64MOVWstoreconst(v *Value) bool {
|
||||
|
|
@ -24589,6 +24641,28 @@ func rewriteValueAMD64_OpAMD64SHLL(v *Value) bool {
|
|||
v.AddArg2(x, v0)
|
||||
return true
|
||||
}
|
||||
// match: (SHLL l:(MOVLload [off] {sym} ptr mem) x)
|
||||
// cond: buildcfg.GOAMD64 >= 3 && canMergeLoad(v, l) && clobber(l)
|
||||
// result: (SHLXLload [off] {sym} ptr x mem)
|
||||
for {
|
||||
l := v_0
|
||||
if l.Op != OpAMD64MOVLload {
|
||||
break
|
||||
}
|
||||
off := auxIntToInt32(l.AuxInt)
|
||||
sym := auxToSym(l.Aux)
|
||||
mem := l.Args[1]
|
||||
ptr := l.Args[0]
|
||||
x := v_1
|
||||
if !(buildcfg.GOAMD64 >= 3 && canMergeLoad(v, l) && clobber(l)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64SHLXLload)
|
||||
v.AuxInt = int32ToAuxInt(off)
|
||||
v.Aux = symToAux(sym)
|
||||
v.AddArg3(ptr, x, mem)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64_OpAMD64SHLLconst(v *Value) bool {
|
||||
|
|
@ -24823,6 +24897,28 @@ func rewriteValueAMD64_OpAMD64SHLQ(v *Value) bool {
|
|||
v.AddArg2(x, v0)
|
||||
return true
|
||||
}
|
||||
// match: (SHLQ l:(MOVQload [off] {sym} ptr mem) x)
|
||||
// cond: buildcfg.GOAMD64 >= 3 && canMergeLoad(v, l) && clobber(l)
|
||||
// result: (SHLXQload [off] {sym} ptr x mem)
|
||||
for {
|
||||
l := v_0
|
||||
if l.Op != OpAMD64MOVQload {
|
||||
break
|
||||
}
|
||||
off := auxIntToInt32(l.AuxInt)
|
||||
sym := auxToSym(l.Aux)
|
||||
mem := l.Args[1]
|
||||
ptr := l.Args[0]
|
||||
x := v_1
|
||||
if !(buildcfg.GOAMD64 >= 3 && canMergeLoad(v, l) && clobber(l)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64SHLXQload)
|
||||
v.AuxInt = int32ToAuxInt(off)
|
||||
v.Aux = symToAux(sym)
|
||||
v.AddArg3(ptr, x, mem)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64_OpAMD64SHLQconst(v *Value) bool {
|
||||
|
|
@ -25152,6 +25248,28 @@ func rewriteValueAMD64_OpAMD64SHRL(v *Value) bool {
|
|||
v.AddArg2(x, v0)
|
||||
return true
|
||||
}
|
||||
// match: (SHRL l:(MOVLload [off] {sym} ptr mem) x)
|
||||
// cond: buildcfg.GOAMD64 >= 3 && canMergeLoad(v, l) && clobber(l)
|
||||
// result: (SHRXLload [off] {sym} ptr x mem)
|
||||
for {
|
||||
l := v_0
|
||||
if l.Op != OpAMD64MOVLload {
|
||||
break
|
||||
}
|
||||
off := auxIntToInt32(l.AuxInt)
|
||||
sym := auxToSym(l.Aux)
|
||||
mem := l.Args[1]
|
||||
ptr := l.Args[0]
|
||||
x := v_1
|
||||
if !(buildcfg.GOAMD64 >= 3 && canMergeLoad(v, l) && clobber(l)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64SHRXLload)
|
||||
v.AuxInt = int32ToAuxInt(off)
|
||||
v.Aux = symToAux(sym)
|
||||
v.AddArg3(ptr, x, mem)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64_OpAMD64SHRLconst(v *Value) bool {
|
||||
|
|
@ -25374,6 +25492,28 @@ func rewriteValueAMD64_OpAMD64SHRQ(v *Value) bool {
|
|||
v.AddArg2(x, v0)
|
||||
return true
|
||||
}
|
||||
// match: (SHRQ l:(MOVQload [off] {sym} ptr mem) x)
|
||||
// cond: buildcfg.GOAMD64 >= 3 && canMergeLoad(v, l) && clobber(l)
|
||||
// result: (SHRXQload [off] {sym} ptr x mem)
|
||||
for {
|
||||
l := v_0
|
||||
if l.Op != OpAMD64MOVQload {
|
||||
break
|
||||
}
|
||||
off := auxIntToInt32(l.AuxInt)
|
||||
sym := auxToSym(l.Aux)
|
||||
mem := l.Args[1]
|
||||
ptr := l.Args[0]
|
||||
x := v_1
|
||||
if !(buildcfg.GOAMD64 >= 3 && canMergeLoad(v, l) && clobber(l)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64SHRXQload)
|
||||
v.AuxInt = int32ToAuxInt(off)
|
||||
v.Aux = symToAux(sym)
|
||||
v.AddArg3(ptr, x, mem)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64_OpAMD64SHRQconst(v *Value) bool {
|
||||
|
|
@ -27974,9 +28114,13 @@ func rewriteValueAMD64_OpBitLen16(v *Value) bool {
|
|||
b := v.Block
|
||||
typ := &b.Func.Config.Types
|
||||
// match: (BitLen16 x)
|
||||
// cond: buildcfg.GOAMD64 < 3
|
||||
// result: (BSRL (LEAL1 <typ.UInt32> [1] (MOVWQZX <typ.UInt32> x) (MOVWQZX <typ.UInt32> x)))
|
||||
for {
|
||||
x := v_0
|
||||
if !(buildcfg.GOAMD64 < 3) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64BSRL)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64LEAL1, typ.UInt32)
|
||||
v0.AuxInt = int32ToAuxInt(1)
|
||||
|
|
@ -27986,15 +28130,38 @@ func rewriteValueAMD64_OpBitLen16(v *Value) bool {
|
|||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
// match: (BitLen16 <t> x)
|
||||
// cond: buildcfg.GOAMD64 >= 3
|
||||
// result: (NEGQ (ADDQconst <t> [-32] (LZCNTL x)))
|
||||
for {
|
||||
t := v.Type
|
||||
x := v_0
|
||||
if !(buildcfg.GOAMD64 >= 3) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64NEGQ)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64ADDQconst, t)
|
||||
v0.AuxInt = int32ToAuxInt(-32)
|
||||
v1 := b.NewValue0(v.Pos, OpAMD64LZCNTL, typ.UInt32)
|
||||
v1.AddArg(x)
|
||||
v0.AddArg(v1)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64_OpBitLen32(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
typ := &b.Func.Config.Types
|
||||
// match: (BitLen32 x)
|
||||
// cond: buildcfg.GOAMD64 < 3
|
||||
// result: (Select0 (BSRQ (LEAQ1 <typ.UInt64> [1] (MOVLQZX <typ.UInt64> x) (MOVLQZX <typ.UInt64> x))))
|
||||
for {
|
||||
x := v_0
|
||||
if !(buildcfg.GOAMD64 < 3) {
|
||||
break
|
||||
}
|
||||
v.reset(OpSelect0)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64BSRQ, types.NewTuple(typ.UInt64, types.TypeFlags))
|
||||
v1 := b.NewValue0(v.Pos, OpAMD64LEAQ1, typ.UInt64)
|
||||
|
|
@ -28006,16 +28173,39 @@ func rewriteValueAMD64_OpBitLen32(v *Value) bool {
|
|||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
// match: (BitLen32 <t> x)
|
||||
// cond: buildcfg.GOAMD64 >= 3
|
||||
// result: (NEGQ (ADDQconst <t> [-32] (LZCNTL x)))
|
||||
for {
|
||||
t := v.Type
|
||||
x := v_0
|
||||
if !(buildcfg.GOAMD64 >= 3) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64NEGQ)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64ADDQconst, t)
|
||||
v0.AuxInt = int32ToAuxInt(-32)
|
||||
v1 := b.NewValue0(v.Pos, OpAMD64LZCNTL, typ.UInt32)
|
||||
v1.AddArg(x)
|
||||
v0.AddArg(v1)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64_OpBitLen64(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
typ := &b.Func.Config.Types
|
||||
// match: (BitLen64 <t> x)
|
||||
// cond: buildcfg.GOAMD64 < 3
|
||||
// result: (ADDQconst [1] (CMOVQEQ <t> (Select0 <t> (BSRQ x)) (MOVQconst <t> [-1]) (Select1 <types.TypeFlags> (BSRQ x))))
|
||||
for {
|
||||
t := v.Type
|
||||
x := v_0
|
||||
if !(buildcfg.GOAMD64 < 3) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64ADDQconst)
|
||||
v.AuxInt = int32ToAuxInt(1)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64CMOVQEQ, t)
|
||||
|
|
@ -28031,15 +28221,38 @@ func rewriteValueAMD64_OpBitLen64(v *Value) bool {
|
|||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
// match: (BitLen64 <t> x)
|
||||
// cond: buildcfg.GOAMD64 >= 3
|
||||
// result: (NEGQ (ADDQconst <t> [-64] (LZCNTQ x)))
|
||||
for {
|
||||
t := v.Type
|
||||
x := v_0
|
||||
if !(buildcfg.GOAMD64 >= 3) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64NEGQ)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64ADDQconst, t)
|
||||
v0.AuxInt = int32ToAuxInt(-64)
|
||||
v1 := b.NewValue0(v.Pos, OpAMD64LZCNTQ, typ.UInt64)
|
||||
v1.AddArg(x)
|
||||
v0.AddArg(v1)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64_OpBitLen8(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
b := v.Block
|
||||
typ := &b.Func.Config.Types
|
||||
// match: (BitLen8 x)
|
||||
// cond: buildcfg.GOAMD64 < 3
|
||||
// result: (BSRL (LEAL1 <typ.UInt32> [1] (MOVBQZX <typ.UInt32> x) (MOVBQZX <typ.UInt32> x)))
|
||||
for {
|
||||
x := v_0
|
||||
if !(buildcfg.GOAMD64 < 3) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64BSRL)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64LEAL1, typ.UInt32)
|
||||
v0.AuxInt = int32ToAuxInt(1)
|
||||
|
|
@ -28049,6 +28262,25 @@ func rewriteValueAMD64_OpBitLen8(v *Value) bool {
|
|||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
// match: (BitLen8 <t> x)
|
||||
// cond: buildcfg.GOAMD64 >= 3
|
||||
// result: (NEGQ (ADDQconst <t> [-32] (LZCNTL x)))
|
||||
for {
|
||||
t := v.Type
|
||||
x := v_0
|
||||
if !(buildcfg.GOAMD64 >= 3) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64NEGQ)
|
||||
v0 := b.NewValue0(v.Pos, OpAMD64ADDQconst, t)
|
||||
v0.AuxInt = int32ToAuxInt(-32)
|
||||
v1 := b.NewValue0(v.Pos, OpAMD64LZCNTL, typ.UInt32)
|
||||
v1.AddArg(x)
|
||||
v0.AddArg(v1)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueAMD64_OpCeil(v *Value) bool {
|
||||
v_0 := v.Args[0]
|
||||
|
|
|
|||
|
|
@ -207,8 +207,8 @@ func (t SparseTree) isAncestor(x, y *Block) bool {
|
|||
// domorder returns a value for dominator-oriented sorting.
|
||||
// Block domination does not provide a total ordering,
|
||||
// but domorder two has useful properties.
|
||||
// (1) If domorder(x) > domorder(y) then x does not dominate y.
|
||||
// (2) If domorder(x) < domorder(y) and domorder(y) < domorder(z) and x does not dominate y,
|
||||
// 1. If domorder(x) > domorder(y) then x does not dominate y.
|
||||
// 2. If domorder(x) < domorder(y) and domorder(y) < domorder(z) and x does not dominate y,
|
||||
// then x does not dominate z.
|
||||
// Property (1) means that blocks sorted by domorder always have a maximal dominant block first.
|
||||
// Property (2) allows searches for dominated blocks to exit early.
|
||||
|
|
|
|||
|
|
@ -80,11 +80,11 @@ func needwb(v *Value, zeroes map[ID]ZeroRegion) bool {
|
|||
// when necessary (the condition above). It rewrites store ops to branches
|
||||
// and runtime calls, like
|
||||
//
|
||||
// if writeBarrier.enabled {
|
||||
// gcWriteBarrier(ptr, val) // Not a regular Go call
|
||||
// } else {
|
||||
// *ptr = val
|
||||
// }
|
||||
// if writeBarrier.enabled {
|
||||
// gcWriteBarrier(ptr, val) // Not a regular Go call
|
||||
// } else {
|
||||
// *ptr = val
|
||||
// }
|
||||
//
|
||||
// A sequence of WB stores for many pointer fields of a single type will
|
||||
// be emitted together, with a single branch.
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import (
|
|||
|
||||
"cmd/compile/internal/base"
|
||||
"cmd/compile/internal/ir"
|
||||
"cmd/compile/internal/staticdata"
|
||||
"cmd/compile/internal/typecheck"
|
||||
"cmd/compile/internal/types"
|
||||
"cmd/internal/obj"
|
||||
|
|
@ -243,17 +242,6 @@ func InitLSym(f *ir.Func, hasBody bool) {
|
|||
if f.Pragma&ir.Systemstack != 0 {
|
||||
f.LSym.Set(obj.AttrCFunc, true)
|
||||
}
|
||||
if f.ABI == obj.ABIInternal || !buildcfg.Experiment.RegabiWrappers {
|
||||
// Function values can only point to
|
||||
// ABIInternal entry points. This will create
|
||||
// the funcsym for either the defining
|
||||
// function or its wrapper as appropriate.
|
||||
//
|
||||
// If we're not using ABI wrappers, we only
|
||||
// InitLSym for the defining ABI of a function,
|
||||
// so we make the funcsym when we see that.
|
||||
staticdata.NeedFuncSym(f)
|
||||
}
|
||||
}
|
||||
if hasBody {
|
||||
setupTextLSym(f, 0)
|
||||
|
|
|
|||
|
|
@ -4496,9 +4496,6 @@ func InitTables() {
|
|||
sys.ARM64)
|
||||
addF("math/bits", "Reverse",
|
||||
func(s *state, n *ir.CallExpr, args []*ssa.Value) *ssa.Value {
|
||||
if s.config.PtrSize == 4 {
|
||||
return s.newValue1(ssa.OpBitRev32, types.Types[types.TINT], args[0])
|
||||
}
|
||||
return s.newValue1(ssa.OpBitRev64, types.Types[types.TINT], args[0])
|
||||
},
|
||||
sys.ARM64)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import (
|
|||
"crypto/sha256"
|
||||
"fmt"
|
||||
"go/constant"
|
||||
"internal/buildcfg"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
|
@ -236,15 +235,9 @@ func FuncLinksym(n *ir.Name) *obj.LSym {
|
|||
// except for the types package, which is protected separately.
|
||||
// Reusing funcsymsmu to also cover this package lookup
|
||||
// avoids a general, broader, expensive package lookup mutex.
|
||||
// Note NeedFuncSym also does package look-up of func sym names,
|
||||
// but that it is only called serially, from the front end.
|
||||
funcsymsmu.Lock()
|
||||
sf, existed := s.Pkg.LookupOK(ir.FuncSymName(s))
|
||||
// Don't export s·f when compiling for dynamic linking.
|
||||
// When dynamically linking, the necessary function
|
||||
// symbols will be created explicitly with NeedFuncSym.
|
||||
// See the NeedFuncSym comment for details.
|
||||
if !base.Ctxt.Flag_dynlink && !existed {
|
||||
if !existed {
|
||||
funcsyms = append(funcsyms, n)
|
||||
}
|
||||
funcsymsmu.Unlock()
|
||||
|
|
@ -259,48 +252,6 @@ func GlobalLinksym(n *ir.Name) *obj.LSym {
|
|||
return n.Linksym()
|
||||
}
|
||||
|
||||
// NeedFuncSym ensures that fn·f is exported, if needed.
|
||||
// It is only used with -dynlink.
|
||||
// When not compiling for dynamic linking,
|
||||
// the funcsyms are created as needed by
|
||||
// the packages that use them.
|
||||
// Normally we emit the fn·f stubs as DUPOK syms,
|
||||
// but DUPOK doesn't work across shared library boundaries.
|
||||
// So instead, when dynamic linking, we only create
|
||||
// the fn·f stubs in fn's package.
|
||||
func NeedFuncSym(fn *ir.Func) {
|
||||
if base.Ctxt.InParallel {
|
||||
// The append below probably just needs to lock
|
||||
// funcsymsmu, like in FuncSym.
|
||||
base.Fatalf("NeedFuncSym must be called in serial")
|
||||
}
|
||||
if fn.ABI != obj.ABIInternal && buildcfg.Experiment.RegabiWrappers {
|
||||
// Function values must always reference ABIInternal
|
||||
// entry points, so it doesn't make sense to create a
|
||||
// funcsym for other ABIs.
|
||||
//
|
||||
// (If we're not using ABI wrappers, it doesn't matter.)
|
||||
base.Fatalf("expected ABIInternal: %v has %v", fn.Nname, fn.ABI)
|
||||
}
|
||||
if ir.IsBlank(fn.Nname) {
|
||||
// Blank functions aren't unique, so we can't make a
|
||||
// funcsym for them.
|
||||
base.Fatalf("NeedFuncSym called for _")
|
||||
}
|
||||
if !base.Ctxt.Flag_dynlink {
|
||||
return
|
||||
}
|
||||
s := fn.Nname.Sym()
|
||||
if base.Flag.CompilingRuntime && (s.Name == "getg" || s.Name == "getclosureptr" || s.Name == "getcallerpc" || s.Name == "getcallersp") ||
|
||||
(base.Ctxt.Pkgpath == "internal/abi" && (s.Name == "FuncPCABI0" || s.Name == "FuncPCABIInternal")) {
|
||||
// runtime.getg(), getclosureptr(), getcallerpc(), getcallersp(),
|
||||
// and internal/abi.FuncPCABIxxx() are not real functions and so
|
||||
// do not get funcsyms.
|
||||
return
|
||||
}
|
||||
funcsyms = append(funcsyms, fn.Nname)
|
||||
}
|
||||
|
||||
func WriteFuncSyms() {
|
||||
sort.Slice(funcsyms, func(i, j int) bool {
|
||||
return funcsyms[i].Linksym().Name < funcsyms[j].Linksym().Name
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ func TestDump(t *testing.T) {
|
|||
t.Skip("skipping test in short mode")
|
||||
}
|
||||
|
||||
ast, _ := ParseFile(*src_, func(err error) { t.Error(err) }, nil, CheckBranches|AllowGenerics)
|
||||
ast, _ := ParseFile(*src_, func(err error) { t.Error(err) }, nil, CheckBranches)
|
||||
|
||||
if ast != nil {
|
||||
Fdump(testOut(), ast)
|
||||
|
|
|
|||
|
|
@ -128,10 +128,6 @@ func testSyntaxErrors(t *testing.T, filename string) {
|
|||
}
|
||||
defer f.Close()
|
||||
|
||||
var mode Mode
|
||||
if strings.HasSuffix(filename, ".go2") {
|
||||
mode = AllowGenerics
|
||||
}
|
||||
ParseFile(filename, func(err error) {
|
||||
e, ok := err.(Error)
|
||||
if !ok {
|
||||
|
|
@ -166,7 +162,7 @@ func testSyntaxErrors(t *testing.T, filename string) {
|
|||
} else {
|
||||
t.Errorf("%s:%s: unexpected error: %s", filename, orig, e.Msg)
|
||||
}
|
||||
}, nil, mode)
|
||||
}, nil, 0)
|
||||
|
||||
if *print {
|
||||
fmt.Println()
|
||||
|
|
|
|||
|
|
@ -462,7 +462,7 @@ func (simpleStmt) aSimpleStmt() {}
|
|||
// Comments
|
||||
|
||||
// TODO(gri) Consider renaming to CommentPos, CommentPlacement, etc.
|
||||
// Kind = Above doesn't make much sense.
|
||||
// Kind = Above doesn't make much sense.
|
||||
type CommentKind uint
|
||||
|
||||
const (
|
||||
|
|
|
|||
|
|
@ -87,8 +87,6 @@ func (p *parser) init(file *PosBase, r io.Reader, errh ErrorHandler, pragh Pragm
|
|||
p.indent = nil
|
||||
}
|
||||
|
||||
func (p *parser) allowGenerics() bool { return p.mode&AllowGenerics != 0 }
|
||||
|
||||
// takePragma returns the current parsed pragmas
|
||||
// and clears them from the parser state.
|
||||
func (p *parser) takePragma() Pragma {
|
||||
|
|
@ -473,8 +471,7 @@ func isEmptyFuncDecl(dcl Decl) bool {
|
|||
// elements are accepted. list returns the position of the closing token.
|
||||
//
|
||||
// list = [ f { sep f } [sep] ] close .
|
||||
//
|
||||
func (p *parser) list(sep, close token, f func() bool) Pos {
|
||||
func (p *parser) list(context string, sep, close token, f func() bool) Pos {
|
||||
if debug && (sep != _Comma && sep != _Semi || close != _Rparen && close != _Rbrace && close != _Rbrack) {
|
||||
panic("invalid sep or close argument for list")
|
||||
}
|
||||
|
|
@ -484,7 +481,7 @@ func (p *parser) list(sep, close token, f func() bool) Pos {
|
|||
done = f()
|
||||
// sep is optional before close
|
||||
if !p.got(sep) && p.tok != close {
|
||||
p.syntaxError(fmt.Sprintf("expecting %s or %s", tokstring(sep), tokstring(close)))
|
||||
p.syntaxError(fmt.Sprintf("in %s; possibly missing %s or %s", context, tokstring(sep), tokstring(close)))
|
||||
p.advance(_Rparen, _Rbrack, _Rbrace)
|
||||
if p.tok != close {
|
||||
// position could be better but we had an error so we don't care
|
||||
|
|
@ -504,7 +501,7 @@ func (p *parser) appendGroup(list []Decl, f func(*Group) Decl) []Decl {
|
|||
g := new(Group)
|
||||
p.clearPragma()
|
||||
p.next() // must consume "(" after calling clearPragma!
|
||||
p.list(_Semi, _Rparen, func() bool {
|
||||
p.list("grouped declaration", _Semi, _Rparen, func() bool {
|
||||
if x := f(g); x != nil {
|
||||
list = append(list, x)
|
||||
}
|
||||
|
|
@ -586,7 +583,7 @@ func (p *parser) typeDecl(group *Group) Decl {
|
|||
d.Pragma = p.takePragma()
|
||||
|
||||
d.Name = p.name()
|
||||
if p.allowGenerics() && p.tok == _Lbrack {
|
||||
if p.tok == _Lbrack {
|
||||
// d.Name "[" ...
|
||||
// array/slice type or type parameter list
|
||||
pos := p.pos()
|
||||
|
|
@ -762,7 +759,7 @@ func (p *parser) funcDeclOrNil() *FuncDecl {
|
|||
f.Name = p.name()
|
||||
|
||||
context := ""
|
||||
if f.Recv != nil && p.mode&AllowMethodTypeParams == 0 {
|
||||
if f.Recv != nil {
|
||||
context = "method" // don't permit (method) type parameters in funcType
|
||||
}
|
||||
f.TParamList, f.Type = p.funcType(context)
|
||||
|
|
@ -1024,22 +1021,24 @@ func (p *parser) operand(keep_parens bool) Expr {
|
|||
// as well (operand is only called from pexpr).
|
||||
}
|
||||
|
||||
// PrimaryExpr =
|
||||
// Operand |
|
||||
// Conversion |
|
||||
// PrimaryExpr Selector |
|
||||
// PrimaryExpr Index |
|
||||
// PrimaryExpr Slice |
|
||||
// PrimaryExpr TypeAssertion |
|
||||
// PrimaryExpr Arguments .
|
||||
// pexpr parses a PrimaryExpr.
|
||||
//
|
||||
// Selector = "." identifier .
|
||||
// Index = "[" Expression "]" .
|
||||
// Slice = "[" ( [ Expression ] ":" [ Expression ] ) |
|
||||
// ( [ Expression ] ":" Expression ":" Expression )
|
||||
// "]" .
|
||||
// TypeAssertion = "." "(" Type ")" .
|
||||
// Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
|
||||
// PrimaryExpr =
|
||||
// Operand |
|
||||
// Conversion |
|
||||
// PrimaryExpr Selector |
|
||||
// PrimaryExpr Index |
|
||||
// PrimaryExpr Slice |
|
||||
// PrimaryExpr TypeAssertion |
|
||||
// PrimaryExpr Arguments .
|
||||
//
|
||||
// Selector = "." identifier .
|
||||
// Index = "[" Expression "]" .
|
||||
// Slice = "[" ( [ Expression ] ":" [ Expression ] ) |
|
||||
// ( [ Expression ] ":" Expression ":" Expression )
|
||||
// "]" .
|
||||
// TypeAssertion = "." "(" Type ")" .
|
||||
// Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
|
||||
func (p *parser) pexpr(x Expr, keep_parens bool) Expr {
|
||||
if trace {
|
||||
defer p.trace("pexpr")()
|
||||
|
|
@ -1098,45 +1097,25 @@ loop:
|
|||
|
||||
var i Expr
|
||||
if p.tok != _Colon {
|
||||
if p.mode&AllowGenerics == 0 {
|
||||
p.xnest++
|
||||
i = p.expr()
|
||||
p.xnest--
|
||||
if p.got(_Rbrack) {
|
||||
// x[i]
|
||||
t := new(IndexExpr)
|
||||
t.pos = pos
|
||||
t.X = x
|
||||
t.Index = i
|
||||
x = t
|
||||
break
|
||||
}
|
||||
} else {
|
||||
var comma bool
|
||||
i, comma = p.typeList()
|
||||
if comma || p.tok == _Rbrack {
|
||||
p.want(_Rbrack)
|
||||
// x[i,] or x[i, j, ...]
|
||||
t := new(IndexExpr)
|
||||
t.pos = pos
|
||||
t.X = x
|
||||
t.Index = i
|
||||
x = t
|
||||
break
|
||||
}
|
||||
var comma bool
|
||||
i, comma = p.typeList()
|
||||
if comma || p.tok == _Rbrack {
|
||||
p.want(_Rbrack)
|
||||
// x[i,] or x[i, j, ...]
|
||||
t := new(IndexExpr)
|
||||
t.pos = pos
|
||||
t.X = x
|
||||
t.Index = i
|
||||
x = t
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// x[i:...
|
||||
// For better error message, don't simply use p.want(_Colon) here (issue #47704).
|
||||
if !p.got(_Colon) {
|
||||
if p.mode&AllowGenerics == 0 {
|
||||
p.syntaxError("expecting : or ]")
|
||||
p.advance(_Colon, _Rbrack)
|
||||
} else {
|
||||
p.syntaxError("expecting comma, : or ]")
|
||||
p.advance(_Comma, _Colon, _Rbrack)
|
||||
}
|
||||
p.syntaxError("expecting comma, : or ]")
|
||||
p.advance(_Comma, _Colon, _Rbrack)
|
||||
}
|
||||
p.xnest++
|
||||
t := new(SliceExpr)
|
||||
|
|
@ -1255,7 +1234,7 @@ func (p *parser) complitexpr() *CompositeLit {
|
|||
|
||||
p.xnest++
|
||||
p.want(_Lbrace)
|
||||
x.Rbrace = p.list(_Comma, _Rbrace, func() bool {
|
||||
x.Rbrace = p.list("composite literal", _Comma, _Rbrace, func() bool {
|
||||
// value
|
||||
e := p.bare_complitexpr()
|
||||
if p.tok == _Colon {
|
||||
|
|
@ -1305,10 +1284,10 @@ func newIndirect(pos Pos, typ Expr) Expr {
|
|||
// typeOrNil is like type_ but it returns nil if there was no type
|
||||
// instead of reporting an error.
|
||||
//
|
||||
// Type = TypeName | TypeLit | "(" Type ")" .
|
||||
// TypeName = identifier | QualifiedIdent .
|
||||
// TypeLit = ArrayType | StructType | PointerType | FunctionType | InterfaceType |
|
||||
// SliceType | MapType | Channel_Type .
|
||||
// Type = TypeName | TypeLit | "(" Type ")" .
|
||||
// TypeName = identifier | QualifiedIdent .
|
||||
// TypeLit = ArrayType | StructType | PointerType | FunctionType | InterfaceType |
|
||||
// SliceType | MapType | Channel_Type .
|
||||
func (p *parser) typeOrNil() Expr {
|
||||
if trace {
|
||||
defer p.trace("typeOrNil")()
|
||||
|
|
@ -1418,7 +1397,7 @@ func (p *parser) funcType(context string) ([]*Field, *FuncType) {
|
|||
typ.pos = p.pos()
|
||||
|
||||
var tparamList []*Field
|
||||
if p.allowGenerics() && p.got(_Lbrack) {
|
||||
if p.got(_Lbrack) {
|
||||
if context != "" {
|
||||
// accept but complain
|
||||
p.syntaxErrorAt(typ.pos, context+" must have no type parameters")
|
||||
|
|
@ -1499,7 +1478,7 @@ func (p *parser) structType() *StructType {
|
|||
|
||||
p.want(_Struct)
|
||||
p.want(_Lbrace)
|
||||
p.list(_Semi, _Rbrace, func() bool {
|
||||
p.list("struct type", _Semi, _Rbrace, func() bool {
|
||||
p.fieldDecl(typ)
|
||||
return false
|
||||
})
|
||||
|
|
@ -1509,7 +1488,6 @@ func (p *parser) structType() *StructType {
|
|||
|
||||
// InterfaceType = "interface" "{" { ( MethodDecl | EmbeddedElem | TypeList ) ";" } "}" .
|
||||
// TypeList = "type" Type { "," Type } .
|
||||
// TODO(gri) remove TypeList syntax if we accept #45346
|
||||
func (p *parser) interfaceType() *InterfaceType {
|
||||
if trace {
|
||||
defer p.trace("interfaceType")()
|
||||
|
|
@ -1520,18 +1498,17 @@ func (p *parser) interfaceType() *InterfaceType {
|
|||
|
||||
p.want(_Interface)
|
||||
p.want(_Lbrace)
|
||||
p.list(_Semi, _Rbrace, func() bool {
|
||||
p.list("interface type", _Semi, _Rbrace, func() bool {
|
||||
switch p.tok {
|
||||
case _Name:
|
||||
f := p.methodDecl()
|
||||
if f.Name == nil && p.allowGenerics() {
|
||||
if f.Name == nil {
|
||||
f = p.embeddedElem(f)
|
||||
}
|
||||
typ.MethodList = append(typ.MethodList, f)
|
||||
return false
|
||||
|
||||
case _Lparen:
|
||||
// TODO(gri) Need to decide how to adjust this restriction.
|
||||
p.syntaxError("cannot parenthesize embedded type")
|
||||
f := new(Field)
|
||||
f.pos = p.pos()
|
||||
|
|
@ -1542,31 +1519,23 @@ func (p *parser) interfaceType() *InterfaceType {
|
|||
return false
|
||||
|
||||
case _Operator:
|
||||
if p.op == Tilde && p.allowGenerics() {
|
||||
if p.op == Tilde {
|
||||
typ.MethodList = append(typ.MethodList, p.embeddedElem(nil))
|
||||
return false
|
||||
}
|
||||
|
||||
default:
|
||||
if p.allowGenerics() {
|
||||
pos := p.pos()
|
||||
if t := p.typeOrNil(); t != nil {
|
||||
f := new(Field)
|
||||
f.pos = pos
|
||||
f.Type = t
|
||||
typ.MethodList = append(typ.MethodList, p.embeddedElem(f))
|
||||
return false
|
||||
}
|
||||
pos := p.pos()
|
||||
if t := p.typeOrNil(); t != nil {
|
||||
f := new(Field)
|
||||
f.pos = pos
|
||||
f.Type = t
|
||||
typ.MethodList = append(typ.MethodList, p.embeddedElem(f))
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if p.allowGenerics() {
|
||||
p.syntaxError("expecting method or embedded element")
|
||||
p.advance(_Semi, _Rbrace)
|
||||
return false
|
||||
}
|
||||
|
||||
p.syntaxError("expecting method or interface name")
|
||||
p.syntaxError("expecting method or embedded element")
|
||||
p.advance(_Semi, _Rbrace)
|
||||
return false
|
||||
})
|
||||
|
|
@ -1640,7 +1609,7 @@ func (p *parser) fieldDecl(styp *StructType) {
|
|||
|
||||
// Careful dance: We don't know if we have an embedded instantiated
|
||||
// type T[P1, P2, ...] or a field T of array/slice type [P]E or []E.
|
||||
if p.allowGenerics() && len(names) == 1 && p.tok == _Lbrack {
|
||||
if len(names) == 1 && p.tok == _Lbrack {
|
||||
typ = p.arrayOrTArgs()
|
||||
if typ, ok := typ.(*IndexExpr); ok {
|
||||
// embedded type T[P1, P2, ...]
|
||||
|
|
@ -1757,20 +1726,6 @@ func (p *parser) methodDecl() *Field {
|
|||
f.pos = p.pos()
|
||||
name := p.name()
|
||||
|
||||
// accept potential name list but complain
|
||||
// TODO(gri) We probably don't need this special check anymore.
|
||||
// Nobody writes this kind of code. It's from ancient
|
||||
// Go beginnings.
|
||||
hasNameList := false
|
||||
for p.got(_Comma) {
|
||||
p.name()
|
||||
hasNameList = true
|
||||
}
|
||||
if hasNameList {
|
||||
p.syntaxError("name list not allowed in interface type")
|
||||
// already progressed, no need to advance
|
||||
}
|
||||
|
||||
const context = "interface method"
|
||||
|
||||
switch p.tok {
|
||||
|
|
@ -1780,79 +1735,72 @@ func (p *parser) methodDecl() *Field {
|
|||
_, f.Type = p.funcType(context)
|
||||
|
||||
case _Lbrack:
|
||||
if p.allowGenerics() {
|
||||
// Careful dance: We don't know if we have a generic method m[T C](x T)
|
||||
// or an embedded instantiated type T[P1, P2] (we accept generic methods
|
||||
// for generality and robustness of parsing).
|
||||
// Careful dance: We don't know if we have a generic method m[T C](x T)
|
||||
// or an embedded instantiated type T[P1, P2] (we accept generic methods
|
||||
// for generality and robustness of parsing but complain with an error).
|
||||
pos := p.pos()
|
||||
p.next()
|
||||
|
||||
// Empty type parameter or argument lists are not permitted.
|
||||
// Treat as if [] were absent.
|
||||
if p.tok == _Rbrack {
|
||||
// name[]
|
||||
pos := p.pos()
|
||||
p.next()
|
||||
|
||||
// Empty type parameter or argument lists are not permitted.
|
||||
// Treat as if [] were absent.
|
||||
if p.tok == _Rbrack {
|
||||
// name[]
|
||||
pos := p.pos()
|
||||
p.next()
|
||||
if p.tok == _Lparen {
|
||||
// name[](
|
||||
p.errorAt(pos, "empty type parameter list")
|
||||
f.Name = name
|
||||
_, f.Type = p.funcType(context)
|
||||
} else {
|
||||
p.errorAt(pos, "empty type argument list")
|
||||
f.Type = name
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// A type argument list looks like a parameter list with only
|
||||
// types. Parse a parameter list and decide afterwards.
|
||||
list := p.paramList(nil, nil, _Rbrack, false)
|
||||
if len(list) == 0 {
|
||||
// The type parameter list is not [] but we got nothing
|
||||
// due to other errors (reported by paramList). Treat
|
||||
// as if [] were absent.
|
||||
if p.tok == _Lparen {
|
||||
f.Name = name
|
||||
_, f.Type = p.funcType(context)
|
||||
} else {
|
||||
f.Type = name
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// len(list) > 0
|
||||
if list[0].Name != nil {
|
||||
// generic method
|
||||
if p.tok == _Lparen {
|
||||
// name[](
|
||||
p.errorAt(pos, "empty type parameter list")
|
||||
f.Name = name
|
||||
_, f.Type = p.funcType(context)
|
||||
// TODO(gri) Record list as type parameter list with f.Type
|
||||
// if we want to type-check the generic method.
|
||||
// For now, report an error so this is not a silent event.
|
||||
p.errorAt(pos, "interface method must have no type parameters")
|
||||
break
|
||||
}
|
||||
|
||||
// embedded instantiated type
|
||||
t := new(IndexExpr)
|
||||
t.pos = pos
|
||||
t.X = name
|
||||
if len(list) == 1 {
|
||||
t.Index = list[0].Type
|
||||
} else {
|
||||
// len(list) > 1
|
||||
l := new(ListExpr)
|
||||
l.pos = list[0].Pos()
|
||||
l.ElemList = make([]Expr, len(list))
|
||||
for i := range list {
|
||||
l.ElemList[i] = list[i].Type
|
||||
}
|
||||
t.Index = l
|
||||
p.errorAt(pos, "empty type argument list")
|
||||
f.Type = name
|
||||
}
|
||||
f.Type = t
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
|
||||
// A type argument list looks like a parameter list with only
|
||||
// types. Parse a parameter list and decide afterwards.
|
||||
list := p.paramList(nil, nil, _Rbrack, false)
|
||||
if len(list) == 0 {
|
||||
// The type parameter list is not [] but we got nothing
|
||||
// due to other errors (reported by paramList). Treat
|
||||
// as if [] were absent.
|
||||
if p.tok == _Lparen {
|
||||
f.Name = name
|
||||
_, f.Type = p.funcType(context)
|
||||
} else {
|
||||
f.Type = name
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// len(list) > 0
|
||||
if list[0].Name != nil {
|
||||
// generic method
|
||||
f.Name = name
|
||||
_, f.Type = p.funcType(context)
|
||||
p.errorAt(pos, "interface method must have no type parameters")
|
||||
break
|
||||
}
|
||||
|
||||
// embedded instantiated type
|
||||
t := new(IndexExpr)
|
||||
t.pos = pos
|
||||
t.X = name
|
||||
if len(list) == 1 {
|
||||
t.Index = list[0].Type
|
||||
} else {
|
||||
// len(list) > 1
|
||||
l := new(ListExpr)
|
||||
l.pos = list[0].Pos()
|
||||
l.ElemList = make([]Expr, len(list))
|
||||
for i := range list {
|
||||
l.ElemList[i] = list[i].Type
|
||||
}
|
||||
t.Index = l
|
||||
}
|
||||
f.Type = t
|
||||
|
||||
default:
|
||||
// embedded type
|
||||
|
|
@ -1938,7 +1886,7 @@ func (p *parser) paramDeclOrNil(name *Name, follow token) *Field {
|
|||
name = p.name()
|
||||
}
|
||||
|
||||
if p.allowGenerics() && p.tok == _Lbrack {
|
||||
if p.tok == _Lbrack {
|
||||
// name "[" ...
|
||||
f.Type = p.arrayOrTArgs()
|
||||
if typ, ok := f.Type.(*IndexExpr); ok {
|
||||
|
|
@ -2033,7 +1981,7 @@ func (p *parser) paramList(name *Name, typ Expr, close token, requireNames bool)
|
|||
|
||||
var named int // number of parameters that have an explicit name and type
|
||||
var typed int // number of parameters that have an explicit type
|
||||
end := p.list(_Comma, close, func() bool {
|
||||
end := p.list("parameter list", _Comma, close, func() bool {
|
||||
var par *Field
|
||||
if typ != nil {
|
||||
if debug && name == nil {
|
||||
|
|
@ -2572,11 +2520,13 @@ func (p *parser) commClause() *CommClause {
|
|||
return c
|
||||
}
|
||||
|
||||
// Statement =
|
||||
// Declaration | LabeledStmt | SimpleStmt |
|
||||
// GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt |
|
||||
// FallthroughStmt | Block | IfStmt | SwitchStmt | SelectStmt | ForStmt |
|
||||
// DeferStmt .
|
||||
// stmtOrNil parses a statement if one is present, or else returns nil.
|
||||
//
|
||||
// Statement =
|
||||
// Declaration | LabeledStmt | SimpleStmt |
|
||||
// GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt |
|
||||
// FallthroughStmt | Block | IfStmt | SwitchStmt | SelectStmt | ForStmt |
|
||||
// DeferStmt .
|
||||
func (p *parser) stmtOrNil() Stmt {
|
||||
if trace {
|
||||
defer p.trace("stmt " + p.tok.String())()
|
||||
|
|
@ -2713,7 +2663,7 @@ func (p *parser) argList() (list []Expr, hasDots bool) {
|
|||
}
|
||||
|
||||
p.xnest++
|
||||
p.list(_Comma, _Rparen, func() bool {
|
||||
p.list("argument list", _Comma, _Rparen, func() bool {
|
||||
list = append(list, p.expr())
|
||||
hasDots = p.got(_DotDotDot)
|
||||
return hasDots
|
||||
|
|
@ -2787,7 +2737,7 @@ func (p *parser) qualifiedName(name *Name) Expr {
|
|||
x = s
|
||||
}
|
||||
|
||||
if p.allowGenerics() && p.tok == _Lbrack {
|
||||
if p.tok == _Lbrack {
|
||||
x = p.typeInstance(x)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,31 +27,17 @@ var (
|
|||
)
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
ParseFile(*src_, func(err error) { t.Error(err) }, nil, AllowGenerics)
|
||||
ParseFile(*src_, func(err error) { t.Error(err) }, nil, 0)
|
||||
}
|
||||
|
||||
func TestVerify(t *testing.T) {
|
||||
ast, err := ParseFile(*src_, func(err error) { t.Error(err) }, nil, AllowGenerics)
|
||||
ast, err := ParseFile(*src_, func(err error) { t.Error(err) }, nil, 0)
|
||||
if err != nil {
|
||||
return // error already reported
|
||||
}
|
||||
verifyPrint(t, *src_, ast)
|
||||
}
|
||||
|
||||
func TestParseGo2(t *testing.T) {
|
||||
dir := filepath.Join(testdata, "go2")
|
||||
list, err := ioutil.ReadDir(dir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, fi := range list {
|
||||
name := fi.Name()
|
||||
if !fi.IsDir() && !strings.HasPrefix(name, ".") {
|
||||
ParseFile(filepath.Join(dir, name), func(err error) { t.Error(err) }, nil, AllowGenerics|AllowMethodTypeParams)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStdLib(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode")
|
||||
|
|
@ -94,7 +80,7 @@ func TestStdLib(t *testing.T) {
|
|||
if debug {
|
||||
fmt.Printf("parsing %s\n", filename)
|
||||
}
|
||||
ast, err := ParseFile(filename, nil, nil, AllowGenerics)
|
||||
ast, err := ParseFile(filename, nil, nil, 0)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ type Pos struct {
|
|||
func MakePos(base *PosBase, line, col uint) Pos { return Pos{base, sat32(line), sat32(col)} }
|
||||
|
||||
// TODO(gri) IsKnown makes an assumption about linebase < 1.
|
||||
// Maybe we should check for Base() != nil instead.
|
||||
// Maybe we should check for Base() != nil instead.
|
||||
|
||||
func (pos Pos) Pos() Pos { return pos }
|
||||
func (pos Pos) IsKnown() bool { return pos.line > 0 }
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ func TestPrint(t *testing.T) {
|
|||
t.Skip("skipping test in short mode")
|
||||
}
|
||||
|
||||
ast, _ := ParseFile(*src_, func(err error) { t.Error(err) }, nil, AllowGenerics)
|
||||
ast, _ := ParseFile(*src_, func(err error) { t.Error(err) }, nil, 0)
|
||||
|
||||
if ast != nil {
|
||||
Fprint(testOut(), ast, LineForm)
|
||||
|
|
@ -117,7 +117,7 @@ var stringTests = [][2]string{
|
|||
|
||||
func TestPrintString(t *testing.T) {
|
||||
for _, test := range stringTests {
|
||||
ast, err := Parse(nil, strings.NewReader(test[0]), nil, nil, AllowGenerics)
|
||||
ast, err := Parse(nil, strings.NewReader(test[0]), nil, nil, 0)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
|
|
@ -237,7 +237,7 @@ var exprTests = [][2]string{
|
|||
func TestShortString(t *testing.T) {
|
||||
for _, test := range exprTests {
|
||||
src := "package p; var _ = " + test[0]
|
||||
ast, err := Parse(nil, strings.NewReader(src), nil, nil, AllowGenerics)
|
||||
ast, err := Parse(nil, strings.NewReader(src), nil, nil, 0)
|
||||
if err != nil {
|
||||
t.Errorf("%s: %s", test[0], err)
|
||||
continue
|
||||
|
|
|
|||
|
|
@ -16,8 +16,6 @@ type Mode uint
|
|||
// Modes supported by the parser.
|
||||
const (
|
||||
CheckBranches Mode = 1 << iota // check correct use of labels, break, continue, and goto statements
|
||||
AllowGenerics
|
||||
AllowMethodTypeParams // does not support interface methods yet; ignored if AllowGenerics is not set
|
||||
)
|
||||
|
||||
// Error describes a syntax error. Error implements the error interface.
|
||||
|
|
@ -65,7 +63,6 @@ type PragmaHandler func(pos Pos, blank bool, text string, current Pragma) Pragma
|
|||
// error, and the returned syntax tree is nil.
|
||||
//
|
||||
// If pragh != nil, it is called with each pragma encountered.
|
||||
//
|
||||
func Parse(base *PosBase, src io.Reader, errh ErrorHandler, pragh PragmaHandler, mode Mode) (_ *File, first error) {
|
||||
defer func() {
|
||||
if p := recover(); p != nil {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// Copyright 2022 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 chans
|
||||
|
||||
import "runtime"
|
||||
|
|
@ -22,7 +26,7 @@ func Ranger[T any]() (*Sender[T], *Receiver[T]) {
|
|||
// A sender is used to send values to a Receiver.
|
||||
type Sender[T any] struct {
|
||||
values chan<- T
|
||||
done <-chan bool
|
||||
done <-chan bool
|
||||
}
|
||||
|
||||
// Send sends a value to the receiver. It returns whether any more
|
||||
|
|
@ -45,7 +49,7 @@ func (s *Sender[T]) Close() {
|
|||
// A Receiver receives values from a Sender.
|
||||
type Receiver[T any] struct {
|
||||
values <-chan T
|
||||
done chan<- bool
|
||||
done chan<- bool
|
||||
}
|
||||
|
||||
// Next returns the next value from the channel. The bool result
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
type myInt int
|
||||
|
||||
// Parameterized type declarations
|
||||
|
||||
type T1[P any] P
|
||||
|
||||
type T2[P any] struct {
|
||||
f P
|
||||
g int // int should still be in scope chain
|
||||
}
|
||||
|
||||
type List[P any] []P
|
||||
|
||||
// Alias type declarations cannot have type parameters. Syntax error.
|
||||
// TODO(gri) Disabled for now as we don't check syntax error here.
|
||||
// type A1[P any] = /* ERROR cannot be alias */ P
|
||||
|
||||
// But an alias may refer to a generic, uninstantiated type.
|
||||
type A2 = List
|
||||
var _ A2[int]
|
||||
var _ A2 /* ERROR without instantiation */
|
||||
|
||||
type A3 = List[int]
|
||||
var _ A3
|
||||
|
||||
// Parameterized type instantiations
|
||||
|
||||
var x int
|
||||
type _ x /* ERROR not a type */ [int]
|
||||
|
||||
type _ int /* ERROR not a generic type */ [int]
|
||||
type _ myInt /* ERROR not a generic type */ [int]
|
||||
|
||||
// TODO(gri) better error messages
|
||||
type _ T1[int]
|
||||
type _ T1[x /* ERROR not a type */ ]
|
||||
type _ T1 /* ERROR got 2 arguments but 1 type parameters */ [int, float32]
|
||||
|
||||
var _ T2[int] = T2[int]{}
|
||||
|
||||
var _ List[int] = []int{1, 2, 3}
|
||||
var _ List[[]int] = [][]int{{1, 2, 3}}
|
||||
var _ List[List[List[int]]]
|
||||
|
||||
// Parameterized types containing parameterized types
|
||||
|
||||
type T3[P any] List[P]
|
||||
|
||||
var _ T3[int] = T3[int](List[int]{1, 2, 3})
|
||||
|
||||
// Self-recursive generic types are not permitted
|
||||
|
||||
type self1[P any] self1 /* ERROR illegal cycle */ [P]
|
||||
type self2[P any] *self2[P] // this is ok
|
||||
|
|
@ -1,232 +0,0 @@
|
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
type List[E any] []E
|
||||
var _ List[List[List[int]]]
|
||||
var _ List[List[List[int]]] = []List[List[int]]{}
|
||||
|
||||
type (
|
||||
T1[P1 any] struct {
|
||||
f1 T2[P1, float32]
|
||||
}
|
||||
|
||||
T2[P2, P3 any] struct {
|
||||
f2 P2
|
||||
f3 P3
|
||||
}
|
||||
)
|
||||
|
||||
func _() {
|
||||
var x1 T1[int]
|
||||
var x2 T2[int, float32]
|
||||
|
||||
x1.f1.f2 = 0
|
||||
x1.f1 = x2
|
||||
}
|
||||
|
||||
type T3[P any] T1[T2[P, P]]
|
||||
|
||||
func _() {
|
||||
var x1 T3[int]
|
||||
var x2 T2[int, int]
|
||||
x1.f1.f2 = x2
|
||||
}
|
||||
|
||||
func f[P any] (x P) List[P] {
|
||||
return List[P]{x}
|
||||
}
|
||||
|
||||
var (
|
||||
_ []int = f(0)
|
||||
_ []float32 = f[float32](10)
|
||||
_ List[complex128] = f(1i)
|
||||
_ []List[int] = f(List[int]{})
|
||||
_ List[List[int]] = []List[int]{}
|
||||
_ = []List[int]{}
|
||||
)
|
||||
|
||||
// Parameterized types with methods
|
||||
|
||||
func (l List[E]) Head() (_ E, _ bool) {
|
||||
if len(l) > 0 {
|
||||
return l[0], true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// A test case for instantiating types with other types (extracted from map.go2)
|
||||
|
||||
type Pair[K any] struct {
|
||||
key K
|
||||
}
|
||||
|
||||
type Receiver[T any] struct {
|
||||
values T
|
||||
}
|
||||
|
||||
type Iterator[K any] struct {
|
||||
r Receiver[Pair[K]]
|
||||
}
|
||||
|
||||
func Values [T any] (r Receiver[T]) T {
|
||||
return r.values
|
||||
}
|
||||
|
||||
func (it Iterator[K]) Next() K {
|
||||
return Values[Pair[K]](it.r).key
|
||||
}
|
||||
|
||||
// A more complex test case testing type bounds (extracted from linalg.go2 and reduced to essence)
|
||||
|
||||
type NumericAbs[T any] interface {
|
||||
Abs() T
|
||||
}
|
||||
|
||||
func AbsDifference[T NumericAbs[T]](x T)
|
||||
|
||||
type OrderedAbs[T any] T
|
||||
|
||||
func (a OrderedAbs[T]) Abs() OrderedAbs[T]
|
||||
|
||||
func OrderedAbsDifference[T any](x T) {
|
||||
AbsDifference(OrderedAbs[T](x))
|
||||
}
|
||||
|
||||
// same code, reduced to essence
|
||||
|
||||
func g[P interface{ m() P }](x P)
|
||||
|
||||
type T4[P any] P
|
||||
|
||||
func (_ T4[P]) m() T4[P]
|
||||
|
||||
func _[Q any](x Q) {
|
||||
g(T4[Q](x))
|
||||
}
|
||||
|
||||
// Another test case that caused problems in the past
|
||||
|
||||
type T5[_ interface { a() }, _ interface{}] struct{}
|
||||
|
||||
type A[P any] struct{ x P }
|
||||
|
||||
func (_ A[P]) a() {}
|
||||
|
||||
var _ T5[A[int], int]
|
||||
|
||||
// Invoking methods with parameterized receiver types uses
|
||||
// type inference to determine the actual type arguments matching
|
||||
// the receiver type parameters from the actual receiver argument.
|
||||
// Go does implicit address-taking and dereferenciation depending
|
||||
// on the actual receiver and the method's receiver type. To make
|
||||
// type inference work, the type-checker matches "pointer-ness"
|
||||
// of the actual receiver and the method's receiver type.
|
||||
// The following code tests this mechanism.
|
||||
|
||||
type R1[A any] struct{}
|
||||
func (_ R1[A]) vm()
|
||||
func (_ *R1[A]) pm()
|
||||
|
||||
func _[T any](r R1[T], p *R1[T]) {
|
||||
r.vm()
|
||||
r.pm()
|
||||
p.vm()
|
||||
p.pm()
|
||||
}
|
||||
|
||||
type R2[A, B any] struct{}
|
||||
func (_ R2[A, B]) vm()
|
||||
func (_ *R2[A, B]) pm()
|
||||
|
||||
func _[T any](r R2[T, int], p *R2[string, T]) {
|
||||
r.vm()
|
||||
r.pm()
|
||||
p.vm()
|
||||
p.pm()
|
||||
}
|
||||
|
||||
// Interface type constraints can contain any type, incl. *Named types.
|
||||
// Verify that we use the underlying type to compute the operational type.
|
||||
type MyInt int
|
||||
func add1[T interface{ ~MyInt }](x T) T {
|
||||
return x + 1
|
||||
}
|
||||
|
||||
type MyString string
|
||||
func double[T interface{ ~MyInt | ~MyString }](x T) T {
|
||||
return x + x
|
||||
}
|
||||
|
||||
// Embedding of interfaces with type constraints leads to interfaces
|
||||
// with type constraints that are the intersection of the embedded
|
||||
// type constraints.
|
||||
|
||||
type E0 interface {
|
||||
~int | ~bool | ~string
|
||||
}
|
||||
|
||||
type E1 interface {
|
||||
~int | ~float64 | ~string
|
||||
}
|
||||
|
||||
type E2 interface {
|
||||
~float64
|
||||
}
|
||||
|
||||
type I0 interface {
|
||||
E0
|
||||
}
|
||||
|
||||
func f0[T I0]()
|
||||
var _ = f0[int]
|
||||
var _ = f0[bool]
|
||||
var _ = f0[string]
|
||||
var _ = f0[float64 /* ERROR does not satisfy I0 */ ]
|
||||
|
||||
type I01 interface {
|
||||
E0
|
||||
E1
|
||||
}
|
||||
|
||||
func f01[T I01]()
|
||||
var _ = f01[int]
|
||||
var _ = f01[bool /* ERROR does not satisfy I0 */ ]
|
||||
var _ = f01[string]
|
||||
var _ = f01[float64 /* ERROR does not satisfy I0 */ ]
|
||||
|
||||
type I012 interface {
|
||||
E0
|
||||
E1
|
||||
E2
|
||||
}
|
||||
|
||||
func f012[T I012]()
|
||||
var _ = f012[int /* ERROR does not satisfy I012 */ ]
|
||||
var _ = f012[bool /* ERROR does not satisfy I012 */ ]
|
||||
var _ = f012[string /* ERROR does not satisfy I012 */ ]
|
||||
var _ = f012[float64 /* ERROR does not satisfy I012 */ ]
|
||||
|
||||
type I12 interface {
|
||||
E1
|
||||
E2
|
||||
}
|
||||
|
||||
func f12[T I12]()
|
||||
var _ = f12[int /* ERROR does not satisfy I12 */ ]
|
||||
var _ = f12[bool /* ERROR does not satisfy I12 */ ]
|
||||
var _ = f12[string /* ERROR does not satisfy I12 */ ]
|
||||
var _ = f12[float64]
|
||||
|
||||
type I0_ interface {
|
||||
E0
|
||||
~int
|
||||
}
|
||||
|
||||
func f0_[T I0_]()
|
||||
var _ = f0_[int]
|
||||
var _ = f0_[bool /* ERROR does not satisfy I0_ */ ]
|
||||
var _ = f0_[string /* ERROR does not satisfy I0_ */ ]
|
||||
var _ = f0_[float64 /* ERROR does not satisfy I0_ */ ]
|
||||
|
|
@ -1,451 +0,0 @@
|
|||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
// import "io" // for type assertion tests
|
||||
|
||||
// The predeclared identifier "any" is only visible as a constraint
|
||||
// in a type parameter list.
|
||||
var _ any // ERROR undeclared
|
||||
func _[_ any /* ok here */ , _ interface{any /* ERROR undeclared */ }](any /* ERROR undeclared */ ) {
|
||||
var _ any /* ERROR undeclared */
|
||||
}
|
||||
|
||||
func identity[T any](x T) T { return x }
|
||||
|
||||
func _[_ any](x int) int
|
||||
func _[T any](T /* ERROR redeclared */ T)()
|
||||
func _[T, T /* ERROR redeclared */ any]()
|
||||
|
||||
func reverse[T any](list []T) []T {
|
||||
rlist := make([]T, len(list))
|
||||
i := len(list)
|
||||
for _, x := range list {
|
||||
i--
|
||||
rlist[i] = x
|
||||
}
|
||||
return rlist
|
||||
}
|
||||
|
||||
var _ = reverse /* ERROR cannot use generic function reverse */
|
||||
var _ = reverse[int, float32 /* ERROR got 2 type arguments */ ] ([]int{1, 2, 3})
|
||||
var _ = reverse[int]([ /* ERROR cannot use */ ]float32{1, 2, 3})
|
||||
var f = reverse[chan int]
|
||||
var _ = f(0 /* ERROR cannot convert 0 .* to \[\]chan int */ )
|
||||
|
||||
func swap[A, B any](a A, b B) (B, A) { return b, a }
|
||||
|
||||
var _ = swap /* ERROR single value is expected */ [int, float32](1, 2)
|
||||
var f32, i = swap[int, float32](swap(float32, int)(1, 2))
|
||||
var _ float32 = f32
|
||||
var _ int = i
|
||||
|
||||
func swapswap[A, B any](a A, b B) (A, B) {
|
||||
return swap[B, A](b, a)
|
||||
}
|
||||
|
||||
type F[A, B any] func(A, B) (B, A)
|
||||
|
||||
func min[T interface{ ~int }](x, y T) T {
|
||||
if x < y {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
}
|
||||
|
||||
func _[T interface{ ~int | ~float32 }](x, y T) bool { return x < y }
|
||||
func _[T any](x, y T) bool { return x /* ERROR cannot compare */ < y }
|
||||
func _[T interface{ ~int | ~float32 | ~bool }](x, y T) bool { return x /* ERROR cannot compare */ < y }
|
||||
|
||||
func _[T C1[T]](x, y T) bool { return x /* ERROR cannot compare */ < y }
|
||||
func _[T C2[T]](x, y T) bool { return x < y }
|
||||
|
||||
type C1[T any] interface{}
|
||||
type C2[T any] interface{ ~int | ~float32 }
|
||||
|
||||
func new[T any]() *T {
|
||||
var x T
|
||||
return &x
|
||||
}
|
||||
|
||||
var _ = new /* ERROR cannot use generic function new */
|
||||
var _ *int = new[int]()
|
||||
|
||||
func _[T any](map[T /* ERROR invalid map key type T \(missing comparable constraint\) */]int) // w/o constraint we don't know if T is comparable
|
||||
|
||||
func f1[T1 any](struct{T1}) int
|
||||
var _ = f1(int)(struct{T1}{})
|
||||
type T1 = int
|
||||
|
||||
func f2[t1 any](struct{t1; x float32}) int
|
||||
var _ = f2(t1)(struct{t1; x float32}{})
|
||||
type t1 = int
|
||||
|
||||
|
||||
func f3[A, B, C any](A, struct{x B}, func(A, struct{x B}, *C)) int
|
||||
|
||||
var _ = f3[int, rune, bool](1, struct{x rune}{}, nil)
|
||||
|
||||
// indexing
|
||||
|
||||
func _[T any] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] }
|
||||
func _[T interface{ ~int }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] }
|
||||
func _[T interface{ ~string }] (x T, i int) { _ = x[i] }
|
||||
func _[T interface{ ~[]int }] (x T, i int) { _ = x[i] }
|
||||
func _[T interface{ ~[10]int | ~*[20]int | ~map[string]int }] (x T, i int) { _ = x[i] }
|
||||
func _[T interface{ ~string | ~[]byte }] (x T, i int) { _ = x[i] }
|
||||
func _[T interface{ ~[]int | ~[1]rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] }
|
||||
func _[T interface{ ~string | ~[]rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] }
|
||||
|
||||
// slicing
|
||||
// TODO(gri) implement this
|
||||
|
||||
func _[T interface{ ~string }] (x T, i, j, k int) { _ = x /* ERROR invalid operation */ [i:j:k] }
|
||||
|
||||
// len/cap built-ins
|
||||
|
||||
func _[T any](x T) { _ = len(x /* ERROR invalid argument */ ) }
|
||||
func _[T interface{ ~int }](x T) { _ = len(x /* ERROR invalid argument */ ) }
|
||||
func _[T interface{ ~string | ~[]byte | ~int }](x T) { _ = len(x /* ERROR invalid argument */ ) }
|
||||
func _[T interface{ ~string }](x T) { _ = len(x) }
|
||||
func _[T interface{ ~[10]int }](x T) { _ = len(x) }
|
||||
func _[T interface{ ~[]byte }](x T) { _ = len(x) }
|
||||
func _[T interface{ ~map[int]int }](x T) { _ = len(x) }
|
||||
func _[T interface{ ~chan int }](x T) { _ = len(x) }
|
||||
func _[T interface{ ~string | ~[]byte | ~chan int }](x T) { _ = len(x) }
|
||||
|
||||
func _[T any](x T) { _ = cap(x /* ERROR invalid argument */ ) }
|
||||
func _[T interface{ ~int }](x T) { _ = cap(x /* ERROR invalid argument */ ) }
|
||||
func _[T interface{ ~string | ~[]byte | ~int }](x T) { _ = cap(x /* ERROR invalid argument */ ) }
|
||||
func _[T interface{ ~string }](x T) { _ = cap(x /* ERROR invalid argument */ ) }
|
||||
func _[T interface{ ~[10]int }](x T) { _ = cap(x) }
|
||||
func _[T interface{ ~[]byte }](x T) { _ = cap(x) }
|
||||
func _[T interface{ ~map[int]int }](x T) { _ = cap(x /* ERROR invalid argument */ ) }
|
||||
func _[T interface{ ~chan int }](x T) { _ = cap(x) }
|
||||
func _[T interface{ ~[]byte | ~chan int }](x T) { _ = cap(x) }
|
||||
|
||||
// range iteration
|
||||
|
||||
func _[T interface{}](x T) {
|
||||
for range x /* ERROR cannot range */ {}
|
||||
}
|
||||
|
||||
func _[T interface{ ~string | ~[]string }](x T) {
|
||||
for range x {}
|
||||
for i := range x { _ = i }
|
||||
for i, _ := range x { _ = i }
|
||||
for i, e := range x /* ERROR must have the same element type */ { _ = i }
|
||||
for _, e := range x /* ERROR must have the same element type */ {}
|
||||
var e rune
|
||||
_ = e
|
||||
for _, (e) = range x /* ERROR must have the same element type */ {}
|
||||
}
|
||||
|
||||
|
||||
func _[T interface{ ~string | ~[]rune | ~map[int]rune }](x T) {
|
||||
for _, e := range x { _ = e }
|
||||
for i, e := range x { _ = i; _ = e }
|
||||
}
|
||||
|
||||
func _[T interface{ ~string | ~[]rune | ~map[string]rune }](x T) {
|
||||
for _, e := range x { _ = e }
|
||||
for i, e := range x /* ERROR must have the same key type */ { _ = e }
|
||||
}
|
||||
|
||||
func _[T interface{ ~string | ~chan int }](x T) {
|
||||
for range x {}
|
||||
for i := range x { _ = i }
|
||||
for i, _ := range x { _ = i } // TODO(gri) should get an error here: channels only return one value
|
||||
}
|
||||
|
||||
func _[T interface{ ~string | ~chan<-int }](x T) {
|
||||
for i := range x /* ERROR send-only channel */ { _ = i }
|
||||
}
|
||||
|
||||
// type inference checks
|
||||
|
||||
var _ = new() /* ERROR cannot infer T */
|
||||
|
||||
func f4[A, B, C any](A, B) C
|
||||
|
||||
var _ = f4(1, 2) /* ERROR cannot infer C */
|
||||
var _ = f4[int, float32, complex128](1, 2)
|
||||
|
||||
func f5[A, B, C any](A, []*B, struct{f []C}) int
|
||||
|
||||
var _ = f5[int, float32, complex128](0, nil, struct{f []complex128}{})
|
||||
var _ = f5(0, nil, struct{f []complex128}{}) // ERROR cannot infer
|
||||
var _ = f5(0, []*float32{new[float32]()}, struct{f []complex128}{})
|
||||
|
||||
func f6[A any](A, []A) int
|
||||
|
||||
var _ = f6(0, nil)
|
||||
|
||||
func f6nil[A any](A) int
|
||||
|
||||
var _ = f6nil(nil) // ERROR cannot infer
|
||||
|
||||
// type inference with variadic functions
|
||||
|
||||
func f7[T any](...T) T
|
||||
|
||||
var _ int = f7() /* ERROR cannot infer T */
|
||||
var _ int = f7(1)
|
||||
var _ int = f7(1, 2)
|
||||
var _ int = f7([]int{}...)
|
||||
var _ int = f7 /* ERROR cannot use */ ([]float64{}...)
|
||||
var _ float64 = f7([]float64{}...)
|
||||
var _ = f7[float64](1, 2.3)
|
||||
var _ = f7(float64(1), 2.3)
|
||||
var _ = f7(1, 2.3 /* ERROR does not match */ )
|
||||
var _ = f7(1.2, 3 /* ERROR does not match */ )
|
||||
|
||||
func f8[A, B any](A, B, ...B) int
|
||||
|
||||
var _ = f8(1) /* ERROR not enough arguments */
|
||||
var _ = f8(1, 2.3)
|
||||
var _ = f8(1, 2.3, 3.4, 4.5)
|
||||
var _ = f8(1, 2.3, 3.4, 4 /* ERROR does not match */ )
|
||||
var _ = f8(int, float64)(1, 2.3, 3.4, 4)
|
||||
|
||||
var _ = f8(int, float64)(0, 0, nil...) // test case for #18268
|
||||
|
||||
// init functions cannot have type parameters
|
||||
|
||||
func init() {}
|
||||
func init[/* ERROR func init must have no type parameters */ _ any]() {}
|
||||
func init[/* ERROR func init must have no type parameters */ P any]() {}
|
||||
|
||||
type T struct {}
|
||||
|
||||
func (T) m1() {}
|
||||
// The type checker accepts method type parameters if configured accordingly.
|
||||
func (T) m2[_ any]() {}
|
||||
func (T) m3[P any]() {}
|
||||
|
||||
// type inference across parameterized types
|
||||
|
||||
type S1[P any] struct { f P }
|
||||
|
||||
func f9[P any](x S1[P])
|
||||
|
||||
func _() {
|
||||
f9[int](S1[int]{42})
|
||||
f9(S1[int]{42})
|
||||
}
|
||||
|
||||
type S2[A, B, C any] struct{}
|
||||
|
||||
func f10[X, Y, Z any](a S2[X, int, Z], b S2[X, Y, bool])
|
||||
|
||||
func _[P any]() {
|
||||
f10[int, float32, string](S2[int, int, string]{}, S2[int, float32, bool]{})
|
||||
f10(S2[int, int, string]{}, S2[int, float32, bool]{})
|
||||
f10(S2[P, int, P]{}, S2[P, float32, bool]{})
|
||||
}
|
||||
|
||||
// corner case for type inference
|
||||
// (was bug: after instanting f11, the type-checker didn't mark f11 as non-generic)
|
||||
|
||||
func f11[T any]()
|
||||
|
||||
func _() {
|
||||
f11[int]()
|
||||
}
|
||||
|
||||
// the previous example was extracted from
|
||||
|
||||
func f12[T interface{m() T}]()
|
||||
|
||||
type A[T any] T
|
||||
|
||||
func (a A[T]) m() A[T]
|
||||
|
||||
func _[T any]() {
|
||||
f12(A[T])()
|
||||
}
|
||||
|
||||
// method expressions
|
||||
|
||||
func (_ S1[P]) m()
|
||||
|
||||
func _() {
|
||||
m := S1[int].m
|
||||
m(struct { f int }{42})
|
||||
}
|
||||
|
||||
func _[T any] (x T) {
|
||||
m := S1[T].m
|
||||
m(S1[T]{x})
|
||||
}
|
||||
|
||||
// type parameters in methods (generalization)
|
||||
|
||||
type R0 struct{}
|
||||
|
||||
func (R0) _[T any](x T)
|
||||
func (R0 /* ERROR invalid receiver */ ) _[R0 any]() // scope of type parameters starts at "func"
|
||||
|
||||
type R1[A, B any] struct{}
|
||||
|
||||
func (_ R1[A, B]) m0(A, B)
|
||||
func (_ R1[A, B]) m1[T any](A, B, T) T
|
||||
func (_ R1 /* ERROR not a generic type */ [R1, _]) _()
|
||||
func (_ R1[A, B]) _[A /* ERROR redeclared */ any](B)
|
||||
|
||||
func _() {
|
||||
var r R1[int, string]
|
||||
r.m1[rune](42, "foo", 'a')
|
||||
r.m1[rune](42, "foo", 1.2 /* ERROR truncated to rune */)
|
||||
r.m1(42, "foo", 1.2) // using type inference
|
||||
var _ float64 = r.m1(42, "foo", 1.2)
|
||||
}
|
||||
|
||||
type I1[A any] interface {
|
||||
m1(A)
|
||||
}
|
||||
|
||||
var _ I1[int] = r1[int]{}
|
||||
|
||||
type r1[T any] struct{}
|
||||
|
||||
func (_ r1[T]) m1(T)
|
||||
|
||||
type I2[A, B any] interface {
|
||||
m1(A)
|
||||
m2(A) B
|
||||
}
|
||||
|
||||
var _ I2[int, float32] = R2[int, float32]{}
|
||||
|
||||
type R2[P, Q any] struct{}
|
||||
|
||||
func (_ R2[X, Y]) m1(X)
|
||||
func (_ R2[X, Y]) m2(X) Y
|
||||
|
||||
// type assertions and type switches over generic types
|
||||
// NOTE: These are currently disabled because it's unclear what the correct
|
||||
// approach is, and one can always work around by assigning the variable to
|
||||
// an interface first.
|
||||
|
||||
// // ReadByte1 corresponds to the ReadByte example in the draft design.
|
||||
// func ReadByte1[T io.Reader](r T) (byte, error) {
|
||||
// if br, ok := r.(io.ByteReader); ok {
|
||||
// return br.ReadByte()
|
||||
// }
|
||||
// var b [1]byte
|
||||
// _, err := r.Read(b[:])
|
||||
// return b[0], err
|
||||
// }
|
||||
//
|
||||
// // ReadBytes2 is like ReadByte1 but uses a type switch instead.
|
||||
// func ReadByte2[T io.Reader](r T) (byte, error) {
|
||||
// switch br := r.(type) {
|
||||
// case io.ByteReader:
|
||||
// return br.ReadByte()
|
||||
// }
|
||||
// var b [1]byte
|
||||
// _, err := r.Read(b[:])
|
||||
// return b[0], err
|
||||
// }
|
||||
//
|
||||
// // type assertions and type switches over generic types are strict
|
||||
// type I3 interface {
|
||||
// m(int)
|
||||
// }
|
||||
//
|
||||
// type I4 interface {
|
||||
// m() int // different signature from I3.m
|
||||
// }
|
||||
//
|
||||
// func _[T I3](x I3, p T) {
|
||||
// // type assertions and type switches over interfaces are not strict
|
||||
// _ = x.(I4)
|
||||
// switch x.(type) {
|
||||
// case I4:
|
||||
// }
|
||||
//
|
||||
// // type assertions and type switches over generic types are strict
|
||||
// _ = p /* ERROR cannot have dynamic type I4 */.(I4)
|
||||
// switch p.(type) {
|
||||
// case I4 /* ERROR cannot have dynamic type I4 */ :
|
||||
// }
|
||||
// }
|
||||
|
||||
// type assertions and type switches over generic types lead to errors for now
|
||||
|
||||
func _[T any](x T) {
|
||||
_ = x /* ERROR not an interface */ .(int)
|
||||
switch x /* ERROR not an interface */ .(type) {
|
||||
}
|
||||
|
||||
// work-around
|
||||
var t interface{} = x
|
||||
_ = t.(int)
|
||||
switch t.(type) {
|
||||
}
|
||||
}
|
||||
|
||||
func _[T interface{ ~int }](x T) {
|
||||
_ = x /* ERROR not an interface */ .(int)
|
||||
switch x /* ERROR not an interface */ .(type) {
|
||||
}
|
||||
|
||||
// work-around
|
||||
var t interface{} = x
|
||||
_ = t.(int)
|
||||
switch t.(type) {
|
||||
}
|
||||
}
|
||||
|
||||
// error messages related to type bounds mention those bounds
|
||||
type C[P any] interface{}
|
||||
|
||||
func _[P C[P]] (x P) {
|
||||
x.m /* ERROR x.m undefined */ ()
|
||||
}
|
||||
|
||||
type I interface {}
|
||||
|
||||
func _[P I] (x P) {
|
||||
x.m /* ERROR interface I has no method m */ ()
|
||||
}
|
||||
|
||||
func _[P interface{}] (x P) {
|
||||
x.m /* ERROR type bound for P has no method m */ ()
|
||||
}
|
||||
|
||||
func _[P any] (x P) {
|
||||
x.m /* ERROR type bound for P has no method m */ ()
|
||||
}
|
||||
|
||||
// automatic distinguishing between array and generic types
|
||||
// NOTE: Disabled when using unified parameter list syntax.
|
||||
/*
|
||||
const P = 10
|
||||
type A1 [P]byte
|
||||
func _(a A1) {
|
||||
assert(len(a) == 10)
|
||||
}
|
||||
|
||||
type A2 [P]struct{
|
||||
f [P]byte
|
||||
}
|
||||
func _(a A2) {
|
||||
assert(len(a) == 10)
|
||||
assert(len(a[0].f) == 10)
|
||||
}
|
||||
|
||||
type A3 [P]func(x [P]A3)
|
||||
func _(a A3) {
|
||||
assert(len(a) == 10)
|
||||
}
|
||||
|
||||
type T2[P] struct{ P }
|
||||
var _ T2[int]
|
||||
|
||||
type T3[P] func(P)
|
||||
var _ T3[int]
|
||||
*/
|
||||
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
package p
|
||||
|
||||
// error messages for parser in generic mode
|
||||
func _() {
|
||||
_ = m[] // ERROR expecting operand
|
||||
_ = m[x,]
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
// error messages for parser in non-generic mode
|
||||
func _() {
|
||||
_ = m[] // ERROR expecting operand
|
||||
_ = m[x,] // ERROR unexpected comma, expecting \: or \]
|
||||
_ = m[x /* ERROR unexpected a */ a b c d]
|
||||
}
|
||||
|
||||
// test case from the issue
|
||||
func f(m map[int]int) int {
|
||||
return m[0 // ERROR expecting \: or \]
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
// test case from issue
|
||||
|
||||
type _ interface{
|
||||
m /* ERROR unexpected int in interface type; possibly missing semicolon or newline or } */ int
|
||||
}
|
||||
|
||||
// other cases where the fix for this issue affects the error message
|
||||
|
||||
const (
|
||||
x int = 10 /* ERROR unexpected literal "foo" in grouped declaration; possibly missing semicolon or newline or \) */ "foo"
|
||||
)
|
||||
|
||||
var _ = []int{1, 2, 3 /* ERROR unexpected int in composite literal; possibly missing comma or } */ int }
|
||||
|
||||
type _ struct {
|
||||
x y /* ERROR syntax error: unexpected comma in struct type; possibly missing semicolon or newline or } */ ,
|
||||
}
|
||||
|
||||
func f(a, b c /* ERROR unexpected d in parameter list; possibly missing comma or \) */ d) {
|
||||
f(a, b, c /* ERROR unexpected d in argument list; possibly missing comma or \) */ d)
|
||||
}
|
||||
|
|
@ -5,8 +5,7 @@
|
|||
// Package orderedmap provides an ordered map, implemented as a binary tree.
|
||||
package orderedmap
|
||||
|
||||
// TODO(gri) fix imports for tests
|
||||
import "chans" // ERROR could not import
|
||||
import "chans"
|
||||
|
||||
// Map is an ordered map.
|
||||
type Map[K, V any] struct {
|
||||
|
|
@ -56,7 +56,7 @@ func reducer(x float64, y int) float64 {
|
|||
}
|
||||
|
||||
var reduced1 = Reduce[int, float64](input, 0, reducer)
|
||||
var reduced2 = Reduce(input, 1i /* ERROR overflows */, reducer) // using type inference
|
||||
var reduced2 = Reduce(input, 1i, reducer) // using type inference
|
||||
var reduced3 = Reduce(input, 1, reducer) // using type inference
|
||||
|
||||
func filter(x int) bool {
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue