diff --git a/doc/contribute.html b/doc/contribute.html
index 3fb617b863..09d43313ff 100644
--- a/doc/contribute.html
+++ b/doc/contribute.html
@@ -806,10 +806,9 @@ tracker will automatically mark the issue as fixed.
If the change is a partial step towards the resolution of the issue,
-uses the notation "Updates #12345".
-This will leave a comment in the issue
-linking back to the change in Gerrit, but it will not close the issue
-when the change is applied.
+write "Updates #12345" instead.
+This will leave a comment in the issue linking back to the change in
+Gerrit, but it will not close the issue when the change is applied.
diff --git a/doc/diagnostics.html b/doc/diagnostics.html
index 478611c15c..f9368886c4 100644
--- a/doc/diagnostics.html
+++ b/doc/diagnostics.html
@@ -454,6 +454,8 @@ environmental variable is set accordingly.
GODEBUG=gctrace=1 prints garbage collector events at
each collection, summarizing the amount of memory collected
and the length of the pause.
+GODEBUG=inittrace=1 prints a summary of execution time and memory allocation
+information for completed package initilization work.
GODEBUG=schedtrace=X prints scheduling events every X milliseconds.
diff --git a/doc/go1.16.html b/doc/go1.16.html
index 09717dac85..43bcc779e5 100644
--- a/doc/go1.16.html
+++ b/doc/go1.16.html
@@ -31,8 +31,22 @@ Do not send CLs removing the interior tags from such phrases.
Ports
-
- TODO
+
NetBSD
+
+
+ Go now supports the 64-bit ARM architecture on NetBSD (the
+ netbsd/arm64 port).
+
+
+386
+
+
+ As announced in the Go 1.15 release notes,
+ Go 1.16 drops support for x87 mode compilation (GO386=387).
+ Support for non-SSE2 processors is now available using soft float
+ mode (GO386=softfloat).
+ Users running on non-SSE2 processors should replace GO386=387
+ with GO386=softfloat.
@@ -85,6 +99,17 @@ Do not send CLs removing the interior tags from such phrases.
that is still considered to be a passing test.
+
+ The go get -insecure flag is
+ deprecated and will be removed in a future version. This flag permits
+ fetching from repositories and resolving custom domains using insecure
+ schemes such as HTTP, and also bypassess module sum validation using the
+ checksum database. To permit the use of insecure schemes, use the
+ GOINSECURE environment variable instead. To bypass module
+ sum validation, use GOPRIVATE or GONOSUMDB.
+ See go help environment for details.
+
+
The all pattern
@@ -148,12 +173,49 @@ Do not send CLs removing the interior tags from such phrases.
TODO: update with final numbers later in the release.
+
+
Core library
TODO
+
+
+
+ New will now panic if separate calls to
+ the hash generation function fail to return new values. Previously, the
+ behavior was undefined and invalid outputs were sometimes generated.
+
+
+
+
+
+ I/O operations on closing or closed TLS connections can now be detected using
+ the new ErrClosed error. A typical use
+ would be errors.Is(err, net.ErrClosed). In earlier releases
+ the only way to reliably detect this case was to match the string returned
+ by the Error method with "tls: use of closed connection".
+
+
+
+
+
+ ParseCertificate and
+ CreateCertificate both
+ now enforce string encoding restrictions for the fields DNSNames,
+ EmailAddresses, and URIs. These fields can only
+ contain strings with characters within the ASCII range.
+
+
+
+ CreateCertificate now
+ verifies the generated certificate's signature using the signer's
+ public key. If the signature is invalid, an error is returned, instead
+ of a malformed certificate.
+
+
@@ -166,6 +228,14 @@ Do not send CLs removing the interior tags from such phrases.
with "use of closed network connection".
+
+
+
+ For interface types and values, Method,
+ MethodByName, and
+ NumMethod now
+ operate on the interface's exported method set, rather than its full method set.
+
@@ -199,6 +269,25 @@ Do not send CLs removing the interior tags from such phrases.
TODO
+- crypto/dsa
+ -
+
+ The crypto/dsa package is now deprecated.
+ See issue #40337.
+
+
+
+
+- crypto/x509
+ -
+
+ DSA signature verification is no longer supported. Note that DSA signature
+ generation was never supported.
+ See issue #40337.
+
+
+
+
- net/http
-
@@ -220,5 +309,31 @@ Do not send CLs removing the interior tags from such phrases.
of the form "Range": "bytes=--N" where "-N" is a negative suffix length, for
example "Range": "bytes=--2". It now replies with a 416 "Range Not Satisfiable" response.
+
+
+ Cookies set with SameSiteDefaultMode now behave according to the current
+ spec (no attribute is set) instead of generating a SameSite key without a value.
+
+
+- runtime/debug
+ -
+
+ TODO: https://golang.org/cl/249677: provide Addr method for errors from SetPanicOnFault
+
+
+
+
+- strconv
+ -
+
+ ParseFloat now uses
+ the Eisel-Lemire
+ algorithm, improving performance by up to a factor of 2. This can
+ also speed up decoding textual formats like encoding/json.
+
+
+
diff --git a/doc/go_spec.html b/doc/go_spec.html
index 154bdbfeaf..e9e9e42130 100644
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1,6 +1,6 @@
@@ -3646,7 +3646,7 @@ For instance, x / y * z is the same as (x / y) * z.
x <= f()
^a >> b
f() || g()
-x == y+1 && <-chanPtr > 0
+x == y+1 && <-chanInt > 0
diff --git a/doc/install-source.html b/doc/install-source.html
index 86a4644c0c..c6dc3aed43 100644
--- a/doc/install-source.html
+++ b/doc/install-source.html
@@ -666,16 +666,13 @@ For example, you should not set $GOHOSTARCH to
arm on an x86 system.
-$GO386 (for 386 only, default is auto-detected
-if built on either 386 or amd64, 387 otherwise)
+$GO386 (for 386 only, defaults to sse2)
-This controls the code generated by gc to use either the 387 floating-point unit
-(set to 387) or SSE2 instructions (set to sse2) for
-floating point computations.
+This variable controls how gc implements floating point computations.
- GO386=387: use x87 for floating point operations; should support all x86 chips (Pentium MMX or later).
- GO386=sse2: use SSE2 for floating point operations; has better performance than 387, but only available on Pentium 4/Opteron/Athlon 64 or later.
+ GO386=softfloat: use software floating point operations; should support all x86 chips (Pentium MMX or later).
+ GO386=sse2: use SSE2 for floating point operations; has better performance but only available on Pentium 4/Opteron/Athlon 64 or later.
diff --git a/lib/time/update.bash b/lib/time/update.bash
index 683d0cf390..65ef8fb62b 100755
--- a/lib/time/update.bash
+++ b/lib/time/update.bash
@@ -8,8 +8,8 @@
# Consult https://www.iana.org/time-zones for the latest versions.
# Versions to use.
-CODE=2020a
-DATA=2020a
+CODE=2020b
+DATA=2020b
set -e
rm -rf work
diff --git a/lib/time/zoneinfo.zip b/lib/time/zoneinfo.zip
index c4bfd5e5de..13034f804c 100644
Binary files a/lib/time/zoneinfo.zip and b/lib/time/zoneinfo.zip differ
diff --git a/misc/cgo/test/issue4029.c b/misc/cgo/test/issue4029.c
index 30646ade02..e6a777fe64 100644
--- a/misc/cgo/test/issue4029.c
+++ b/misc/cgo/test/issue4029.c
@@ -3,6 +3,7 @@
// license that can be found in the LICENSE file.
// +build !windows,!static
+// +build !darwin !internal_pie
#include
#include
diff --git a/misc/cgo/test/issue4029.go b/misc/cgo/test/issue4029.go
index 1bf029d760..8602ce19e2 100644
--- a/misc/cgo/test/issue4029.go
+++ b/misc/cgo/test/issue4029.go
@@ -3,6 +3,10 @@
// license that can be found in the LICENSE file.
// +build !windows,!static
+// +build !darwin !internal_pie
+
+// Excluded in darwin internal linking PIE mode, as dynamic export is not
+// supported.
package cgotest
diff --git a/misc/cgo/test/issue4029w.go b/misc/cgo/test/issue4029w.go
index eee33f7010..de0cf2138a 100644
--- a/misc/cgo/test/issue4029w.go
+++ b/misc/cgo/test/issue4029w.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.
-// +build windows static
+// +build windows static darwin,internal_pie
package cgotest
diff --git a/misc/cgo/test/sigaltstack.go b/misc/cgo/test/sigaltstack.go
index 27b753a147..034cc4b371 100644
--- a/misc/cgo/test/sigaltstack.go
+++ b/misc/cgo/test/sigaltstack.go
@@ -62,7 +62,7 @@ import (
func testSigaltstack(t *testing.T) {
switch {
- case runtime.GOOS == "solaris", runtime.GOOS == "illumos", (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && runtime.GOARCH == "arm64":
+ case runtime.GOOS == "solaris", runtime.GOOS == "illumos", runtime.GOOS == "ios" && runtime.GOARCH == "arm64":
t.Skipf("switching signal stack not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
}
diff --git a/misc/cgo/test/testdata/issue41761.go b/misc/cgo/test/testdata/issue41761.go
new file mode 100644
index 0000000000..919c749251
--- /dev/null
+++ b/misc/cgo/test/testdata/issue41761.go
@@ -0,0 +1,20 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cgotest
+
+/*
+ typedef struct S S;
+*/
+import "C"
+
+import (
+ "cgotest/issue41761a"
+ "testing"
+)
+
+func test41761(t *testing.T) {
+ var x issue41761a.T
+ _ = (*C.struct_S)(x.X)
+}
diff --git a/misc/cgo/test/testdata/issue41761a/a.go b/misc/cgo/test/testdata/issue41761a/a.go
new file mode 100644
index 0000000000..ca5c18191e
--- /dev/null
+++ b/misc/cgo/test/testdata/issue41761a/a.go
@@ -0,0 +1,14 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package issue41761a
+
+/*
+ typedef struct S S;
+*/
+import "C"
+
+type T struct {
+ X *C.S
+}
diff --git a/misc/cgo/testcarchive/carchive_test.go b/misc/cgo/testcarchive/carchive_test.go
index 2e223ea369..6ed25d8948 100644
--- a/misc/cgo/testcarchive/carchive_test.go
+++ b/misc/cgo/testcarchive/carchive_test.go
@@ -603,7 +603,7 @@ func TestExtar(t *testing.T) {
if runtime.Compiler == "gccgo" {
t.Skip("skipping -extar test when using gccgo")
}
- if (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && runtime.GOARCH == "arm64" {
+ if runtime.GOOS == "ios" {
t.Skip("shell scripts are not executable on iOS hosts")
}
diff --git a/misc/ios/README b/misc/ios/README
index d7df191414..433bcdfd8f 100644
--- a/misc/ios/README
+++ b/misc/ios/README
@@ -1,13 +1,20 @@
Go on iOS
=========
-For details on developing Go for iOS on macOS, see the documentation in the mobile
-subrepository:
+To run the standard library tests, run all.bash as usual, but with the compiler
+set to the clang wrapper that invokes clang for iOS. For example, this command runs
+ all.bash on the iOS emulator:
- https://github.com/golang/mobile
+ GOOS=ios GOARCH=amd64 CGO_ENABLED=1 CC_FOR_TARGET=$(pwd)/../misc/ios/clangwrap.sh ./all.bash
-It is necessary to set up the environment before running tests or programs directly on a
-device.
+To use the go tool to run individual programs and tests, put $GOROOT/bin into PATH to ensure
+the go_ios_$GOARCH_exec wrapper is found. For example, to run the archive/tar tests:
+
+ export PATH=$GOROOT/bin:$PATH
+ GOOS=ios GOARCH=amd64 CGO_ENABLED=1 go test archive/tar
+
+The go_ios_exec wrapper uses GOARCH to select the emulator (amd64) or the device (arm64).
+However, further setup is required to run tests or programs directly on a device.
First make sure you have a valid developer certificate and have setup your device properly
to run apps signed by your developer certificate. Then install the libimobiledevice and
@@ -29,18 +36,10 @@ which will output something similar to
export GOIOS_TEAM_ID=ZZZZZZZZ
If you have multiple devices connected, specify the device UDID with the GOIOS_DEVICE_ID
-variable. Use `idevice_id -l` to list all available UDIDs.
+variable. Use `idevice_id -l` to list all available UDIDs. Then, setting GOARCH to arm64
+will select the device:
-Finally, to run the standard library tests, run all.bash as usual, but with the compiler
-set to the clang wrapper that invokes clang for iOS. For example,
-
- GOARCH=arm64 CGO_ENABLED=1 CC_FOR_TARGET=$(pwd)/../misc/ios/clangwrap.sh ./all.bash
-
-To use the go tool directly to run programs and tests, put $GOROOT/bin into PATH to ensure
-the go_darwin_$GOARCH_exec wrapper is found. For example, to run the archive/tar tests
-
- export PATH=$GOROOT/bin:$PATH
- GOARCH=arm64 CGO_ENABLED=1 go test archive/tar
+ GOOS=ios GOARCH=arm64 CGO_ENABLED=1 CC_FOR_TARGET=$(pwd)/../misc/ios/clangwrap.sh ./all.bash
Note that the go_darwin_$GOARCH_exec wrapper uninstalls any existing app identified by
the bundle id before installing a new app. If the uninstalled app is the last app by
diff --git a/misc/ios/clangwrap.sh b/misc/ios/clangwrap.sh
index 1d6dee28a8..dca3fcc904 100755
--- a/misc/ios/clangwrap.sh
+++ b/misc/ios/clangwrap.sh
@@ -2,17 +2,19 @@
# This uses the latest available iOS SDK, which is recommended.
# To select a specific SDK, run 'xcodebuild -showsdks'
# to see the available SDKs and replace iphoneos with one of them.
-SDK=iphoneos
+if [ "$GOARCH" == "arm64" ]; then
+ SDK=iphoneos
+ PLATFORM=ios
+ CLANGARCH="arm64"
+else
+ SDK=iphonesimulator
+ PLATFORM=ios-simulator
+ CLANGARCH="x86_64"
+fi
+
SDK_PATH=`xcrun --sdk $SDK --show-sdk-path`
export IPHONEOS_DEPLOYMENT_TARGET=5.1
# cmd/cgo doesn't support llvm-gcc-4.2, so we have to use clang.
CLANG=`xcrun --sdk $SDK --find clang`
-if [ "$GOARCH" == "arm64" ]; then
- CLANGARCH="arm64"
-else
- echo "unknown GOARCH=$GOARCH" >&2
- exit 1
-fi
-
-exec "$CLANG" -arch $CLANGARCH -isysroot "$SDK_PATH" -mios-version-min=10.0 "$@"
+exec "$CLANG" -arch $CLANGARCH -isysroot "$SDK_PATH" -m${PLATFORM}-version-min=10.0 "$@"
diff --git a/misc/ios/detect.go b/misc/ios/detect.go
index 1d47e47c86..d32bcc3202 100644
--- a/misc/ios/detect.go
+++ b/misc/ios/detect.go
@@ -6,7 +6,7 @@
// detect attempts to autodetect the correct
// values of the environment variables
-// used by go_darwin_arm_exec.
+// used by go_ios_exec.
// detect shells out to ideviceinfo, a third party program that can
// be obtained by following the instructions at
// https://github.com/libimobiledevice/libimobiledevice.
diff --git a/misc/ios/go_darwin_arm_exec.go b/misc/ios/go_ios_exec.go
similarity index 81%
rename from misc/ios/go_darwin_arm_exec.go
rename to misc/ios/go_ios_exec.go
index cdf4b07d0a..0acf1b259c 100644
--- a/misc/ios/go_darwin_arm_exec.go
+++ b/misc/ios/go_ios_exec.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.
-// This program can be used as go_darwin_arm_exec by the Go tool.
+// This program can be used as go_ios_$GOARCH_exec by the Go tool.
// It executes binaries on an iOS device using the XCode toolchain
// and the ios-deploy program: https://github.com/phonegap/ios-deploy
//
@@ -34,6 +34,7 @@ import (
"os/signal"
"path/filepath"
"runtime"
+ "strconv"
"strings"
"syscall"
"time"
@@ -58,34 +59,16 @@ var lock *os.File
func main() {
log.SetFlags(0)
- log.SetPrefix("go_darwin_arm_exec: ")
+ log.SetPrefix("go_ios_exec: ")
if debug {
log.Println(strings.Join(os.Args, " "))
}
if len(os.Args) < 2 {
- log.Fatal("usage: go_darwin_arm_exec a.out")
+ log.Fatal("usage: go_ios_exec a.out")
}
- // e.g. B393DDEB490947F5A463FD074299B6C0AXXXXXXX
- devID = getenv("GOIOS_DEV_ID")
-
- // e.g. Z8B3JBXXXX.org.golang.sample, Z8B3JBXXXX prefix is available at
- // https://developer.apple.com/membercenter/index.action#accountSummary as Team ID.
- appID = getenv("GOIOS_APP_ID")
-
- // e.g. Z8B3JBXXXX, available at
- // https://developer.apple.com/membercenter/index.action#accountSummary as Team ID.
- teamID = getenv("GOIOS_TEAM_ID")
-
- // Device IDs as listed with ios-deploy -c.
- deviceID = os.Getenv("GOIOS_DEVICE_ID")
-
- parts := strings.SplitN(appID, ".", 2)
// For compatibility with the old builders, use a fallback bundle ID
bundleID = "golang.gotest"
- if len(parts) == 2 {
- bundleID = parts[1]
- }
exitCode, err := runMain()
if err != nil {
@@ -96,7 +79,7 @@ func main() {
func runMain() (int, error) {
var err error
- tmpdir, err = ioutil.TempDir("", "go_darwin_arm_exec_")
+ tmpdir, err = ioutil.TempDir("", "go_ios_exec_")
if err != nil {
return 1, err
}
@@ -117,7 +100,7 @@ func runMain() (int, error) {
//
// The lock file is never deleted, to avoid concurrent locks on distinct
// files with the same path.
- lockName := filepath.Join(os.TempDir(), "go_darwin_arm_exec-"+deviceID+".lock")
+ lockName := filepath.Join(os.TempDir(), "go_ios_exec-"+deviceID+".lock")
lock, err = os.OpenFile(lockName, os.O_CREATE|os.O_RDONLY, 0666)
if err != nil {
return 1, err
@@ -126,28 +109,12 @@ func runMain() (int, error) {
return 1, err
}
- if err := uninstall(bundleID); err != nil {
- return 1, err
+ if goarch := os.Getenv("GOARCH"); goarch == "arm64" {
+ err = runOnDevice(appdir)
+ } else {
+ err = runOnSimulator(appdir)
}
-
- if err := install(appdir); err != nil {
- return 1, err
- }
-
- if err := mountDevImage(); err != nil {
- return 1, err
- }
-
- // Kill any hanging debug bridges that might take up port 3222.
- exec.Command("killall", "idevicedebugserverproxy").Run()
-
- closer, err := startDebugBridge()
if err != nil {
- return 1, err
- }
- defer closer()
-
- if err := run(appdir, bundleID, os.Args[2:]); err != nil {
// If the lldb driver completed with an exit code, use that.
if err, ok := err.(*exec.ExitError); ok {
if ws, ok := err.Sys().(interface{ ExitStatus() int }); ok {
@@ -159,6 +126,62 @@ func runMain() (int, error) {
return 0, nil
}
+func runOnSimulator(appdir string) error {
+ if err := installSimulator(appdir); err != nil {
+ return err
+ }
+
+ return runSimulator(appdir, bundleID, os.Args[2:])
+}
+
+func runOnDevice(appdir string) error {
+ // e.g. B393DDEB490947F5A463FD074299B6C0AXXXXXXX
+ devID = getenv("GOIOS_DEV_ID")
+
+ // e.g. Z8B3JBXXXX.org.golang.sample, Z8B3JBXXXX prefix is available at
+ // https://developer.apple.com/membercenter/index.action#accountSummary as Team ID.
+ appID = getenv("GOIOS_APP_ID")
+
+ // e.g. Z8B3JBXXXX, available at
+ // https://developer.apple.com/membercenter/index.action#accountSummary as Team ID.
+ teamID = getenv("GOIOS_TEAM_ID")
+
+ // Device IDs as listed with ios-deploy -c.
+ deviceID = os.Getenv("GOIOS_DEVICE_ID")
+
+ parts := strings.SplitN(appID, ".", 2)
+ if len(parts) == 2 {
+ bundleID = parts[1]
+ }
+
+ if err := signApp(appdir); err != nil {
+ return err
+ }
+
+ if err := uninstallDevice(bundleID); err != nil {
+ return err
+ }
+
+ if err := installDevice(appdir); err != nil {
+ return err
+ }
+
+ if err := mountDevImage(); err != nil {
+ return err
+ }
+
+ // Kill any hanging debug bridges that might take up port 3222.
+ exec.Command("killall", "idevicedebugserverproxy").Run()
+
+ closer, err := startDebugBridge()
+ if err != nil {
+ return err
+ }
+ defer closer()
+
+ return runDevice(appdir, bundleID, os.Args[2:])
+}
+
func getenv(envvar string) string {
s := os.Getenv(envvar)
if s == "" {
@@ -191,7 +214,11 @@ func assembleApp(appdir, bin string) error {
if err := ioutil.WriteFile(filepath.Join(appdir, "ResourceRules.plist"), []byte(resourceRules), 0744); err != nil {
return err
}
+ return nil
+}
+func signApp(appdir string) error {
+ entitlementsPath := filepath.Join(tmpdir, "Entitlements.plist")
cmd := exec.Command(
"codesign",
"-f",
@@ -421,7 +448,20 @@ func parsePlistDict(dict []byte) (map[string]string, error) {
return values, nil
}
-func uninstall(bundleID string) error {
+func installSimulator(appdir string) error {
+ cmd := exec.Command(
+ "xcrun", "simctl", "install",
+ "booted", // Install to the booted simulator.
+ appdir,
+ )
+ if out, err := cmd.CombinedOutput(); err != nil {
+ os.Stderr.Write(out)
+ return fmt.Errorf("xcrun simctl install booted %q: %v", appdir, err)
+ }
+ return nil
+}
+
+func uninstallDevice(bundleID string) error {
cmd := idevCmd(exec.Command(
"ideviceinstaller",
"-U", bundleID,
@@ -433,7 +473,7 @@ func uninstall(bundleID string) error {
return nil
}
-func install(appdir string) error {
+func installDevice(appdir string) error {
attempt := 0
for {
cmd := idevCmd(exec.Command(
@@ -464,15 +504,28 @@ func idevCmd(cmd *exec.Cmd) *exec.Cmd {
return cmd
}
-func run(appdir, bundleID string, args []string) error {
- var env []string
- for _, e := range os.Environ() {
- // Don't override TMPDIR, HOME, GOCACHE on the device.
- if strings.HasPrefix(e, "TMPDIR=") || strings.HasPrefix(e, "HOME=") || strings.HasPrefix(e, "GOCACHE=") {
- continue
- }
- env = append(env, e)
+func runSimulator(appdir, bundleID string, args []string) error {
+ cmd := exec.Command(
+ "xcrun", "simctl", "launch",
+ "--wait-for-debugger",
+ "booted",
+ bundleID,
+ )
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ os.Stderr.Write(out)
+ return fmt.Errorf("xcrun simctl launch booted %q: %v", bundleID, err)
}
+ var processID int
+ var ignore string
+ if _, err := fmt.Sscanf(string(out), "%s %d", &ignore, &processID); err != nil {
+ return fmt.Errorf("runSimulator: couldn't find processID from `simctl launch`: %v (%q)", err, out)
+ }
+ _, err = runLLDB("ios-simulator", appdir, strconv.Itoa(processID), args)
+ return err
+}
+
+func runDevice(appdir, bundleID string, args []string) error {
attempt := 0
for {
// The device app path reported by the device might be stale, so retry
@@ -487,37 +540,10 @@ func run(appdir, bundleID string, args []string) error {
time.Sleep(5 * time.Second)
continue
}
- lldb := exec.Command(
- "python",
- "-", // Read script from stdin.
- appdir,
- deviceapp,
- )
- lldb.Args = append(lldb.Args, args...)
- lldb.Env = env
- lldb.Stdin = strings.NewReader(lldbDriver)
- lldb.Stdout = os.Stdout
- var out bytes.Buffer
- lldb.Stderr = io.MultiWriter(&out, os.Stderr)
- err = lldb.Start()
- if err == nil {
- // Forward SIGQUIT to the lldb driver which in turn will forward
- // to the running program.
- sigs := make(chan os.Signal, 1)
- signal.Notify(sigs, syscall.SIGQUIT)
- proc := lldb.Process
- go func() {
- for sig := range sigs {
- proc.Signal(sig)
- }
- }()
- err = lldb.Wait()
- signal.Stop(sigs)
- close(sigs)
- }
+ out, err := runLLDB("remote-ios", appdir, deviceapp, args)
// If the program was not started it can be retried without papering over
// real test failures.
- started := bytes.HasPrefix(out.Bytes(), []byte("lldb: running program"))
+ started := bytes.HasPrefix(out, []byte("lldb: running program"))
if started || err == nil || attempt == 5 {
return err
}
@@ -528,6 +554,47 @@ func run(appdir, bundleID string, args []string) error {
}
}
+func runLLDB(target, appdir, deviceapp string, args []string) ([]byte, error) {
+ var env []string
+ for _, e := range os.Environ() {
+ // Don't override TMPDIR, HOME, GOCACHE on the device.
+ if strings.HasPrefix(e, "TMPDIR=") || strings.HasPrefix(e, "HOME=") || strings.HasPrefix(e, "GOCACHE=") {
+ continue
+ }
+ env = append(env, e)
+ }
+ lldb := exec.Command(
+ "python",
+ "-", // Read script from stdin.
+ target,
+ appdir,
+ deviceapp,
+ )
+ lldb.Args = append(lldb.Args, args...)
+ lldb.Env = env
+ lldb.Stdin = strings.NewReader(lldbDriver)
+ lldb.Stdout = os.Stdout
+ var out bytes.Buffer
+ lldb.Stderr = io.MultiWriter(&out, os.Stderr)
+ err := lldb.Start()
+ if err == nil {
+ // Forward SIGQUIT to the lldb driver which in turn will forward
+ // to the running program.
+ sigs := make(chan os.Signal, 1)
+ signal.Notify(sigs, syscall.SIGQUIT)
+ proc := lldb.Process
+ go func() {
+ for sig := range sigs {
+ proc.Signal(sig)
+ }
+ }()
+ err = lldb.Wait()
+ signal.Stop(sigs)
+ close(sigs)
+ }
+ return out.Bytes(), err
+}
+
func copyLocalDir(dst, src string) error {
if err := os.Mkdir(dst, 0755); err != nil {
return err
@@ -679,6 +746,7 @@ func infoPlist(pkgpath string) string {
CFBundleSupportedPlatformsiPhoneOS
CFBundleExecutablegotest
CFBundleVersion1.0
+CFBundleShortVersionString1.0
CFBundleIdentifier` + bundleID + `
CFBundleResourceSpecificationResourceRules.plist
LSRequiresIPhoneOS
@@ -739,7 +807,7 @@ import sys
import os
import signal
-exe, device_exe, args = sys.argv[1], sys.argv[2], sys.argv[3:]
+platform, exe, device_exe_or_pid, args = sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4:]
env = []
for k, v in os.environ.items():
@@ -754,17 +822,21 @@ debugger.SetAsync(True)
debugger.SkipLLDBInitFiles(True)
err = lldb.SBError()
-target = debugger.CreateTarget(exe, None, 'remote-ios', True, err)
+target = debugger.CreateTarget(exe, None, platform, True, err)
if not target.IsValid() or not err.Success():
sys.stderr.write("lldb: failed to setup up target: %s\n" % (err))
sys.exit(1)
-target.modules[0].SetPlatformFileSpec(lldb.SBFileSpec(device_exe))
-
listener = debugger.GetListener()
-process = target.ConnectRemote(listener, 'connect://localhost:3222', None, err)
+
+if platform == 'remote-ios':
+ target.modules[0].SetPlatformFileSpec(lldb.SBFileSpec(device_exe_or_pid))
+ process = target.ConnectRemote(listener, 'connect://localhost:3222', None, err)
+else:
+ process = target.AttachToProcessWithID(listener, int(device_exe_or_pid), err)
+
if not err.Success():
- sys.stderr.write("lldb: failed to connect to remote target: %s\n" % (err))
+ sys.stderr.write("lldb: failed to connect to remote target %s: %s\n" % (device_exe_or_pid, err))
sys.exit(1)
# Don't stop on signals.
@@ -777,6 +849,25 @@ for i in range(0, sigs.GetNumSignals()):
event = lldb.SBEvent()
running = False
prev_handler = None
+
+def signal_handler(signal, frame):
+ process.Signal(signal)
+
+def run_program():
+ # Forward SIGQUIT to the program.
+ prev_handler = signal.signal(signal.SIGQUIT, signal_handler)
+ # Tell the Go driver that the program is running and should not be retried.
+ sys.stderr.write("lldb: running program\n")
+ running = True
+ # Process is stopped at attach/launch. Let it run.
+ process.Continue()
+
+if platform != 'remote-ios':
+ # For the local emulator the program is ready to run.
+ # For remote device runs, we need to wait for eStateConnected,
+ # below.
+ run_program()
+
while True:
if not listener.WaitForEvent(1, event):
continue
@@ -800,24 +891,22 @@ while True:
signal.signal(signal.SIGQUIT, prev_handler)
break
elif state == lldb.eStateConnected:
- process.RemoteLaunch(args, env, None, None, None, None, 0, False, err)
- if not err.Success():
- sys.stderr.write("lldb: failed to launch remote process: %s\n" % (err))
- process.Kill()
- debugger.Terminate()
- sys.exit(1)
- # Forward SIGQUIT to the program.
- def signal_handler(signal, frame):
- process.Signal(signal)
- prev_handler = signal.signal(signal.SIGQUIT, signal_handler)
- # Tell the Go driver that the program is running and should not be retried.
- sys.stderr.write("lldb: running program\n")
- running = True
- # Process stops once at the beginning. Continue.
- process.Continue()
+ if platform == 'remote-ios':
+ process.RemoteLaunch(args, env, None, None, None, None, 0, False, err)
+ if not err.Success():
+ sys.stderr.write("lldb: failed to launch remote process: %s\n" % (err))
+ process.Kill()
+ debugger.Terminate()
+ sys.exit(1)
+ run_program()
exitStatus = process.GetExitStatus()
+exitDesc = process.GetExitDescription()
process.Kill()
debugger.Terminate()
+if exitStatus == 0 and exitDesc is not None:
+ # Ensure tests fail when killed by a signal.
+ exitStatus = 123
+
sys.exit(exitStatus)
`
diff --git a/src/buildall.bash b/src/buildall.bash
index dc67c0630f..7b3751f42e 100755
--- a/src/buildall.bash
+++ b/src/buildall.bash
@@ -3,10 +3,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-# Usage: buildall.sh [-e] [pattern]
+# Usage: buildall.bash [-e] [pattern]
#
# buildall.bash builds the standard library for all Go-supported
-# architectures. It is used by the "all-compile" trybot builder,
+# architectures. It is used by the "misc-compile" trybot builders,
# as a smoke test to quickly flag portability issues.
#
# Options:
@@ -37,12 +37,11 @@ GOROOT="$(cd .. && pwd)"
gettargets() {
../bin/go tool dist list | sed -e 's|/|-|'
- echo linux-386-387
echo linux-arm-arm5
}
selectedtargets() {
- gettargets | egrep -v 'android-arm|darwin-arm64' | egrep "$pattern"
+ gettargets | egrep "$pattern"
}
# put linux first in the target list to get all the architectures up front.
@@ -64,15 +63,11 @@ do
echo "### Building $target"
export GOOS=$(echo $target | sed 's/-.*//')
export GOARCH=$(echo $target | sed 's/.*-//')
- unset GO386 GOARM
+ unset GOARM
if [ "$GOARCH" = "arm5" ]; then
export GOARCH=arm
export GOARM=5
fi
- if [ "$GOARCH" = "387" ]; then
- export GOARCH=386
- export GO386=387
- fi
# Build and vet everything.
# cmd/go/internal/work/exec.go enables the same vet flags during go test of std cmd
diff --git a/src/bytes/bytes.go b/src/bytes/bytes.go
index aa07b9fbc1..ce52649f13 100644
--- a/src/bytes/bytes.go
+++ b/src/bytes/bytes.go
@@ -227,19 +227,26 @@ func IndexAny(s []byte, chars string) int {
continue
}
r, width = utf8.DecodeRune(s[i:])
- if r == utf8.RuneError {
- for _, r = range chars {
- if r == utf8.RuneError {
+ if r != utf8.RuneError {
+ // r is 2 to 4 bytes
+ if len(chars) == width {
+ if chars == string(r) {
return i
}
+ continue
+ }
+ // Use bytealg.IndexString for performance if available.
+ if bytealg.MaxLen >= width {
+ if bytealg.IndexString(chars, string(r)) >= 0 {
+ return i
+ }
+ continue
}
- continue
}
- // r is 2 to 4 bytes. Using strings.Index is more reasonable, but as the bytes
- // package should not import the strings package, use bytealg.IndexString
- // instead. And this does not seem to lose much performance.
- if chars == string(r) || bytealg.IndexString(chars, string(r)) >= 0 {
- return i
+ for _, ch := range chars {
+ if r == ch {
+ return i
+ }
}
}
return -1
@@ -304,19 +311,26 @@ func LastIndexAny(s []byte, chars string) int {
}
r, size := utf8.DecodeLastRune(s[:i])
i -= size
- if r == utf8.RuneError {
- for _, r = range chars {
- if r == utf8.RuneError {
+ if r != utf8.RuneError {
+ // r is 2 to 4 bytes
+ if len(chars) == size {
+ if chars == string(r) {
return i
}
+ continue
+ }
+ // Use bytealg.IndexString for performance if available.
+ if bytealg.MaxLen >= size {
+ if bytealg.IndexString(chars, string(r)) >= 0 {
+ return i
+ }
+ continue
}
- continue
}
- // r is 2 to 4 bytes. Using strings.Index is more reasonable, but as the bytes
- // package should not import the strings package, use bytealg.IndexString
- // instead. And this does not seem to lose much performance.
- if chars == string(r) || bytealg.IndexString(chars, string(r)) >= 0 {
- return i
+ for _, ch := range chars {
+ if r == ch {
+ return i
+ }
}
}
return -1
diff --git a/src/cmd/asm/internal/arch/arm64.go b/src/cmd/asm/internal/arch/arm64.go
index 3817fcd5c2..e643889aef 100644
--- a/src/cmd/asm/internal/arch/arm64.go
+++ b/src/cmd/asm/internal/arch/arm64.go
@@ -82,6 +82,17 @@ func IsARM64STLXR(op obj.As) bool {
return false
}
+// IsARM64TBL reports whether the op (as defined by an arm64.A*
+// constant) is one of the TBL-like instructions and one of its
+// inputs does not fit into prog.Reg, so require special handling.
+func IsARM64TBL(op obj.As) bool {
+ switch op {
+ case arm64.AVTBL, arm64.AVMOVQ:
+ return true
+ }
+ return false
+}
+
// ARM64Suffix handles the special suffix for the ARM64.
// It returns a boolean to indicate success; failure means
// cond was unrecognized.
@@ -125,13 +136,6 @@ func arm64RegisterNumber(name string, n int16) (int16, bool) {
return 0, false
}
-// IsARM64TBL reports whether the op (as defined by an arm64.A*
-// constant) is one of the table lookup instructions that require special
-// handling.
-func IsARM64TBL(op obj.As) bool {
- return op == arm64.AVTBL
-}
-
// ARM64RegisterExtension parses an ARM64 register with extension or arrangement.
func ARM64RegisterExtension(a *obj.Addr, ext string, reg, num int16, isAmount, isIndex bool) error {
Rnum := (reg & 31) + int16(num<<5)
diff --git a/src/cmd/asm/internal/asm/asm.go b/src/cmd/asm/internal/asm/asm.go
index 42e217dc23..b9efa454ed 100644
--- a/src/cmd/asm/internal/asm/asm.go
+++ b/src/cmd/asm/internal/asm/asm.go
@@ -181,7 +181,7 @@ func (p *Parser) asmText(operands [][]lex.Token) {
// Argsize set below.
},
}
- nameAddr.Sym.Func.Text = prog
+ nameAddr.Sym.Func().Text = prog
prog.To.Val = int32(argSize)
p.append(prog, "", true)
}
@@ -622,8 +622,9 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
prog.SetFrom3(a[1])
prog.To = a[2]
case sys.ARM64:
- // ARM64 instructions with one input and two outputs.
- if arch.IsARM64STLXR(op) {
+ switch {
+ case arch.IsARM64STLXR(op):
+ // ARM64 instructions with one input and two outputs.
prog.From = a[0]
prog.To = a[1]
if a[2].Type != obj.TYPE_REG {
@@ -631,20 +632,16 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
return
}
prog.RegTo2 = a[2].Reg
- break
- }
- if arch.IsARM64TBL(op) {
+ case arch.IsARM64TBL(op):
+ // one of its inputs does not fit into prog.Reg.
prog.From = a[0]
- if a[1].Type != obj.TYPE_REGLIST {
- p.errorf("%s: expected list; found %s", op, obj.Dconv(prog, &a[1]))
- }
prog.SetFrom3(a[1])
prog.To = a[2]
- break
+ default:
+ prog.From = a[0]
+ prog.Reg = p.getRegister(prog, op, &a[1])
+ prog.To = a[2]
}
- prog.From = a[0]
- prog.Reg = p.getRegister(prog, op, &a[1])
- prog.To = a[2]
case sys.I386:
prog.From = a[0]
prog.SetFrom3(a[1])
diff --git a/src/cmd/asm/internal/asm/endtoend_test.go b/src/cmd/asm/internal/asm/endtoend_test.go
index 0759b7d10f..989b7a5405 100644
--- a/src/cmd/asm/internal/asm/endtoend_test.go
+++ b/src/cmd/asm/internal/asm/endtoend_test.go
@@ -31,7 +31,7 @@ func testEndToEnd(t *testing.T, goarch, file string) {
architecture, ctxt := setArch(goarch)
architecture.Init(ctxt)
lexer := lex.NewLexer(input)
- parser := NewParser(ctxt, architecture, lexer)
+ parser := NewParser(ctxt, architecture, lexer, false)
pList := new(obj.Plist)
var ok bool
testOut = new(bytes.Buffer) // The assembler writes test output to this buffer.
@@ -257,11 +257,11 @@ func isHexes(s string) bool {
return true
}
-// It would be nice if the error messages began with
+// It would be nice if the error messages always began with
// the standard file:line: prefix,
// but that's not where we are today.
// It might be at the beginning but it might be in the middle of the printed instruction.
-var fileLineRE = regexp.MustCompile(`(?:^|\()(testdata[/\\][0-9a-z]+\.s:[0-9]+)(?:$|\))`)
+var fileLineRE = regexp.MustCompile(`(?:^|\()(testdata[/\\][0-9a-z]+\.s:[0-9]+)(?:$|\)|:)`)
// Same as in test/run.go
var (
@@ -273,7 +273,7 @@ func testErrors(t *testing.T, goarch, file string) {
input := filepath.Join("testdata", file+".s")
architecture, ctxt := setArch(goarch)
lexer := lex.NewLexer(input)
- parser := NewParser(ctxt, architecture, lexer)
+ parser := NewParser(ctxt, architecture, lexer, false)
pList := new(obj.Plist)
var ok bool
testOut = new(bytes.Buffer) // The assembler writes test output to this buffer.
@@ -281,6 +281,7 @@ func testErrors(t *testing.T, goarch, file string) {
defer ctxt.Bso.Flush()
failed := false
var errBuf bytes.Buffer
+ parser.errorWriter = &errBuf
ctxt.DiagFunc = func(format string, args ...interface{}) {
failed = true
s := fmt.Sprintf(format, args...)
@@ -292,7 +293,7 @@ func testErrors(t *testing.T, goarch, file string) {
pList.Firstpc, ok = parser.Parse()
obj.Flushplist(ctxt, pList, nil, "")
if ok && !failed {
- t.Errorf("asm: %s had no errors", goarch)
+ t.Errorf("asm: %s had no errors", file)
}
errors := map[string]string{}
@@ -353,12 +354,7 @@ func testErrors(t *testing.T, goarch, file string) {
}
func Test386EndToEnd(t *testing.T) {
- defer func(old string) { objabi.GO386 = old }(objabi.GO386)
- for _, go386 := range []string{"387", "sse2"} {
- t.Logf("GO386=%v", go386)
- objabi.GO386 = go386
- testEndToEnd(t, "386", "386")
- }
+ testEndToEnd(t, "386", "386")
}
func TestARMEndToEnd(t *testing.T) {
@@ -373,6 +369,10 @@ func TestARMEndToEnd(t *testing.T) {
}
}
+func TestGoBuildErrors(t *testing.T) {
+ testErrors(t, "amd64", "buildtagerror")
+}
+
func TestARMErrors(t *testing.T) {
testErrors(t, "arm", "armerror")
}
@@ -442,10 +442,6 @@ func TestPPC64EndToEnd(t *testing.T) {
testEndToEnd(t, "ppc64", "ppc64")
}
-func TestPPC64Encoder(t *testing.T) {
- testEndToEnd(t, "ppc64", "ppc64enc")
-}
-
func TestRISCVEncoder(t *testing.T) {
testEndToEnd(t, "riscv64", "riscvenc")
}
diff --git a/src/cmd/asm/internal/asm/expr_test.go b/src/cmd/asm/internal/asm/expr_test.go
index 1251594349..e9c92df1f3 100644
--- a/src/cmd/asm/internal/asm/expr_test.go
+++ b/src/cmd/asm/internal/asm/expr_test.go
@@ -57,7 +57,7 @@ var exprTests = []exprTest{
}
func TestExpr(t *testing.T) {
- p := NewParser(nil, nil, nil) // Expression evaluation uses none of these fields of the parser.
+ p := NewParser(nil, nil, nil, false) // Expression evaluation uses none of these fields of the parser.
for i, test := range exprTests {
p.start(lex.Tokenize(test.input))
result := int64(p.expr())
@@ -113,7 +113,7 @@ func TestBadExpr(t *testing.T) {
}
func runBadTest(i int, test badExprTest, t *testing.T) (err error) {
- p := NewParser(nil, nil, nil) // Expression evaluation uses none of these fields of the parser.
+ p := NewParser(nil, nil, nil, false) // Expression evaluation uses none of these fields of the parser.
p.start(lex.Tokenize(test.input))
return tryParse(t, func() {
p.expr()
diff --git a/src/cmd/asm/internal/asm/line_test.go b/src/cmd/asm/internal/asm/line_test.go
index 01b058bd95..da857ced3a 100644
--- a/src/cmd/asm/internal/asm/line_test.go
+++ b/src/cmd/asm/internal/asm/line_test.go
@@ -39,7 +39,7 @@ func testBadInstParser(t *testing.T, goarch string, tests []badInstTest) {
for i, test := range tests {
arch, ctxt := setArch(goarch)
tokenizer := lex.NewTokenizer("", strings.NewReader(test.input+"\n"), nil)
- parser := NewParser(ctxt, arch, tokenizer)
+ parser := NewParser(ctxt, arch, tokenizer, false)
err := tryParse(t, func() {
parser.Parse()
diff --git a/src/cmd/asm/internal/asm/operand_test.go b/src/cmd/asm/internal/asm/operand_test.go
index f187d0b166..2e83e176b2 100644
--- a/src/cmd/asm/internal/asm/operand_test.go
+++ b/src/cmd/asm/internal/asm/operand_test.go
@@ -28,7 +28,7 @@ func setArch(goarch string) (*arch.Arch, *obj.Link) {
func newParser(goarch string) *Parser {
architecture, ctxt := setArch(goarch)
- return NewParser(ctxt, architecture, nil)
+ return NewParser(ctxt, architecture, nil, false)
}
// tryParse executes parse func in panicOnError=true context.
@@ -75,7 +75,12 @@ func testOperandParser(t *testing.T, parser *Parser, tests []operandTest) {
parser.start(lex.Tokenize(test.input))
addr := obj.Addr{}
parser.operand(&addr)
- result := obj.Dconv(&emptyProg, &addr)
+ var result string
+ if parser.compilingRuntime {
+ result = obj.DconvWithABIDetail(&emptyProg, &addr)
+ } else {
+ result = obj.Dconv(&emptyProg, &addr)
+ }
if result != test.output {
t.Errorf("fail at %s: got %s; expected %s\n", test.input, result, test.output)
}
@@ -86,6 +91,9 @@ func TestAMD64OperandParser(t *testing.T) {
parser := newParser("amd64")
testOperandParser(t, parser, amd64OperandTests)
testBadOperandParser(t, parser, amd64BadOperandTests)
+ parser.compilingRuntime = true
+ testOperandParser(t, parser, amd64RuntimeOperandTests)
+ testBadOperandParser(t, parser, amd64BadOperandRuntimeTests)
}
func Test386OperandParser(t *testing.T) {
@@ -141,7 +149,7 @@ func TestFuncAddress(t *testing.T) {
parser := newParser(sub.arch)
for _, test := range sub.tests {
parser.start(lex.Tokenize(test.input))
- name, ok := parser.funcAddress()
+ name, _, ok := parser.funcAddress()
isFuncSym := strings.HasSuffix(test.input, "(SB)") &&
// Ignore static symbols.
@@ -298,6 +306,11 @@ var amd64OperandTests = []operandTest{
{"[):[o-FP", ""}, // Issue 12469 - asm hung parsing the o-FP range on non ARM platforms.
}
+var amd64RuntimeOperandTests = []operandTest{
+ {"$bar(SB)", "$bar(SB)"},
+ {"$foo(SB)", "$foo(SB)"},
+}
+
var amd64BadOperandTests = []badOperandTest{
{"[", "register list: expected ']', found EOF"},
{"[4", "register list: bad low register in `[4`"},
@@ -311,6 +324,11 @@ var amd64BadOperandTests = []badOperandTest{
{"[X0-X1-X2]", "register list: expected ']' after `[X0-X1`, found '-'"},
{"[X0,X3]", "register list: expected '-' after `[X0`, found ','"},
{"[X0,X1,X2,X3]", "register list: expected '-' after `[X0`, found ','"},
+ {"$foo", "ABI selector only permitted when compiling runtime, reference was to \"foo\""},
+}
+
+var amd64BadOperandRuntimeTests = []badOperandTest{
+ {"$foo", "malformed ABI selector \"bletch\" in reference to \"foo\""},
}
var x86OperandTests = []operandTest{
diff --git a/src/cmd/asm/internal/asm/parse.go b/src/cmd/asm/internal/asm/parse.go
index 17d40ee415..154cf9c7a7 100644
--- a/src/cmd/asm/internal/asm/parse.go
+++ b/src/cmd/asm/internal/asm/parse.go
@@ -25,24 +25,26 @@ import (
)
type Parser struct {
- lex lex.TokenReader
- lineNum int // Line number in source file.
- errorLine int // Line number of last error.
- errorCount int // Number of errors.
- pc int64 // virtual PC; count of Progs; doesn't advance for GLOBL or DATA.
- input []lex.Token
- inputPos int
- pendingLabels []string // Labels to attach to next instruction.
- labels map[string]*obj.Prog
- toPatch []Patch
- addr []obj.Addr
- arch *arch.Arch
- ctxt *obj.Link
- firstProg *obj.Prog
- lastProg *obj.Prog
- dataAddr map[string]int64 // Most recent address for DATA for this symbol.
- isJump bool // Instruction being assembled is a jump.
- errorWriter io.Writer
+ lex lex.TokenReader
+ lineNum int // Line number in source file.
+ errorLine int // Line number of last error.
+ errorCount int // Number of errors.
+ sawCode bool // saw code in this file (as opposed to comments and blank lines)
+ pc int64 // virtual PC; count of Progs; doesn't advance for GLOBL or DATA.
+ input []lex.Token
+ inputPos int
+ pendingLabels []string // Labels to attach to next instruction.
+ labels map[string]*obj.Prog
+ toPatch []Patch
+ addr []obj.Addr
+ arch *arch.Arch
+ ctxt *obj.Link
+ firstProg *obj.Prog
+ lastProg *obj.Prog
+ dataAddr map[string]int64 // Most recent address for DATA for this symbol.
+ isJump bool // Instruction being assembled is a jump.
+ compilingRuntime bool
+ errorWriter io.Writer
}
type Patch struct {
@@ -50,14 +52,15 @@ type Patch struct {
label string
}
-func NewParser(ctxt *obj.Link, ar *arch.Arch, lexer lex.TokenReader) *Parser {
+func NewParser(ctxt *obj.Link, ar *arch.Arch, lexer lex.TokenReader, compilingRuntime bool) *Parser {
return &Parser{
- ctxt: ctxt,
- arch: ar,
- lex: lexer,
- labels: make(map[string]*obj.Prog),
- dataAddr: make(map[string]int64),
- errorWriter: os.Stderr,
+ ctxt: ctxt,
+ arch: ar,
+ lex: lexer,
+ labels: make(map[string]*obj.Prog),
+ dataAddr: make(map[string]int64),
+ errorWriter: os.Stderr,
+ compilingRuntime: compilingRuntime,
}
}
@@ -132,6 +135,30 @@ func (p *Parser) ParseSymABIs(w io.Writer) bool {
return p.errorCount == 0
}
+// nextToken returns the next non-build-comment token from the lexer.
+// It reports misplaced //go:build comments but otherwise discards them.
+func (p *Parser) nextToken() lex.ScanToken {
+ for {
+ tok := p.lex.Next()
+ if tok == lex.BuildComment {
+ if p.sawCode {
+ p.errorf("misplaced //go:build comment")
+ }
+ continue
+ }
+ if tok != '\n' {
+ p.sawCode = true
+ }
+ if tok == '#' {
+ // A leftover wisp of a #include/#define/etc,
+ // to let us know that p.sawCode should be true now.
+ // Otherwise ignored.
+ continue
+ }
+ return tok
+ }
+}
+
// line consumes a single assembly line from p.lex of the form
//
// {label:} WORD[.cond] [ arg {, arg} ] (';' | '\n')
@@ -146,7 +173,7 @@ next:
// Skip newlines.
var tok lex.ScanToken
for {
- tok = p.lex.Next()
+ tok = p.nextToken()
// We save the line number here so error messages from this instruction
// are labeled with this line. Otherwise we complain after we've absorbed
// the terminating newline and the line numbers are off by one in errors.
@@ -179,11 +206,11 @@ next:
items = make([]lex.Token, 0, 3)
}
for {
- tok = p.lex.Next()
+ tok = p.nextToken()
if len(operands) == 0 && len(items) == 0 {
if p.arch.InFamily(sys.ARM, sys.ARM64, sys.AMD64, sys.I386) && tok == '.' {
// Suffixes: ARM conditionals or x86 modifiers.
- tok = p.lex.Next()
+ tok = p.nextToken()
str := p.lex.Text()
if tok != scanner.Ident {
p.errorf("instruction suffix expected identifier, found %s", str)
@@ -285,8 +312,8 @@ func (p *Parser) symDefRef(w io.Writer, word string, operands [][]lex.Token) {
// Defines text symbol in operands[0].
if len(operands) > 0 {
p.start(operands[0])
- if name, ok := p.funcAddress(); ok {
- fmt.Fprintf(w, "def %s ABI0\n", name)
+ if name, abi, ok := p.funcAddress(); ok {
+ fmt.Fprintf(w, "def %s %s\n", name, abi)
}
}
return
@@ -304,8 +331,8 @@ func (p *Parser) symDefRef(w io.Writer, word string, operands [][]lex.Token) {
// Search for symbol references.
for _, op := range operands {
p.start(op)
- if name, ok := p.funcAddress(); ok {
- fmt.Fprintf(w, "ref %s ABI0\n", name)
+ if name, abi, ok := p.funcAddress(); ok {
+ fmt.Fprintf(w, "ref %s %s\n", name, abi)
}
}
}
@@ -740,20 +767,19 @@ func (p *Parser) symbolReference(a *obj.Addr, name string, prefix rune) {
case '*':
a.Type = obj.TYPE_INDIR
}
- // Weirdness with statics: Might now have "<>".
- isStatic := false
- if p.peek() == '<' {
- isStatic = true
- p.next()
- p.get('>')
- }
+
+ // Parse optional <> (indicates a static symbol) or
+ // (selecting text symbol with specific ABI).
+ doIssueError := true
+ isStatic, abi := p.symRefAttrs(name, doIssueError)
+
if p.peek() == '+' || p.peek() == '-' {
a.Offset = int64(p.expr())
}
if isStatic {
a.Sym = p.ctxt.LookupStatic(name)
} else {
- a.Sym = p.ctxt.Lookup(name)
+ a.Sym = p.ctxt.LookupABI(name, abi)
}
if p.peek() == scanner.EOF {
if prefix == 0 && p.isJump {
@@ -798,12 +824,60 @@ func (p *Parser) setPseudoRegister(addr *obj.Addr, reg string, isStatic bool, pr
}
}
+// symRefAttrs parses an optional function symbol attribute clause for
+// the function symbol 'name', logging an error for a malformed
+// attribute clause if 'issueError' is true. The return value is a
+// (boolean, ABI) pair indicating that the named symbol is either
+// static or a particular ABI specification.
+//
+// The expected form of the attribute clause is:
+//
+// empty, yielding (false, obj.ABI0)
+// "<>", yielding (true, obj.ABI0)
+// "" yielding (false, obj.ABI0)
+// "" yielding (false, obj.ABIInternal)
+//
+// 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
+ if p.peek() != '<' {
+ return isStatic, abi
+ }
+ p.next()
+ tok := p.peek()
+ if tok == '>' {
+ isStatic = true
+ } else if tok == scanner.Ident {
+ abistr := p.get(scanner.Ident).String()
+ if !p.compilingRuntime {
+ if issueError {
+ p.errorf("ABI selector only permitted when compiling runtime, reference was to %q", name)
+ }
+ } else {
+ theabi, valid := obj.ParseABI(abistr)
+ if !valid {
+ if issueError {
+ p.errorf("malformed ABI selector %q in reference to %q",
+ abistr, name)
+ }
+ } else {
+ abi = theabi
+ }
+ }
+ }
+ p.get('>')
+ return isStatic, abi
+}
+
// funcAddress parses an external function address. This is a
// constrained form of the operand syntax that's always SB-based,
// non-static, and has at most a simple integer offset:
//
-// [$|*]sym[+Int](SB)
-func (p *Parser) funcAddress() (string, bool) {
+// [$|*]sym[][+Int](SB)
+func (p *Parser) funcAddress() (string, obj.ABI, bool) {
switch p.peek() {
case '$', '*':
// Skip prefix.
@@ -813,25 +887,32 @@ func (p *Parser) funcAddress() (string, bool) {
tok := p.next()
name := tok.String()
if tok.ScanToken != scanner.Ident || p.atStartOfRegister(name) {
- return "", false
+ return "", obj.ABI0, false
+ }
+ // Parse optional <> (indicates a static symbol) or
+ // (selecting text symbol with specific ABI).
+ noErrMsg := false
+ isStatic, abi := p.symRefAttrs(name, noErrMsg)
+ if isStatic {
+ return "", obj.ABI0, false // This function rejects static symbols.
}
tok = p.next()
if tok.ScanToken == '+' {
if p.next().ScanToken != scanner.Int {
- return "", false
+ return "", obj.ABI0, false
}
tok = p.next()
}
if tok.ScanToken != '(' {
- return "", false
+ return "", obj.ABI0, false
}
if reg := p.next(); reg.ScanToken != scanner.Ident || reg.String() != "SB" {
- return "", false
+ return "", obj.ABI0, false
}
if p.next().ScanToken != ')' || p.peek() != scanner.EOF {
- return "", false
+ return "", obj.ABI0, false
}
- return name, true
+ return name, abi, true
}
// registerIndirect parses the general form of a register indirection.
diff --git a/src/cmd/asm/internal/asm/pseudo_test.go b/src/cmd/asm/internal/asm/pseudo_test.go
index 100bef91cf..622ee25ce7 100644
--- a/src/cmd/asm/internal/asm/pseudo_test.go
+++ b/src/cmd/asm/internal/asm/pseudo_test.go
@@ -37,6 +37,7 @@ func TestErroneous(t *testing.T) {
{"TEXT", "$0É:0, 0, $1", "expected end of operand, found É"}, // Issue #12467.
{"TEXT", "$:0:(SB, 0, $1", "expected '(', found 0"}, // Issue 12468.
{"TEXT", "@B(SB),0,$0", "expected '(', found B"}, // Issue 23580.
+ {"TEXT", "foo(SB),0", "ABI selector only permitted when compiling runtime, reference was to \"foo\""},
{"FUNCDATA", "", "expect two operands for FUNCDATA"},
{"FUNCDATA", "(SB ", "expect two operands for FUNCDATA"},
{"DATA", "", "expect two operands for DATA"},
diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s
index acfb16b096..7f495b90bb 100644
--- a/src/cmd/asm/internal/asm/testdata/arm64.s
+++ b/src/cmd/asm/internal/asm/testdata/arm64.s
@@ -81,6 +81,8 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
SHA512H2 V4.D2, V3, V2 // 628464ce
SHA512SU0 V9.D2, V8.D2 // 2881c0ce
SHA512SU1 V7.D2, V6.D2, V5.D2 // c58867ce
+ VRAX1 V26.D2, V29.D2, V30.D2 // be8f7ace
+ VXAR $63, V27.D2, V21.D2, V26.D2 // bafe9bce
VADDV V0.S4, V0 // 00b8b14e
VMOVI $82, V0.B16 // 40e6024f
VUADDLV V6.B16, V6 // c638306e
@@ -139,6 +141,8 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
VTBL V14.B16, [V3.B16, V4.B16, V5.B16], V17.B16 // 71400e4e
VTBL V13.B16, [V29.B16, V30.B16, V31.B16, V0.B16], V28.B16 // bc630d4e
VTBL V3.B8, [V27.B16], V8.B8 // 6803030e
+ VEOR3 V2.B16, V7.B16, V12.B16, V25.B16 // 990907ce
+ VBCAX V1.B16, V2.B16, V26.B16, V31.B16 // 5f0722ce
VZIP1 V16.H8, V3.H8, V19.H8 // 7338504e
VZIP2 V22.D2, V25.D2, V21.D2 // 357bd64e
VZIP1 V6.D2, V9.D2, V11.D2 // 2b39c64e
@@ -218,8 +222,10 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
FMOVD $(28.0), F4 // 0490671e
// move a large constant to a Vd.
- FMOVD $0x8040201008040201, V20 // FMOVD $-9205322385119247871, V20
- FMOVQ $0x8040201008040202, V29 // FMOVQ $-9205322385119247870, V29
+ VMOVS $0x80402010, V11 // VMOVS $2151686160, V11
+ VMOVD $0x8040201008040201, V20 // VMOVD $-9205322385119247871, V20
+ VMOVQ $0x7040201008040201, $0x8040201008040201, V10 // VMOVQ $8088500183983456769, $-9205322385119247871, V10
+ VMOVQ $0x8040201008040202, $0x7040201008040201, V20 // VMOVQ $-9205322385119247870, $8088500183983456769, V20
FMOVS (R2)(R6), F4 // FMOVS (R2)(R6*1), F4 // 446866bc
FMOVS (R2)(R6<<2), F4 // 447866bc
diff --git a/src/cmd/asm/internal/asm/testdata/buildtagerror.s b/src/cmd/asm/internal/asm/testdata/buildtagerror.s
new file mode 100644
index 0000000000..5a2d65b978
--- /dev/null
+++ b/src/cmd/asm/internal/asm/testdata/buildtagerror.s
@@ -0,0 +1,8 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define X 1
+
+//go:build x // ERROR "misplaced //go:build comment"
+
diff --git a/src/cmd/asm/internal/asm/testdata/ppc64.s b/src/cmd/asm/internal/asm/testdata/ppc64.s
index ba64d84a35..2b1191c44b 100644
--- a/src/cmd/asm/internal/asm/testdata/ppc64.s
+++ b/src/cmd/asm/internal/asm/testdata/ppc64.s
@@ -2,1311 +2,717 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// This input was created by taking the instruction productions in
-// the old assembler's (9a's) grammar and hand-writing complete
-// instructions for each rule, to guarantee we cover the same space.
+// This contains the majority of valid opcode combinations
+// available in cmd/internal/obj/ppc64/asm9.go with
+// their valid instruction encodings.
#include "../../../../../runtime/textflag.h"
-TEXT foo(SB),DUPOK|NOSPLIT,$0
+TEXT asmtest(SB),DUPOK|NOSPLIT,$0
+ // move constants
+ MOVD $1, R3 // 38600001
+ MOVD $-1, R4 // 3880ffff
+ MOVD $65535, R5 // 6005ffff
+ MOVD $65536, R6 // 64060001
+ MOVD $-32767, R5 // 38a08001
+ MOVD $-32768, R6 // 38c08000
+ MOVD $1234567, R5 // 6405001260a5d687
+ MOVW $1, R3 // 38600001
+ MOVW $-1, R4 // 3880ffff
+ MOVW $65535, R5 // 6005ffff
+ MOVW $65536, R6 // 64060001
+ MOVW $-32767, R5 // 38a08001
+ MOVW $-32768, R6 // 38c08000
+ MOVW $1234567, R5 // 6405001260a5d687
+ MOVD 8(R3), R4 // e8830008
+ MOVD (R3)(R4), R5 // 7ca4182a
+ MOVW 4(R3), R4 // e8830006
+ MOVW (R3)(R4), R5 // 7ca41aaa
+ MOVWZ 4(R3), R4 // 80830004
+ MOVWZ (R3)(R4), R5 // 7ca4182e
+ MOVH 4(R3), R4 // a8830004
+ MOVH (R3)(R4), R5 // 7ca41aae
+ MOVHZ 2(R3), R4 // a0830002
+ MOVHZ (R3)(R4), R5 // 7ca41a2e
+ MOVB 1(R3), R4 // 888300017c840774
+ MOVB (R3)(R4), R5 // 7ca418ae7ca50774
+ MOVBZ 1(R3), R4 // 88830001
+ MOVBZ (R3)(R4), R5 // 7ca418ae
+ MOVDBR (R3)(R4), R5 // 7ca41c28
+ MOVWBR (R3)(R4), R5 // 7ca41c2c
+ MOVHBR (R3)(R4), R5 // 7ca41e2c
+
+ MOVDU 8(R3), R4 // e8830009
+ MOVDU (R3)(R4), R5 // 7ca4186a
+ MOVWU (R3)(R4), R5 // 7ca41aea
+ MOVWZU 4(R3), R4 // 84830004
+ MOVWZU (R3)(R4), R5 // 7ca4186e
+ MOVHU 2(R3), R4 // ac830002
+ MOVHU (R3)(R4), R5 // 7ca41aee
+ MOVHZU 2(R3), R4 // a4830002
+ MOVHZU (R3)(R4), R5 // 7ca41a6e
+ MOVBU 1(R3), R4 // 8c8300017c840774
+ MOVBU (R3)(R4), R5 // 7ca418ee7ca50774
+ MOVBZU 1(R3), R4 // 8c830001
+ MOVBZU (R3)(R4), R5 // 7ca418ee
+
+ MOVD R4, 8(R3) // f8830008
+ MOVD R5, (R3)(R4) // 7ca4192a
+ MOVW R4, 4(R3) // 90830004
+ MOVW R5, (R3)(R4) // 7ca4192e
+ MOVH R4, 2(R3) // b0830002
+ MOVH R5, (R3)(R4) // 7ca41b2e
+ MOVB R4, 1(R3) // 98830001
+ MOVB R5, (R3)(R4) // 7ca419ae
+ MOVDBR R5, (R3)(R4) // 7ca41d28
+ MOVWBR R5, (R3)(R4) // 7ca41d2c
+ MOVHBR R5, (R3)(R4) // 7ca41f2c
+
+ MOVDU R4, 8(R3) // f8830009
+ MOVDU R5, (R3)(R4) // 7ca4196a
+ MOVWU R4, 4(R3) // 94830004
+ MOVWU R5, (R3)(R4) // 7ca4196e
+ MOVHU R4, 2(R3) // b4830002
+ MOVHU R5, (R3)(R4) // 7ca41b6e
+ MOVBU R4, 1(R3) // 9c830001
+ MOVBU R5, (R3)(R4) // 7ca419ee
+
+ ADD $1, R3 // 38630001
+ ADD $1, R3, R4 // 38830001
+ ADD $-1, R4 // 3884ffff
+ ADD $-1, R4, R5 // 38a4ffff
+ ADD $65535, R5 // 601fffff7cbf2a14
+ ADD $65535, R5, R6 // 601fffff7cdf2a14
+ ADD $65536, R6 // 3cc60001
+ ADD $65536, R6, R7 // 3ce60001
+ ADD $-32767, R5 // 38a58001
+ ADD $-32767, R5, R4 // 38858001
+ ADD $-32768, R6 // 38c68000
+ ADD $-32768, R6, R5 // 38a68000
+ ADD $1234567, R5 // 641f001263ffd6877cbf2a14
+ ADD $1234567, R5, R6 // 641f001263ffd6877cdf2a14
+ ADDEX R3, R5, $3, R6 // 7cc32f54
+ ADDIS $8, R3 // 3c630008
+ ADDIS $1000, R3, R4 // 3c8303e8
+
+ ANDCC $1, R3 // 70630001
+ ANDCC $1, R3, R4 // 70640001
+ ANDCC $-1, R4 // 3be0ffff7fe42039
+ ANDCC $-1, R4, R5 // 3be0ffff7fe52039
+ ANDCC $65535, R5 // 70a5ffff
+ ANDCC $65535, R5, R6 // 70a6ffff
+ ANDCC $65536, R6 // 74c60001
+ ANDCC $65536, R6, R7 // 74c70001
+ ANDCC $-32767, R5 // 3be080017fe52839
+ ANDCC $-32767, R5, R4 // 3be080017fe42839
+ ANDCC $-32768, R6 // 3be080007fe63039
+ ANDCC $-32768, R5, R6 // 3be080007fe62839
+ ANDCC $1234567, R5 // 641f001263ffd6877fe52839
+ ANDCC $1234567, R5, R6 // 641f001263ffd6877fe62839
+ ANDISCC $1, R3 // 74630001
+ ANDISCC $1000, R3, R4 // 746403e8
+
+ OR $1, R3 // 60630001
+ OR $1, R3, R4 // 60640001
+ OR $-1, R4 // 3be0ffff7fe42378
+ OR $-1, R4, R5 // 3be0ffff7fe52378
+ OR $65535, R5 // 60a5ffff
+ OR $65535, R5, R6 // 60a6ffff
+ OR $65536, R6 // 64c60001
+ OR $65536, R6, R7 // 64c70001
+ OR $-32767, R5 // 3be080017fe52b78
+ OR $-32767, R5, R6 // 3be080017fe62b78
+ OR $-32768, R6 // 3be080007fe63378
+ OR $-32768, R6, R7 // 3be080007fe73378
+ OR $1234567, R5 // 641f001263ffd6877fe52b78
+ OR $1234567, R5, R3 // 641f001263ffd6877fe32b78
+ ORIS $255, R3, R4
+
+ XOR $1, R3 // 68630001
+ XOR $1, R3, R4 // 68640001
+ XOR $-1, R4 // 3be0ffff7fe42278
+ XOR $-1, R4, R5 // 3be0ffff7fe52278
+ XOR $65535, R5 // 68a5ffff
+ XOR $65535, R5, R6 // 68a6ffff
+ XOR $65536, R6 // 6cc60001
+ XOR $65536, R6, R7 // 6cc70001
+ XOR $-32767, R5 // 3be080017fe52a78
+ XOR $-32767, R5, R6 // 3be080017fe62a78
+ XOR $-32768, R6 // 3be080007fe63278
+ XOR $-32768, R6, R7 // 3be080007fe73278
+ XOR $1234567, R5 // 641f001263ffd6877fe52a78
+ XOR $1234567, R5, R3 // 641f001263ffd6877fe32a78
+ XORIS $15, R3, R4
+
+ // TODO: the order of CR operands don't match
+ CMP R3, R4 // 7c232000
+ CMPU R3, R4 // 7c232040
+ CMPW R3, R4 // 7c032000
+ CMPWU R3, R4 // 7c032040
+ CMPB R3,R4,R4 // 7c6423f8
+ CMPEQB R3,R4,CR6 // 7f0321c0
+
+ // TODO: constants for ADDC?
+ ADD R3, R4 // 7c841a14
+ ADD R3, R4, R5 // 7ca41a14
+ ADDC R3, R4 // 7c841814
+ ADDC R3, R4, R5 // 7ca41814
+ ADDE R3, R4 // 7c841914
+ ADDECC R3, R4 // 7c841915
+ ADDEV R3, R4 // 7c841d14
+ ADDEVCC R3, R4 // 7c841d15
+ ADDV R3, R4 // 7c841e14
+ ADDVCC R3, R4 // 7c841e15
+ ADDCCC R3, R4, R5 // 7ca41815
+ ADDME R3, R4 // 7c8301d4
+ ADDMECC R3, R4 // 7c8301d5
+ ADDMEV R3, R4 // 7c8305d4
+ ADDMEVCC R3, R4 // 7c8305d5
+ ADDCV R3, R4 // 7c841c14
+ ADDCVCC R3, R4 // 7c841c15
+ ADDZE R3, R4 // 7c830194
+ ADDZECC R3, R4 // 7c830195
+ ADDZEV R3, R4 // 7c830594
+ ADDZEVCC R3, R4 // 7c830595
+ SUBME R3, R4 // 7c8301d0
+ SUBMECC R3, R4 // 7c8301d1
+ SUBMEV R3, R4 // 7c8305d0
+ SUBZE R3, R4 // 7c830190
+ SUBZECC R3, R4 // 7c830191
+ SUBZEV R3, R4 // 7c830590
+ SUBZEVCC R3, R4 // 7c830591
+
+ AND R3, R4 // 7c841838
+ AND R3, R4, R5 // 7c851838
+ ANDN R3, R4, R5 // 7c851878
+ ANDCC R3, R4, R5 // 7c851839
+ OR R3, R4 // 7c841b78
+ OR R3, R4, R5 // 7c851b78
+ ORN R3, R4, R5 // 7c851b38
+ ORCC R3, R4, R5 // 7c851b79
+ XOR R3, R4 // 7c841a78
+ XOR R3, R4, R5 // 7c851a78
+ XORCC R3, R4, R5 // 7c851a79
+ NAND R3, R4, R5 // 7c851bb8
+ NANDCC R3, R4, R5 // 7c851bb9
+ EQV R3, R4, R5 // 7c851a38
+ EQVCC R3, R4, R5 // 7c851a39
+ NOR R3, R4, R5 // 7c8518f8
+ NORCC R3, R4, R5 // 7c8518f9
+
+ SUB R3, R4 // 7c832050
+ SUB R3, R4, R5 // 7ca32050
+ SUBC R3, R4 // 7c832010
+ SUBC R3, R4, R5 // 7ca32010
+
+ MULLW R3, R4 // 7c8419d6
+ MULLW R3, R4, R5 // 7ca419d6
+ MULLW $10, R3 // 1c63000a
+ MULLW $10000000, R3 // 641f009863ff96807c7f19d6
+
+ MULLWCC R3, R4, R5 // 7ca419d7
+ MULHW R3, R4, R5 // 7ca41896
+
+ MULHWU R3, R4, R5 // 7ca41816
+ MULLD R3, R4 // 7c8419d2
+ MULLD R4, R4, R5 // 7ca421d2
+ MULLD $20, R4 // 1c840014
+ MULLD $200000000, R4 // 641f0beb63ffc2007c9f21d2
+
+ MULLDCC R3, R4, R5 // 7ca419d3
+ MULHD R3, R4, R5 // 7ca41892
+ MULHDCC R3, R4, R5 // 7ca41893
+
+ MULLWV R3, R4 // 7c841dd6
+ MULLWV R3, R4, R5 // 7ca41dd6
+ MULLWVCC R3, R4, R5 // 7ca41dd7
+ MULHWUCC R3, R4, R5 // 7ca41817
+ MULLDV R3, R4, R5 // 7ca41dd2
+ MULLDVCC R3, R4, R5 // 7ca41dd3
+
+ DIVD R3,R4 // 7c841bd2
+ DIVD R3, R4, R5 // 7ca41bd2
+ DIVDCC R3,R4, R5 // 7ca41bd3
+ DIVDU R3, R4, R5 // 7ca41b92
+ DIVDV R3, R4, R5 // 7ca41fd2
+ DIVDUCC R3, R4, R5 // 7ca41b93
+ DIVDVCC R3, R4, R5 // 7ca41fd3
+ DIVDUV R3, R4, R5 // 7ca41f92
+ DIVDUVCC R3, R4, R5 // 7ca41f93
+ DIVDE R3, R4, R5 // 7ca41b52
+ DIVDECC R3, R4, R5 // 7ca41b53
+ DIVDEU R3, R4, R5 // 7ca41b12
+ DIVDEUCC R3, R4, R5 // 7ca41b13
+
+ REM R3, R4, R5 // 7fe41bd67fff19d67cbf2050
+ REMU R3, R4, R5 // 7fe41b967fff19d67bff00287cbf2050
+ REMD R3, R4, R5 // 7fe41bd27fff19d27cbf2050
+ REMDU R3, R4, R5 // 7fe41b927fff19d27cbf2050
+
+ MADDHD R3,R4,R5,R6 // 10c32170
+ MADDHDU R3,R4,R5,R6 // 10c32171
+
+ MODUD R3, R4, R5 // 7ca41a12
+ MODUW R3, R4, R5 // 7ca41a16
+ MODSD R3, R4, R5 // 7ca41e12
+ MODSW R3, R4, R5 // 7ca41e16
+
+ SLW $8, R3, R4 // 5464402e
+ SLW R3, R4, R5 // 7c851830
+ SLWCC R3, R4 // 7c841831
+ SLD $16, R3, R4 // 786483e4
+ SLD R3, R4, R5 // 7c851836
+ SLDCC R3, R4 // 7c841837
+
+ SRW $8, R3, R4 // 5464c23e
+ SRW R3, R4, R5 // 7c851c30
+ SRWCC R3, R4 // 7c841c31
+ SRAW $8, R3, R4 // 7c644670
+ SRAW R3, R4, R5 // 7c851e30
+ SRAWCC R3, R4 // 7c841e31
+ SRD $16, R3, R4 // 78648402
+ SRD R3, R4, R5 // 7c851c36
+ SRDCC R3, R4 // 7c841c37
+ SRAD $16, R3, R4 // 7c648674
+ SRAD R3, R4, R5 // 7c851e34
+ SRDCC R3, R4 // 7c841c37
+ ROTLW $16, R3, R4 // 5464803e
+ ROTLW R3, R4, R5 // 5c85183e
+ EXTSWSLI $3, R4, R5 // 7c851ef4
+ RLWMI $7, R3, $65535, R6 // 50663c3e
+ RLWMICC $7, R3, $65535, R6 // 50663c3f
+ RLWNM $3, R4, $7, R6 // 54861f7e
+ RLWNMCC $3, R4, $7, R6 // 54861f7f
+ RLDMI $0, R4, $7, R6 // 7886076c
+ RLDMICC $0, R4, $7, R6 // 7886076d
+ RLDIMI $0, R4, $7, R6 // 788601cc
+ RLDIMICC $0, R4, $7, R6 // 788601cd
+ RLDC $0, R4, $15, R6 // 78860728
+ RLDCCC $0, R4, $15, R6 // 78860729
+ RLDCL $0, R4, $7, R6 // 78860770
+ RLDCLCC $0, R4, $15, R6 // 78860721
+ RLDCR $0, R4, $-16, R6 // 788606f2
+ RLDCRCC $0, R4, $-16, R6 // 788606f3
+ RLDICL $0, R4, $15, R6 // 788603c0
+ RLDICLCC $0, R4, $15, R6 // 788603c1
+ RLDICR $0, R4, $15, R6 // 788603c4
+ RLDICRCC $0, R4, $15, R6 // 788603c5
+ RLDIC $0, R4, $15, R6 // 788603c8
+ RLDICCC $0, R4, $15, R6 // 788603c9
+ CLRLSLWI $16, R5, $8, R4 // 54a4422e
+ CLRLSLDI $24, R4, $2, R3 // 78831588
+
+ BEQ 0(PC) // 41820000
+ BEQ CR1,0(PC) // 41860000
+ BGE 0(PC) // 40800000
+ BGE CR2,0(PC) // 40880000
+ BGT 4(PC) // 41810010
+ BGT CR3,4(PC) // 418d0010
+ BLE 0(PC) // 40810000
+ BLE CR4,0(PC) // 40910000
+ BLT 0(PC) // 41800000
+ BLT CR5,0(PC) // 41940000
+ BNE 0(PC) // 40820000
+ BLT CR6,0(PC) // 41980000
+ JMP 8(PC) // 48000010
-//inst:
-//
-// load ints and bytes
-//
-// LMOVW rreg ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW R1, R2
-
-// LMOVW addr ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW foo<>+4(SB), R2
- MOVW 16(R1), R2
-
-// LMOVW regaddr ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW (R1), R2
- MOVW (R1+R2), R3 // MOVW (R1)(R2*1), R3
-
-// LMOVB rreg ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW R1, R2
-
-// LMOVB addr ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVB foo<>+3(SB), R2
- MOVB 16(R1), R2
-
-// LMOVB regaddr ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVB (R1), R2
- MOVB (R1+R2), R3 // MOVB (R1)(R2*1), R3
-
-//
-// load floats
-//
-// LFMOV addr ',' freg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- FMOVD foo<>+4(SB), F2
- FMOVD 16(R1), F2
-
-// LFMOV regaddr ',' freg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- FMOVD (R1), F2
-
-// LFMOV fimm ',' freg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- FMOVD $0.1, F2 // FMOVD $(0.10000000000000001), F2
-
-// LFMOV freg ',' freg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- FMOVD F1, F2
-
-// LFMOV freg ',' addr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- FMOVD F2, foo<>+4(SB)
- FMOVD F2, 16(R1)
-
-// LFMOV freg ',' regaddr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- FMOVD F2, (R1)
-
-//
-// store ints and bytes
-//
-// LMOVW rreg ',' addr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW R1, foo<>+3(SB)
- MOVW R1, 16(R2)
-
-// LMOVW rreg ',' regaddr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW R1, (R1)
- MOVW R1, (R2+R3) // MOVW R1, (R2)(R3*1)
-
-// LMOVB rreg ',' addr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVB R1, foo<>+3(SB)
- MOVB R1, 16(R2)
-
-// LMOVB rreg ',' regaddr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVB R1, (R1)
- MOVB R1, (R2+R3) // MOVB R1, (R2)(R3*1)
-//
-// store floats
-//
-// LMOVW freg ',' addr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- FMOVD F1, foo<>+4(SB)
- FMOVD F1, 16(R2)
-
-// LMOVW freg ',' regaddr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- FMOVD F1, (R1)
-
-//
-// floating point status
-//
-// LMOVW fpscr ',' freg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVFL FPSCR, F1
-
-// LMOVW freg ',' fpscr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVFL F1, FPSCR
-
-// LMOVW freg ',' imm ',' fpscr
-// {
-// outgcode(int($1), &$2, 0, &$4, &$6);
-// }
- MOVFL F1, $4, FPSCR
-
-// LMOVW fpscr ',' creg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVFL FPSCR, CR0
-
-// LMTFSB imm ',' con
-// {
-// outcode(int($1), &$2, int($4), &nullgen);
-// }
-//TODO 9a doesn't work MTFSB0 $4, 4
-
-//
-// field moves (mtcrf)
-//
-// LMOVW rreg ',' imm ',' lcr
-// {
-// outgcode(int($1), &$2, 0, &$4, &$6);
-// }
-// TODO 9a doesn't work MOVFL R1,$4,CR
-
-// LMOVW rreg ',' creg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW R1, CR1
-
-// LMOVW rreg ',' lcr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW R1, CR
-
-//
-// integer operations
-// logical instructions
-// shift instructions
-// unary instructions
-//
-// LADDW rreg ',' sreg ',' rreg
-// {
-// outcode(int($1), &$2, int($4), &$6);
-// }
- ADD R1, R2, R3
-
-// LADDW imm ',' sreg ',' rreg
-// {
-// outcode(int($1), &$2, int($4), &$6);
-// }
- ADD $1, R2, R3
-
-// LADDW rreg ',' imm ',' rreg
-// {
-// outgcode(int($1), &$2, 0, &$4, &$6);
-// }
-//TODO 9a trouble ADD R1, $2, R3 maybe swap rreg and imm
-
-// LADDW rreg ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- ADD R1, R2
-
-// LADDW imm ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- ADD $4, R1
-
-// LLOGW rreg ',' sreg ',' rreg
-// {
-// outcode(int($1), &$2, int($4), &$6);
-// }
- ADDE R1, R2, R3
-
-// LLOGW rreg ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- ADDE R1, R2
-
-// LSHW rreg ',' sreg ',' rreg
-// {
-// outcode(int($1), &$2, int($4), &$6);
-// }
- SLW R1, R2, R3
-
-// LSHW rreg ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- SLW R1, R2
-
-// LSHW imm ',' sreg ',' rreg
-// {
-// outcode(int($1), &$2, int($4), &$6);
-// }
- SLW $4, R1, R2
-
-// LSHW imm ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- SLW $4, R1
-
-// LABS rreg ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- SLW $4, R1
-
-// LABS rreg
-// {
-// outcode(int($1), &$2, 0, &$2);
-// }
- SUBME R1 // SUBME R1, R1
-
-//
-// multiply-accumulate
-//
-// LMA rreg ',' sreg ',' rreg
-// {
-// outcode(int($1), &$2, int($4), &$6);
-// }
-//TODO this instruction is undefined in lex.go LMA R1, R2, R3 NOT SUPPORTED (called MAC)
-
-//
-// move immediate: macro for cau+or, addi, addis, and other combinations
-//
-// LMOVW imm ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW $1, R1
-
-// LMOVW ximm ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW $1, R1
- MOVW $foo(SB), R1
-
-// condition register operations
-//
-// LCROP cbit ',' cbit
-// {
-// outcode(int($1), &$2, int($4.Reg), &$4);
-// }
-//TODO 9a trouble CREQV 1, 2 delete? liblink encodes like a divide (maybe wrong too)
-
-// LCROP cbit ',' con ',' cbit
-// {
-// outcode(int($1), &$2, int($4), &$6);
-// }
-//TODO 9a trouble CREQV 1, 2, 3
-
-//
-// condition register moves
-// move from machine state register
-//
-// LMOVW creg ',' creg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVFL CR0, CR1
-
-// LMOVW psr ',' creg // TODO: should psr should be fpscr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
-//TODO 9a trouble MOVW FPSCR, CR1
-
-// LMOVW lcr ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW CR, R1
-
-// LMOVW psr ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW SPR(0), R1
- MOVW SPR(7), R1
-
-// LMOVW xlreg ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW LR, R1
- MOVW CTR, R1
-
-// LMOVW rreg ',' xlreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW R1, LR
- MOVW R1, CTR
-
-// LMOVW creg ',' psr // TODO doesn't exist
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
-//TODO 9a trouble MOVW CR1, SPR(7)
-
-// LMOVW rreg ',' psr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW R1, SPR(7)
-
-//
-// branch, branch conditional
-// branch conditional register
-// branch conditional to count register
-//
-// LBRA rel
-// {
-// outcode(int($1), &nullgen, 0, &$2);
-// }
- BEQ CR1, 2(PC)
-label0:
- BR 1(PC) // JMP 1(PC)
- BEQ CR1, 2(PC)
- BR label0+0 // JMP 62
-
-// LBRA addr
-// {
-// outcode(int($1), &nullgen, 0, &$2);
-// }
- BEQ CR1, 2(PC)
- BR LR // JMP LR
- BEQ CR1, 2(PC)
-// BR 0(R1) // TODO should work
- BEQ CR1, 2(PC)
- BR foo+0(SB) // JMP foo(SB)
-
-// LBRA '(' xlreg ')'
-// {
-// outcode(int($1), &nullgen, 0, &$3);
-// }
- BEQ CR1, 2(PC)
- BR (CTR) // JMP CTR
-
-// LBRA ',' rel // asm doesn't support the leading comma
-// {
-// outcode(int($1), &nullgen, 0, &$3);
-// }
-// LBRA ',' addr // asm doesn't support the leading comma
-// {
-// outcode(int($1), &nullgen, 0, &$3);
-// }
-// LBRA ',' '(' xlreg ')' // asm doesn't support the leading comma
-// {
-// outcode(int($1), &nullgen, 0, &$4);
-// }
-// LBRA creg ',' rel
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
-label1:
- BEQ CR1, 1(PC)
- BEQ CR1, label1 // BEQ CR1, 72
-
-// LBRA creg ',' addr // TODO DOES NOT WORK in 9a
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
-
-// LBRA creg ',' '(' xlreg ')' // TODO DOES NOT WORK in 9a
-// {
-// outcode(int($1), &$2, 0, &$5);
-// }
-
-// LBRA con ',' rel // TODO DOES NOT WORK in 9a
-// {
-// outcode(int($1), &nullgen, int($2), &$4);
-// }
-
-// LBRA con ',' addr // TODO DOES NOT WORK in 9a
-// {
-// outcode(int($1), &nullgen, int($2), &$4);
-// }
-
-// LBRA con ',' '(' xlreg ')'
-// {
-// outcode(int($1), &nullgen, int($2), &$5);
-// }
-// BC 4, (CTR) // TODO - should work
-
-// LBRA con ',' con ',' rel
-// {
-// var g obj.Addr
-// g = nullgen;
-// g.Type = obj.TYPE_CONST;
-// g.Offset = $2;
-// outcode(int($1), &g, int(REG_R0+$4), &$6);
-// }
-// BC 3, 4, label1 // TODO - should work
-
-// LBRA con ',' con ',' addr // TODO mystery
-// {
-// var g obj.Addr
-// g = nullgen;
-// g.Type = obj.TYPE_CONST;
-// g.Offset = $2;
-// outcode(int($1), &g, int(REG_R0+$4), &$6);
-// }
-//TODO 9a trouble BC 3, 3, 4(R1)
-
-// LBRA con ',' con ',' '(' xlreg ')'
-// {
-// var g obj.Addr
-// g = nullgen;
-// g.Type = obj.TYPE_CONST;
-// g.Offset = $2;
-// outcode(int($1), &g, int(REG_R0+$4), &$7);
-// }
- BC 3, 3, (LR) // BC $3, R3, LR
-
-//
-// conditional trap // TODO NOT DEFINED
-// TODO these instructions are not in lex.go
-//
-// LTRAP rreg ',' sreg
-// {
-// outcode(int($1), &$2, int($4), &nullgen);
-// }
-// LTRAP imm ',' sreg
-// {
-// outcode(int($1), &$2, int($4), &nullgen);
-// }
-// LTRAP rreg comma
-// {
-// outcode(int($1), &$2, 0, &nullgen);
-// }
-// LTRAP comma
-// {
-// outcode(int($1), &nullgen, 0, &nullgen);
-// }
-
-//
-// floating point operate
-//
-// LFCONV freg ',' freg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- FABS F1, F2
-
-// LFADD freg ',' freg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- FADD F1, F2
-
-// LFADD freg ',' freg ',' freg
-// {
-// outcode(int($1), &$2, int($4.Reg), &$6);
-// }
- FADD F1, F2, F3
-
-// LFMA freg ',' freg ',' freg ',' freg
-// {
-// outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
-// }
- FMADD F1, F2, F3, F4
-
-// LFCMP freg ',' freg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- FCMPU F1, F2
-
-// LFCMP freg ',' freg ',' creg
-// {
-// outcode(int($1), &$2, int($6.Reg), &$4);
-// }
-// FCMPU F1, F2, CR0
-
-// FTDIV FRA, FRB, BF produces
-// ftdiv BF, FRA, FRB
- FTDIV F1,F2,$7
-
-// FTSQRT FRB, BF produces
-// ftsqrt BF, FRB
- FTSQRT F2,$7
-
-// FCFID
-// FCFIDS
-
- FCFID F2,F3
- FCFIDCC F3,F3
- FCFIDS F2,F3
- FCFIDSCC F2,F3
-
-//
-// CMP
-//
-// LCMP rreg ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- CMP R1, R2
-
-// LCMP rreg ',' imm
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- CMP R1, $4
-
-// LCMP rreg ',' rreg ',' creg
-// {
-// outcode(int($1), &$2, int($6.Reg), &$4);
-// }
- CMP R1, R2, CR0 // CMP R1, CR0, R2
-
-// LCMP rreg ',' imm ',' creg
-// {
-// outcode(int($1), &$2, int($6.Reg), &$4);
-// }
- CMP R1, $4, CR0 // CMP R1, CR0, $4
-
-// CMPB RS,RB,RA produces
-// cmpb RA,RS,RB
- CMPB R2,R2,R1
-
-// CMPEQB RA,RB,BF produces
-// cmpeqb BF,RA,RB
- CMPEQB R1, R2, CR0
-
-//
-// rotate extended mnemonics map onto other shift instructions
-//
-
- ROTL $12,R2,R3
- ROTL R2,R3,R4
- ROTLW $9,R2,R3
- ROTLW R2,R3,R4
-
-//
-// rotate and mask
-//
-// LRLWM imm ',' rreg ',' imm ',' rreg
-// {
-// outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
-// }
- RLDC $4, R1, $16, R2
-
-// LRLWM imm ',' rreg ',' mask ',' rreg
-// {
-// outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
-// }
- RLDC $26, R1, 4, 5, R2 // RLDC $26, R1, $201326592, R2
-
-// LRLWM rreg ',' rreg ',' imm ',' rreg
-// {
-// outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
-// }
- RLDCL R1, R2, $7, R3
-
-// LRLWM rreg ',' rreg ',' mask ',' rreg
-// {
-// outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
-// }
- RLWMI R1, R2, 4, 5, R3 // RLWMI R1, R2, $201326592, R3
-
-
-// opcodes added with constant shift counts, not masks
-
- RLDICR $3, R2, $24, R4
-
- RLDICL $1, R2, $61, R6
-
- RLDIMI $7, R2, $52, R7
-
-// opcodes for right and left shifts, const and reg shift counts
-
- SLD $4, R3, R4
- SLD R2, R3, R4
- SLW $4, R3, R4
- SLW R2, R3, R4
- SRD $8, R3, R4
- SRD R2, R3, R4
- SRW $8, R3, R4
- SRW R2, R3, R4
-
-//
-// load/store multiple
-//
-// LMOVMW addr ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
-// MOVMW foo+0(SB), R2 // TODO TLS broke this!
- MOVMW 4(R1), R2
-
-// LMOVMW rreg ',' addr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
-// MOVMW R1, foo+0(SB) // TODO TLS broke this!
- MOVMW R1, 4(R2)
-
-//
-// various indexed load/store
-// indexed unary (eg, cache clear)
-//
-// LXLD regaddr ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- LSW (R1), R2
- LSW (R1+R2), R3 // LSW (R1)(R2*1), R3
-
-// LXLD regaddr ',' imm ',' rreg
-// {
-// outgcode(int($1), &$2, 0, &$4, &$6);
-// }
- LSW (R1), $1, R2
- LSW (R1+R2), $1, R3 // LSW (R1)(R2*1), $1, R3
-
-// LXST rreg ',' regaddr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- STSW R1, (R2)
- STSW R1, (R2+R3) // STSW R1, (R2)(R3*1)
-
-// LXST rreg ',' imm ',' regaddr
-// {
-// outgcode(int($1), &$2, 0, &$4, &$6);
-// }
- STSW R1, $1, (R2)
- STSW R1, $1, (R2+R3) // STSW R1, $1, (R2)(R3*1)
-
-// LXMV regaddr ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVHBR (R1), R2
- MOVHBR (R1+R2), R3 // MOVHBR (R1)(R2*1), R3
-
-// LXMV rreg ',' regaddr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVHBR R1, (R2)
- MOVHBR R1, (R2+R3) // MOVHBR R1, (R2)(R3*1)
-
-// LXOP regaddr
-// {
-// outcode(int($1), &$2, 0, &nullgen);
-// }
- DCBF (R1)
- DCBF (R1+R2) // DCBF (R1)(R2*1)
- DCBF (R1), $1
- DCBF (R1)(R2*1), $1
- DCBT (R1), $1
- DCBT (R1)(R2*1), $1
-
-// LDMX (RB)(RA*1),RT produces
-// ldmx RT,RA,RB
- LDMX (R2)(R1*1), R3
-
-// Population count, X-form
-// RS,RA produces
-// RA,RS
- POPCNTD R1,R2
- POPCNTW R1,R2
- POPCNTB R1,R2
-
-// Copysign
- FCPSGN F1,F2,F3
-
-// Random number generator, X-form
-// DARN L,RT produces
-// darn RT,L
- DARN $1, R1
-
-// Copy/Paste facility
-// RB,RA produces
-// RA,RB
- COPY R2,R1
- PASTECC R2,R1
-
-// Modulo signed/unsigned double/word X-form
-// RA,RB,RT produces
-// RT,RA,RB
- MODUD R3,R4,R5
- MODUW R3,R4,R5
- MODSD R3,R4,R5
- MODSW R3,R4,R5
-
-// VMX instructions
-
-// Described as:
-// ,
-// produces
-//
-
-// Vector load, VX-form
-// (RB)(RA*1),VRT produces
-// VRT,RA,RB
- LVEBX (R1)(R2*1), V0
- LVEHX (R3)(R4*1), V1
- LVEWX (R5)(R6*1), V2
- LVX (R7)(R8*1), V3
- LVXL (R9)(R10*1), V4
- LVSL (R11)(R12*1), V5
- LVSR (R14)(R15*1), V6
-
-// Vector store, VX-form
-// VRT,(RB)(RA*1) produces
-// VRT,RA,RB
- STVEBX V31, (R1)(R2*1)
- STVEHX V30, (R2)(R3*1)
- STVEWX V29, (R4)(R5*1)
- STVX V28, (R6)(R7*1)
- STVXL V27, (R9)(R9*1)
-
-// Vector AND, VX-form
-// VRA,VRB,VRT produces
-// VRT,VRA,VRB
- VAND V10, V9, V8
- VANDC V15, V14, V13
- VNAND V19, V18, V17
-
-// Vector OR, VX-form
-// VRA,VRB,VRT produces
-// VRT,VRA,VRB
- VOR V26, V25, V24
- VORC V23, V22, V21
- VNOR V20, V19, V18
- VXOR V17, V16, V15
- VEQV V14, V13, V12
-
-// Vector ADD, VX-form
-// VRA,VRB,VRT produces
-// VRT,VRA,VRB
- VADDUBM V3, V2, V1
- VADDUHM V3, V2, V1
- VADDUWM V3, V2, V1
- VADDUDM V3, V2, V1
- VADDUQM V3, V2, V1
- VADDCUQ V3, V2, V1
- VADDCUW V3, V2, V1
- VADDUBS V3, V2, V1
- VADDUHS V3, V2, V1
- VADDUWS V3, V2, V1
- VADDSBS V3, V2, V1
- VADDSHS V3, V2, V1
- VADDSWS V3, V2, V1
-
-// Vector ADD extended, VA-form
-// VRA,VRB,VRC,VRT produces
-// VRT,VRA,VRB,VRC
- VADDEUQM V4, V3, V2, V1
- VADDECUQ V4, V3, V2, V1
-
-// Vector multiply, VX-form
-// VRA,VRB,VRT produces
-// VRT,VRA,VRB
- VMULESB V2, V3, V1
- VMULOSB V2, V3, V1
- VMULEUB V2, V3, V1
- VMULOUB V2, V3, V1
- VMULESH V2, V3, V1
- VMULOSH V2, V3, V1
- VMULEUH V2, V3, V1
- VMULOUH V2, V3, V1
- VMULESW V2, V3, V1
- VMULOSW V2, V3, V1
- VMULEUW V2, V3, V1
- VMULOUW V2, V3, V1
- VMULUWM V2, V3, V1
-
-// Vector polynomial multiply-sum, VX-form
-// VRA,VRB,VRT produces
-// VRT,VRA,VRB
- VPMSUMB V2, V3, V1
- VPMSUMH V2, V3, V1
- VPMSUMW V2, V3, V1
- VPMSUMD V2, V3, V1
-
-// Vector multiply-sum, VA-form
-// VRA, VRB, VRC, VRT produces
-// VRT, VRA, VRB, VRC
- VMSUMUDM V4, V3, V2, V1
-
-// Vector SUB, VX-form
-// VRA,VRB,VRT produces
-// VRT,VRA,VRB
- VSUBUBM V3, V2, V1
- VSUBUHM V3, V2, V1
- VSUBUWM V3, V2, V1
- VSUBUDM V3, V2, V1
- VSUBUQM V3, V2, V1
- VSUBCUQ V3, V2, V1
- VSUBCUW V3, V2, V1
- VSUBUBS V3, V2, V1
- VSUBUHS V3, V2, V1
- VSUBUWS V3, V2, V1
- VSUBSBS V3, V2, V1
- VSUBSHS V3, V2, V1
- VSUBSWS V3, V2, V1
-
-// Vector SUB extended, VA-form
-// VRA,VRB,VRC,VRT produces
-// VRT,VRA,VRB,VRC
- VSUBEUQM V4, V3, V2, V1
- VSUBECUQ V4, V3, V2, V1
-
-// Vector rotate, VX-form
-// VRA,VRB,VRT produces
-// VRT,VRA,VRB
- VRLB V2, V1, V0
- VRLH V2, V1, V0
- VRLW V2, V1, V0
- VRLD V2, V1, V0
-
-// Vector shift, VX-form
-// VRA,VRB,VRT
-// VRT,VRA,VRB
- VSLB V2, V1, V0
- VSLH V2, V1, V0
- VSLW V2, V1, V0
- VSL V2, V1, V0
- VSLO V2, V1, V0
- VSRB V2, V1, V0
- VSRH V2, V1, V0
- VSRW V2, V1, V0
- VSR V2, V1, V0
- VSRO V2, V1, V0
- VSLD V2, V1, V0
- VSRD V2, V1, V0
- VSRAB V2, V1, V0
- VSRAH V2, V1, V0
- VSRAW V2, V1, V0
- VSRAD V2, V1, V0
-
-// Vector shift by octect immediate, VA-form with SHB 4-bit field
-// SHB,VRA,VRB,VRT produces
-// VRT,VRA,VRB,SHB
- VSLDOI $4, V2, V1, V0
-
-// Vector merge odd and even word
-// VRA,VRB,VRT produces
-// VRT,VRA,VRB
-
- VMRGOW V4,V5,V6
- VMRGEW V4,V5,V6
-
-// Vector count, VX-form
-// VRB,VRT produces
-// VRT,VRB
- VCLZB V4, V5
- VCLZH V4, V5
- VCLZW V4, V5
- VCLZD V4, V5
- VPOPCNTB V4, V5
- VPOPCNTH V4, V5
- VPOPCNTW V4, V5
- VPOPCNTD V4, V5
-
-// Vector compare, VC-form
-// VRA,VRB,VRT produces
-// VRT,VRA,VRB
-// * Note: 'CC' suffix denotes Rc=1
-// i.e. vcmpequb. v3,v1,v2 equals VCMPEQUBCC V1,V2,V3
- VCMPEQUB V3, V2, V1
- VCMPEQUBCC V3, V2, V1
- VCMPEQUH V3, V2, V1
- VCMPEQUHCC V3, V2, V1
- VCMPEQUW V3, V2, V1
- VCMPEQUWCC V3, V2, V1
- VCMPEQUD V3, V2, V1
- VCMPEQUDCC V3, V2, V1
- VCMPGTUB V3, V2, V1
- VCMPGTUBCC V3, V2, V1
- VCMPGTUH V3, V2, V1
- VCMPGTUHCC V3, V2, V1
- VCMPGTUW V3, V2, V1
- VCMPGTUWCC V3, V2, V1
- VCMPGTUD V3, V2, V1
- VCMPGTUDCC V3, V2, V1
- VCMPGTSB V3, V2, V1
- VCMPGTSBCC V3, V2, V1
- VCMPGTSH V3, V2, V1
- VCMPGTSHCC V3, V2, V1
- VCMPGTSW V3, V2, V1
- VCMPGTSWCC V3, V2, V1
- VCMPGTSD V3, V2, V1
- VCMPGTSDCC V3, V2, V1
- VCMPNEZB V3, V2, V1
- VCMPNEZBCC V3, V2, V1
- VCMPNEB V3, V2, V1
- VCMPNEBCC V3, V2, V1
- VCMPNEH V3, V2, V1
- VCMPNEHCC V3, V2, V1
- VCMPNEW V3, V2, V1
- VCMPNEWCC V3, V2, V1
-
-// Vector permute, VA-form
-// VRA,VRB,VRC,VRT produces
-// VRT,VRA,VRB,VRC
- VPERM V3, V2, V1, V0
- VPERMXOR V3, V2, V1, V0
- VPERMR V3, V2, V1, V0
-
-// Vector bit permute, VX-form
-// VRA,VRB,VRT produces
-// VRT,VRA,VRB
- VBPERMQ V3,V1,V2
- VBPERMD V3,V1,V2
-
-// Vector select, VA-form
-// VRA,VRB,VRC,VRT produces
-// VRT,VRA,VRB,VRC
- VSEL V3, V2, V1, V0
-
-// Vector splat, VX-form with 4-bit UIM field
-// UIM,VRB,VRT produces
-// VRT,VRB,UIM
- VSPLTB $15, V1, V0
- VSPLTH $7, V1, V0
- VSPLTW $3, V1, V0
-
-// Vector splat immediate signed, VX-form with 5-bit SIM field
-// SIM,VRT produces
-// VRT,SIM
- VSPLTISB $31, V4
- VSPLTISH $31, V4
- VSPLTISW $31, V4
-
-// Vector AES cipher, VX-form
-// VRA,VRB,VRT produces
-// VRT,VRA,VRB
- VCIPHER V3, V2, V1
- VCIPHERLAST V3, V2, V1
- VNCIPHER V3, V2, V1
- VNCIPHERLAST V3, V2, V1
-
-// Vector AES subbytes, VX-form
-// VRA,VRT produces
-// VRT,VRA
- VSBOX V2, V1
-
-// Vector SHA, VX-form with ST bit field and 4-bit SIX field
-// SIX,VRA,ST,VRT produces
-// VRT,VRA,ST,SIX
- VSHASIGMAW $15, V1, $1, V0
- VSHASIGMAD $15, V1, $1, V0
-
-// VSX instructions
-// Described as:
-// ,
-// produces
-//
-
-// VSX load, XX1-form
-// (RB)(RA*1),XT produces
-// XT,RA,RB
- LXVD2X (R1)(R2*1), VS0
- LXVW4X (R1)(R2*1), VS0
- LXVH8X (R1)(R2*1), VS0
- LXVB16X (R1)(R2*1), VS0
- LXVDSX (R1)(R2*1), VS0
- LXSDX (R1)(R2*1), VS0
- LXSIWAX (R1)(R2*1), VS0
- LXSIWZX (R1)(R2*1), VS0
-
-// VSX load with length X-form (also left-justified)
- LXVL R3,R4, VS0
- LXVLL R3,R4, VS0
- LXVX R3,R4, VS0
-// VSX load, DQ-form
-// DQ(RA), XS produces
-// XS, DQ(RA)
- LXV 32752(R1), VS0
-
-// VSX store, XX1-form
-// XS,(RB)(RA*1) produces
-// XS,RA,RB
- STXVD2X VS63, (R1)(R2*1)
- STXVW4X VS63, (R1)(R2*1)
- STXVH8X VS63, (R1)(R2*1)
- STXVB16X VS63, (R1)(R2*1)
- STXSDX VS63, (R1)(R2*1)
- STXSIWX VS63, (R1)(R2*1)
-
-// VSX store, DQ-form
-// DQ(RA), XS produces
-// XS, DQ(RA)
- STXV VS63, -32752(R1)
-
-// VSX store with length, X-form (also left-justified)
- STXVL VS0, R3,R4
- STXVLL VS0, R3,R4
- STXVX VS0, R3,R4
-
-// VSX move from VSR, XX1-form
-// XS,RA produces
-// RA,XS
-// Extended mnemonics accept VMX and FP registers as sources
- MFVSRD VS0, R1
- MFVSRWZ VS33, R1
- MFVSRLD VS63, R1
- MFVRD V0, R1
- MFFPRD F0, R1
-
-// VSX move to VSR, XX1-form
-// RA,XT produces
-// XT,RA
-// Extended mnemonics accept VMX and FP registers as targets
- MTVSRD R1, VS0
- MTVSRWA R1, VS31
- MTVSRWZ R1, VS63
- MTVSRDD R1, R2, VS0
- MTVSRWS R1, VS32
- MTVRD R1, V13
- MTFPRD R1, F24
-
-// VSX AND, XX3-form
-// XA,XB,XT produces
-// XT,XA,XB
- XXLAND VS0,VS1,VS32
- XXLANDC VS0,VS1,VS32
- XXLEQV VS0,VS1,VS32
- XXLNAND VS0,VS1,VS32
-
-// VSX OR, XX3-form
-// XA,XB,XT produces
-// XT,XA,XB
- XXLORC VS0,VS1,VS32
- XXLNOR VS0,VS1,VS32
- XXLORQ VS0,VS1,VS32
- XXLXOR VS0,VS1,VS32
- XXLOR VS0,VS1,VS32
-
-// VSX select, XX4-form
-// XA,XB,XC,XT produces
-// XT,XA,XB,XC
- XXSEL VS0,VS1,VS3,VS32
-
-// VSX merge, XX3-form
-// XA,XB,XT produces
-// XT,XA,XB
- XXMRGHW VS0,VS1,VS32
- XXMRGLW VS0,VS1,VS32
-
-// VSX splat, XX2-form
-// XB,UIM,XT produces
-// XT,XB,UIM
- XXSPLTW VS0,$3,VS32
- XXSPLTIB $26,VS0
-
-// VSX permute, XX3-form
-// XA,XB,XT produces
-// XT,XA,XB
- XXPERM VS0,VS1,VS32
-
-// VSX permute, XX3-form
-// XA,XB,DM,XT produces
-// XT,XA,XB,DM
- XXPERMDI VS0,VS1,$3,VS32
-
-// VSX shift, XX3-form
-// XA,XB,SHW,XT produces
-// XT,XA,XB,SHW
- XXSLDWI VS0,VS1,$3,VS32
-
-// VSX byte-reverse XX2-form
-// XB,XT produces
-// XT,XB
- XXBRQ VS0,VS1
- XXBRD VS0,VS1
- XXBRW VS0,VS1
- XXBRH VS0,VS1
-
-// VSX scalar FP-FP conversion, XX2-form
-// XB,XT produces
-// XT,XB
- XSCVDPSP VS0,VS32
- XSCVSPDP VS0,VS32
- XSCVDPSPN VS0,VS32
- XSCVSPDPN VS0,VS32
-
-// VSX vector FP-FP conversion, XX2-form
-// XB,XT produces
-// XT,XB
- XVCVDPSP VS0,VS32
- XVCVSPDP VS0,VS32
-
-// VSX scalar FP-integer conversion, XX2-form
-// XB,XT produces
-// XT,XB
- XSCVDPSXDS VS0,VS32
- XSCVDPSXWS VS0,VS32
- XSCVDPUXDS VS0,VS32
- XSCVDPUXWS VS0,VS32
-
-// VSX scalar integer-FP conversion, XX2-form
-// XB,XT produces
-// XT,XB
- XSCVSXDDP VS0,VS32
- XSCVUXDDP VS0,VS32
- XSCVSXDSP VS0,VS32
- XSCVUXDSP VS0,VS32
-
-// VSX vector FP-integer conversion, XX2-form
-// XB,XT produces
-// XT,XB
- XVCVDPSXDS VS0,VS32
- XVCVDPSXWS VS0,VS32
- XVCVDPUXDS VS0,VS32
- XVCVDPUXWS VS0,VS32
- XVCVSPSXDS VS0,VS32
- XVCVSPSXWS VS0,VS32
- XVCVSPUXDS VS0,VS32
- XVCVSPUXWS VS0,VS32
-
-// VSX scalar integer-FP conversion, XX2-form
-// XB,XT produces
-// XT,XB
- XVCVSXDDP VS0,VS32
- XVCVSXWDP VS0,VS32
- XVCVUXDDP VS0,VS32
- XVCVUXWDP VS0,VS32
- XVCVSXDSP VS0,VS32
- XVCVSXWSP VS0,VS32
- XVCVUXDSP VS0,VS32
- XVCVUXWSP VS0,VS32
-
-// Multiply-Add High Doubleword
-// RA,RB,RC,RT produces
-// RT,RA,RB,RC
- MADDHD R1,R2,R3,R4
- MADDHDU R1,R2,R3,R4
-
-// Add Extended using alternate carry bit
-// ADDEX RA,RB,CY,RT produces
-// addex RT, RA, RB, CY
- ADDEX R1, R2, $0, R3
-
-// Immediate-shifted operations
-// ADDIS SI, RA, RT produces
-// addis RT, RA, SI
- ADDIS $8, R3, R4
- ADDIS $-1, R3, R4
-
-// ANDISCC UI, RS, RA produces
-// andis. RA, RS, UI
- ANDISCC $7, R4, R5
-
-// ORIS UI, RS, RA produces
-// oris RA, RS, UI
- ORIS $4, R2, R3
-
-// XORIS UI, RS, RA produces
-// xoris RA, RS, UI
- XORIS $1, R1, R2
-
-//
-// NOP
-//
-// LNOP comma // asm doesn't support the trailing comma.
-// {
-// outcode(int($1), &nullgen, 0, &nullgen);
-// }
NOP
-
-// LNOP rreg comma // asm doesn't support the trailing comma.
-// {
-// outcode(int($1), &$2, 0, &nullgen);
-// }
NOP R2
+ NOP F2
+ NOP $4
-// LNOP freg comma // asm doesn't support the trailing comma.
-// {
-// outcode(int($1), &$2, 0, &nullgen);
-// }
- NOP F2
+ CRAND CR1, CR2, CR3 // 4c620a02
+ CRANDN CR1, CR2, CR3 // 4c620902
+ CREQV CR1, CR2, CR3 // 4c620a42
+ CRNAND CR1, CR2, CR3 // 4c6209c2
+ CRNOR CR1, CR2, CR3 // 4c620842
+ CROR CR1, CR2, CR3 // 4c620b82
+ CRORN CR1, CR2, CR3 // 4c620b42
+ CRXOR CR1, CR2, CR3 // 4c620982
-// LNOP ',' rreg // asm doesn't support the leading comma.
-// {
-// outcode(int($1), &nullgen, 0, &$3);
-// }
- NOP R2
+ ISEL $1, R3, R4, R5 // 7ca3205e
+ ISEL $0, R3, R4, R5 // 7ca3201e
+ ISEL $2, R3, R4, R5 // 7ca3209e
+ ISEL $3, R3, R4, R5 // 7ca320de
+ ISEL $4, R3, R4, R5 // 7ca3211e
+ POPCNTB R3, R4 // 7c6400f4
+ POPCNTW R3, R4 // 7c6402f4
+ POPCNTD R3, R4 // 7c6403f4
-// LNOP ',' freg // asm doesn't support the leading comma.
-// {
-// outcode(int($1), &nullgen, 0, &$3);
-// }
- NOP F2
+ PASTECC R3, R4 // 7c23270d
+ COPY R3, R4 // 7c23260c
-// LNOP imm // SYSCALL $num: load $num to R0 before syscall and restore R0 to 0 afterwards.
-// {
-// outcode(int($1), &$2, 0, &nullgen);
-// }
- NOP $4
+ // load-and-reserve
+ LBAR (R4)(R3*1),$1,R5 // 7ca32069
+ LBAR (R4),$0,R5 // 7ca02068
+ LBAR (R3),R5 // 7ca01868
+ LHAR (R4)(R3*1),$1,R5 // 7ca320e9
+ LHAR (R4),$0,R5 // 7ca020e8
+ LHAR (R3),R5 // 7ca018e8
+ LWAR (R4)(R3*1),$1,R5 // 7ca32029
+ LWAR (R4),$0,R5 // 7ca02028
+ LWAR (R3),R5 // 7ca01828
+ LDAR (R4)(R3*1),$1,R5 // 7ca320a9
+ LDAR (R4),$0,R5 // 7ca020a8
+ LDAR (R3),R5 // 7ca018a8
+
+ STBCCC R3, (R4)(R5) // 7c65256d
+ STWCCC R3, (R4)(R5) // 7c65212d
+ STDCCC R3, (R4)(R5) // 7c6521ad
+ STHCCC R3, (R4)(R5)
+ STSW R3, (R4)(R5)
+
+ SYNC // 7c0004ac
+ ISYNC // 4c00012c
+ LWSYNC // 7c2004ac
+
+ DARN $1, R5 // 7ca105e6
+
+ DCBF (R3)(R4) // 7c0418ac
+ DCBI (R3)(R4) // 7c041bac
+ DCBST (R3)(R4) // 7c04186c
+ DCBZ (R3)(R4) // 7c041fec
+ DCBT (R3)(R4) // 7c041a2c
+ ICBI (R3)(R4) // 7c041fac
+
+ // float constants
+ FMOVD $(0.0), F1 // f0210cd0
+ FMOVD $(-0.0), F1 // f0210cd0fc200850
+
+ FMOVD 8(R3), F1 // c8230008
+ FMOVD (R3)(R4), F1 // 7c241cae
+ FMOVDU 8(R3), F1 // cc230008
+ FMOVDU (R3)(R4), F1 // 7c241cee
+ FMOVS 4(R3), F1 // c0230004
+ FMOVS (R3)(R4), F1 // 7c241c2e
+ FMOVSU 4(R3), F1 // c4230004
+ FMOVSU (R3)(R4), F1 // 7c241c6e
+
+ FMOVD F1, 8(R3) // d8230008
+ FMOVD F1, (R3)(R4) // 7c241dae
+ FMOVDU F1, 8(R3) // dc230008
+ FMOVDU F1, (R3)(R4) // 7c241dee
+ FMOVS F1, 4(R3) // d0230004
+ FMOVS F1, (R3)(R4) // 7c241d2e
+ FMOVSU F1, 4(R3) // d4230004
+ FMOVSU F1, (R3)(R4) // 7c241d6e
+ FADD F1, F2 // fc42082a
+ FADD F1, F2, F3 // fc62082a
+ FADDCC F1, F2, F3 // fc62082b
+ FADDS F1, F2 // ec42082a
+ FADDS F1, F2, F3 // ec62082a
+ FADDSCC F1, F2, F3 // ec62082b
+ FSUB F1, F2 // fc420828
+ FSUB F1, F2, F3 // fc620828
+ FSUBCC F1, F2, F3 // fc620829
+ FSUBS F1, F2 // ec420828
+ FSUBS F1, F2, F3 // ec620828
+ FSUBCC F1, F2, F3 // fc620829
+ FMUL F1, F2 // fc420072
+ FMUL F1, F2, F3 // fc620072
+ FMULCC F1, F2, F3 // fc620073
+ FMULS F1, F2 // ec420072
+ FMULS F1, F2, F3 // ec620072
+ FMULSCC F1, F2, F3 // ec620073
+ FDIV F1, F2 // fc420824
+ FDIV F1, F2, F3 // fc620824
+ FDIVCC F1, F2, F3 // fc620825
+ FDIVS F1, F2 // ec420824
+ FDIVS F1, F2, F3 // ec620824
+ FDIVSCC F1, F2, F3 // ec620825
+ FMADD F1, F2, F3, F4 // fc8110fa
+ FMADDCC F1, F2, F3, F4 // fc8110fb
+ FMADDS F1, F2, F3, F4 // ec8110fa
+ FMADDSCC F1, F2, F3, F4 // ec8110fb
+ FMSUB F1, F2, F3, F4 // fc8110f8
+ FMSUBCC F1, F2, F3, F4 // fc8110f9
+ FMSUBS F1, F2, F3, F4 // ec8110f8
+ FMSUBSCC F1, F2, F3, F4 // ec8110f9
+ FNMADD F1, F2, F3, F4 // fc8110fe
+ FNMADDCC F1, F2, F3, F4 // fc8110ff
+ FNMADDS F1, F2, F3, F4 // ec8110fe
+ FNMADDSCC F1, F2, F3, F4 // ec8110ff
+ FNMSUB F1, F2, F3, F4 // fc8110fc
+ FNMSUBCC F1, F2, F3, F4 // fc8110fd
+ FNMSUBS F1, F2, F3, F4 // ec8110fc
+ FNMSUBSCC F1, F2, F3, F4 // ec8110fd
+ FSEL F1, F2, F3, F4 // fc8110ee
+ FSELCC F1, F2, F3, F4 // fc8110ef
+ FABS F1, F2 // fc400a10
+ FABSCC F1, F2 // fc400a11
+ FNEG F1, F2 // fc400850
+ FABSCC F1, F2 // fc400a11
+ FRSP F1, F2 // fc400818
+ FRSPCC F1, F2 // fc400819
+ FCTIW F1, F2 // fc40081c
+ FCTIWCC F1, F2 // fc40081d
+ FCTIWZ F1, F2 // fc40081e
+ FCTIWZCC F1, F2 // fc40081f
+ FCTID F1, F2 // fc400e5c
+ FCTIDCC F1, F2 // fc400e5d
+ FCTIDZ F1, F2 // fc400e5e
+ FCTIDZCC F1, F2 // fc400e5f
+ FCFID F1, F2 // fc400e9c
+ FCFIDCC F1, F2 // fc400e9d
+ FCFIDU F1, F2 // fc400f9c
+ FCFIDUCC F1, F2 // fc400f9d
+ FCFIDS F1, F2 // ec400e9c
+ FCFIDSCC F1, F2 // ec400e9d
+ FRES F1, F2 // ec400830
+ FRESCC F1, F2 // ec400831
+ FRIM F1, F2 // fc400bd0
+ FRIMCC F1, F2 // fc400bd1
+ FRIP F1, F2 // fc400b90
+ FRIPCC F1, F2 // fc400b91
+ FRIZ F1, F2 // fc400b50
+ FRIZCC F1, F2 // fc400b51
+ FRIN F1, F2 // fc400b10
+ FRINCC F1, F2 // fc400b11
+ FRSQRTE F1, F2 // fc400834
+ FRSQRTECC F1, F2 // fc400835
+ FSQRT F1, F2 // fc40082c
+ FSQRTCC F1, F2 // fc40082d
+ FSQRTS F1, F2 // ec40082c
+ FSQRTSCC F1, F2 // ec40082d
+ FCPSGN F1, F2 // fc420810
+ FCPSGNCC F1, F2 // fc420811
+ FCMPO F1, F2 // fc011040
+ FCMPU F1, F2 // fc011000
+ LVX (R3)(R4), V1 // 7c2418ce
+ LVXL (R3)(R4), V1 // 7c241ace
+ LVSL (R3)(R4), V1 // 7c24180c
+ LVSR (R3)(R4), V1 // 7c24184c
+ LVEBX (R3)(R4), V1 // 7c24180e
+ LVEHX (R3)(R4), V1 // 7c24184e
+ LVEWX (R3)(R4), V1 // 7c24188e
+ STVX V1, (R3)(R4) // 7c2419ce
+ STVXL V1, (R3)(R4) // 7c241bce
+ STVEBX V1, (R3)(R4) // 7c24190e
+ STVEHX V1, (R3)(R4) // 7c24194e
+ STVEWX V1, (R3)(R4) // 7c24198e
+
+ VAND V1, V2, V3 // 10611404
+ VANDC V1, V2, V3 // 10611444
+ VNAND V1, V2, V3 // 10611584
+ VOR V1, V2, V3 // 10611484
+ VORC V1, V2, V3 // 10611544
+ VXOR V1, V2, V3 // 106114c4
+ VNOR V1, V2, V3 // 10611504
+ VEQV V1, V2, V3 // 10611684
+ VADDUBM V1, V2, V3 // 10611000
+ VADDUHM V1, V2, V3 // 10611040
+ VADDUWM V1, V2, V3 // 10611080
+ VADDUDM V1, V2, V3 // 106110c0
+ VADDUQM V1, V2, V3 // 10611100
+ VADDCUQ V1, V2, V3 // 10611140
+ VADDCUW V1, V2, V3 // 10611180
+ VADDUBS V1, V2, V3 // 10611200
+ VADDUHS V1, V2, V3 // 10611240
+ VADDUWS V1, V2, V3 // 10611280
+ VSUBUBM V1, V2, V3 // 10611400
+ VSUBUHM V1, V2, V3 // 10611440
+ VSUBUWM V1, V2, V3 // 10611480
+ VSUBUDM V1, V2, V3 // 106114c0
+ VSUBUQM V1, V2, V3 // 10611500
+ VSUBCUQ V1, V2, V3 // 10611540
+ VSUBCUW V1, V2, V3 // 10611580
+ VSUBUBS V1, V2, V3 // 10611600
+ VSUBUHS V1, V2, V3 // 10611640
+ VSUBUWS V1, V2, V3 // 10611680
+ VSUBSBS V1, V2, V3 // 10611700
+ VSUBSHS V1, V2, V3 // 10611740
+ VSUBSWS V1, V2, V3 // 10611780
+ VSUBEUQM V1, V2, V3, V4 // 108110fe
+ VSUBECUQ V1, V2, V3, V4 // 108110ff
+ VMULESB V1, V2, V3 // 10611308
+ VMULOSB V1, V2, V3 // 10611108
+ VMULEUB V1, V2, V3 // 10611208
+ VMULOUB V1, V2, V3 // 10611008
+ VMULESH V1, V2, V3 // 10611348
+ VMULOSH V1, V2, V3 // 10611148
+ VMULEUH V1, V2, V3 // 10611248
+ VMULOUH V1, V2, V3 // 10611048
+ VMULESH V1, V2, V3 // 10611348
+ VMULOSW V1, V2, V3 // 10611188
+ VMULEUW V1, V2, V3 // 10611288
+ VMULOUW V1, V2, V3 // 10611088
+ VMULUWM V1, V2, V3 // 10611089
+ VPMSUMB V1, V2, V3 // 10611408
+ VPMSUMH V1, V2, V3 // 10611448
+ VPMSUMW V1, V2, V3 // 10611488
+ VPMSUMD V1, V2, V3 // 106114c8
+ VMSUMUDM V1, V2, V3, V4 // 108110e3
+ VRLB V1, V2, V3 // 10611004
+ VRLH V1, V2, V3 // 10611044
+ VRLW V1, V2, V3 // 10611084
+ VRLD V1, V2, V3 // 106110c4
+ VSLB V1, V2, V3 // 10611104
+ VSLH V1, V2, V3 // 10611144
+ VSLW V1, V2, V3 // 10611184
+ VSL V1, V2, V3 // 106111c4
+ VSLO V1, V2, V3 // 1061140c
+ VSRB V1, V2, V3 // 10611204
+ VSRH V1, V2, V3 // 10611244
+ VSRW V1, V2, V3 // 10611284
+ VSR V1, V2, V3 // 106112c4
+ VSRO V1, V2, V3 // 1061144c
+ VSLD V1, V2, V3 // 106115c4
+ VSRAB V1, V2, V3 // 10611304
+ VSRAH V1, V2, V3 // 10611344
+ VSRAW V1, V2, V3 // 10611384
+ VSRAD V1, V2, V3 // 106113c4
+ VSLDOI $3, V1, V2, V3 // 106110ec
+ VCLZB V1, V2 // 10400f02
+ VCLZH V1, V2 // 10400f42
+ VCLZW V1, V2 // 10400f82
+ VCLZD V1, V2 // 10400fc2
+ VPOPCNTB V1, V2 // 10400f03
+ VPOPCNTH V1, V2 // 10400f43
+ VPOPCNTW V1, V2 // 10400f83
+ VPOPCNTD V1, V2 // 10400fc3
+ VCMPEQUB V1, V2, V3 // 10611006
+ VCMPEQUBCC V1, V2, V3 // 10611406
+ VCMPEQUH V1, V2, V3 // 10611046
+ VCMPEQUHCC V1, V2, V3 // 10611446
+ VCMPEQUW V1, V2, V3 // 10611086
+ VCMPEQUWCC V1, V2, V3 // 10611486
+ VCMPEQUD V1, V2, V3 // 106110c7
+ VCMPEQUDCC V1, V2, V3 // 106114c7
+ VCMPGTUB V1, V2, V3 // 10611206
+ VCMPGTUBCC V1, V2, V3 // 10611606
+ VCMPGTUH V1, V2, V3 // 10611246
+ VCMPGTUHCC V1, V2, V3 // 10611646
+ VCMPGTUW V1, V2, V3 // 10611286
+ VCMPGTUWCC V1, V2, V3 // 10611686
+ VCMPGTUD V1, V2, V3 // 106112c7
+ VCMPGTUDCC V1, V2, V3 // 106116c7
+ VCMPGTSB V1, V2, V3 // 10611306
+ VCMPGTSBCC V1, V2, V3 // 10611706
+ VCMPGTSH V1, V2, V3 // 10611346
+ VCMPGTSHCC V1, V2, V3 // 10611746
+ VCMPGTSW V1, V2, V3 // 10611386
+ VCMPGTSWCC V1, V2, V3 // 10611786
+ VCMPGTSD V1, V2, V3 // 106113c7
+ VCMPGTSDCC V1, V2, V3 // 106117c7
+ VCMPNEZB V1, V2, V3 // 10611107
+ VCMPNEZBCC V1, V2, V3 // 10611507
+ VCMPNEB V1, V2, V3 // 10611007
+ VCMPNEBCC V1, V2, V3 // 10611407
+ VCMPNEH V1, V2, V3 // 10611047
+ VCMPNEHCC V1, V2, V3 // 10611447
+ VCMPNEW V1, V2, V3 // 10611087
+ VCMPNEWCC V1, V2, V3 // 10611487
+ VPERM V1, V2, V3, V4 // 108110eb
+ VPERMR V1, V2, V3, V4 // 108110fb
+ VPERMXOR V1, V2, V3, V4 // 108110ed
+ VBPERMQ V1, V2, V3 // 1061154c
+ VBPERMD V1, V2, V3 // 106115cc
+ VSEL V1, V2, V3, V4 // 108110ea
+ VSPLTB $1, V1, V2 // 10410a0c
+ VSPLTH $1, V1, V2 // 10410a4c
+ VSPLTW $1, V1, V2 // 10410a8c
+ VSPLTISB $1, V1 // 1021030c
+ VSPLTISW $1, V1 // 1021038c
+ VSPLTISH $1, V1 // 1021034c
+ VCIPHER V1, V2, V3 // 10611508
+ VCIPHERLAST V1, V2, V3 // 10611509
+ VNCIPHER V1, V2, V3 // 10611548
+ VNCIPHERLAST V1, V2, V3 // 10611549
+ VSBOX V1, V2 // 104105c8
+ VSHASIGMAW $1, V1, $15, V2 // 10418e82
+ VSHASIGMAD $2, V1, $15, V2 // 104196c2
+
+ LXVD2X (R3)(R4), VS1 // 7c241e98
+ LXVDSX (R3)(R4), VS1 // 7c241a98
+ LXVH8X (R3)(R4), VS1 // 7c241e58
+ LXVB16X (R3)(R4), VS1 // 7c241ed8
+ LXVW4X (R3)(R4), VS1 // 7c241e18
+ LXV 16(R3), VS1 // f4230011
+ LXVL R3, R4, VS1 // 7c23221a
+ LXVLL R3, R4, VS1 // 7c23225a
+ LXVX R3, R4, VS1 // 7c232218
+ LXSDX (R3)(R4), VS1 // 7c241c98
+ STXVD2X VS1, (R3)(R4) // 7c241f98
+ STXV VS1,16(R3) // f4230015
+ STXVL VS1, R3, R4 // 7c23231a
+ STXVLL VS1, R3, R4 // 7c23235a
+ STXVX VS1, R3, R4 // 7c232318
+ STXVB16X VS1, (R4)(R5) // 7c2527d8
+ STXVH8X VS1, (R4)(R5) // 7c252758
+
+ STXSDX VS1, (R3)(R4) // 7c241d98
+ LXSIWAX (R3)(R4), VS1 // 7c241898
+ STXSIWX VS1, (R3)(R4) // 7c241918
+ MFVSRD VS1, R3 // 7c230066
+ MTFPRD R3, F0 // 7c030166
+ MFVRD V0, R3 // 7c030067
+ MFVSRLD VS63,R4 // 7fe40267
+ MFVSRWZ VS33,R4 // 7c2400e7
+ MTVSRD R3, VS1 // 7c230166
+ MTVRD R3, V13 // 7da30167
+ MTVSRWA R4, VS31 // 7fe401a6
+ MTVSRWS R4, VS32 // 7c040327
+ MTVSRWZ R4, VS63 // 7fe401e7
+ XXBRD VS0, VS1 // f037076c
+ XXBRW VS1, VS2 // f04f0f6c
+ XXBRH VS2, VS3 // f067176c
+ XXLAND VS1, VS2, VS3 // f0611410
+ XXLANDC VS1, VS2, VS3 // f0611450
+ XXLEQV VS0, VS1, VS2 // f0400dd0
+ XXLNAND VS0, VS1, VS2 // f0400d90
+ XXLNOR VS0, VS1, VS32 // f0000d11
+ XXLOR VS1, VS2, VS3 // f0611490
+ XXLORC VS1, VS2, VS3 // f0611550
+ XXLORQ VS1, VS2, VS3 // f0611490
+ XXLXOR VS1, VS2, VS3 // f06114d0
+ XXSEL VS1, VS2, VS3, VS4 // f08110f0
+ XXMRGHW VS1, VS2, VS3 // f0611090
+ XXMRGLW VS1, VS2, VS3 // f0611190
+ XXSPLTW VS1, $1, VS2 // f0410a90
+ XXPERM VS1, VS2, VS3 // f06110d0
+ XXSLDWI VS1, VS2, $1, VS3 // f0611110
+ XSCVDPSP VS1, VS2 // f0400c24
+ XVCVDPSP VS1, VS2 // f0400e24
+ XSCVSXDDP VS1, VS2 // f0400de0
+ XVCVDPSXDS VS1, VS2 // f0400f60
+ XVCVSXDDP VS1, VS2 // f0400fe0
+ XSCVDPSPN VS1,VS32 // f0000c2d
+ XSCVDPSP VS1,VS32 // f0000c25
+ XSCVDPSXDS VS1,VS32 // f0000d61
+ XSCVDPSXWS VS1,VS32 // f0000961
+ XSCVDPUXDS VS1,VS32 // f0000d21
+ XSCVDPUXWS VS1,VS32 // f0000921
+ XSCVSPDPN VS1,VS32 // f0000d2d
+ XSCVSPDP VS1,VS32 // f0000d25
+ XSCVSXDDP VS1,VS32 // f0000de1
+ XSCVSXDSP VS1,VS32 // f0000ce1
+ XSCVUXDDP VS1,VS32 // f0000da1
+ XSCVUXDSP VS1,VS32 // f0000ca1
+ XVCVDPSP VS1,VS32 // f0000e25
+ XVCVDPSXDS VS1,VS32 // f0000f61
+ XVCVDPSXWS VS1,VS32 // f0000b61
+ XVCVDPUXDS VS1,VS32 // f0000f21
+ XVCVDPUXWS VS1,VS32 // f0000b21
+ XVCVSPDP VS1,VS32 // f0000f25
+ XVCVSPSXDS VS1,VS32 // f0000e61
+ XVCVSPSXWS VS1,VS32 // f0000a61
+ XVCVSPUXDS VS1,VS32 // f0000e21
+ XVCVSPUXWS VS1,VS32 // f0000a21
+ XVCVSXDDP VS1,VS32 // f0000fe1
+ XVCVSXDSP VS1,VS32 // f0000ee1
+ XVCVSXWDP VS1,VS32 // f0000be1
+ XVCVSXWSP VS1,VS32 // f0000ae1
+ XVCVUXDDP VS1,VS32 // f0000fa1
+ XVCVUXDSP VS1,VS32 // f0000ea1
+ XVCVUXWDP VS1,VS32 // f0000ba1
+ XVCVUXWSP VS1,VS32 // f0000aa1
+
+ MOVD R3, LR // 7c6803a6
+ MOVD R3, CTR // 7c6903a6
+ MOVD R3, XER // 7c6103a6
+ MOVD LR, R3 // 7c6802a6
+ MOVD CTR, R3 // 7c6902a6
+ MOVD XER, R3 // 7c6102a6
+ MOVFL CR3, CR1 // 4c8c0000
-// RET
-//
-// LRETRN comma // asm doesn't support the trailing comma.
-// {
-// outcode(int($1), &nullgen, 0, &nullgen);
-// }
- BEQ 2(PC)
RET
-
-// More BR/BL cases, and canonical names JMP, CALL.
-
- BEQ 2(PC)
- BR foo(SB) // JMP foo(SB)
- BL foo(SB) // CALL foo(SB)
- BEQ 2(PC)
- JMP foo(SB)
- CALL foo(SB)
- RET foo(SB)
-
-// load-and-reserve
-// L*AR (RB)(RA*1),EH,RT produces
-// l*arx RT,RA,RB,EH
-//
-// Extended forms also accepted. Assumes RA=0, EH=0:
-// L*AR (RB),RT
-// L*AR (RB),EH,RT
- LBAR (R4)(R3*1), $1, R5
- LBAR (R4), $0, R5
- LBAR (R3), R5
- LHAR (R4)(R3*1), $1, R5
- LHAR (R4), $0, R5
- LHAR (R3), R5
- LWAR (R4)(R3*1), $1, R5
- LWAR (R4), $0, R5
- LWAR (R3), R5
- LDAR (R4)(R3*1), $1, R5
- LDAR (R4), $0, R5
- LDAR (R3), R5
-
-// END
-//
-// LEND comma // asm doesn't support the trailing comma.
-// {
-// outcode(int($1), &nullgen, 0, &nullgen);
-// }
- END
diff --git a/src/cmd/asm/internal/asm/testdata/ppc64enc.s b/src/cmd/asm/internal/asm/testdata/ppc64enc.s
deleted file mode 100644
index e26f6f8933..0000000000
--- a/src/cmd/asm/internal/asm/testdata/ppc64enc.s
+++ /dev/null
@@ -1,637 +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.
-
-// Initial set of opcode combinations based on
-// improvements to processing of constant
-// operands.
-
-// Full set will be added at a later date.
-
-#include "../../../../../runtime/textflag.h"
-
-TEXT asmtest(SB),DUPOK|NOSPLIT,$0
- // move constants
- MOVD $1, R3 // 38600001
- MOVD $-1, R4 // 3880ffff
- MOVD $65535, R5 // 6005ffff
- MOVD $65536, R6 // 64060001
- MOVD $-32767, R5 // 38a08001
- MOVD $-32768, R6 // 38c08000
- MOVD $1234567, R5 // 6405001260a5d687
- MOVW $1, R3 // 38600001
- MOVW $-1, R4 // 3880ffff
- MOVW $65535, R5 // 6005ffff
- MOVW $65536, R6 // 64060001
- MOVW $-32767, R5 // 38a08001
- MOVW $-32768, R6 // 38c08000
- MOVW $1234567, R5 // 6405001260a5d687
- MOVD 8(R3), R4 // e8830008
- MOVD (R3)(R4), R5 // 7ca4182a
- MOVW 4(R3), R4 // e8830006
- MOVW (R3)(R4), R5 // 7ca41aaa
- MOVWZ 4(R3), R4 // 80830004
- MOVWZ (R3)(R4), R5 // 7ca4182e
- MOVH 4(R3), R4 // a8830004
- MOVH (R3)(R4), R5 // 7ca41aae
- MOVHZ 2(R3), R4 // a0830002
- MOVHZ (R3)(R4), R5 // 7ca41a2e
- MOVB 1(R3), R4 // 888300017c840774
- MOVB (R3)(R4), R5 // 7ca418ae7ca50774
- MOVBZ 1(R3), R4 // 88830001
- MOVBZ (R3)(R4), R5 // 7ca418ae
- MOVDBR (R3)(R4), R5 // 7ca41c28
- MOVWBR (R3)(R4), R5 // 7ca41c2c
- MOVHBR (R3)(R4), R5 // 7ca41e2c
-
- MOVDU 8(R3), R4 // e8830009
- MOVDU (R3)(R4), R5 // 7ca4186a
- MOVWU (R3)(R4), R5 // 7ca41aea
- MOVWZU 4(R3), R4 // 84830004
- MOVWZU (R3)(R4), R5 // 7ca4186e
- MOVHU 2(R3), R4 // ac830002
- MOVHU (R3)(R4), R5 // 7ca41aee
- MOVHZU 2(R3), R4 // a4830002
- MOVHZU (R3)(R4), R5 // 7ca41a6e
- MOVBU 1(R3), R4 // 8c8300017c840774
- MOVBU (R3)(R4), R5 // 7ca418ee7ca50774
- MOVBZU 1(R3), R4 // 8c830001
- MOVBZU (R3)(R4), R5 // 7ca418ee
-
- MOVD R4, 8(R3) // f8830008
- MOVD R5, (R3)(R4) // 7ca4192a
- MOVW R4, 4(R3) // 90830004
- MOVW R5, (R3)(R4) // 7ca4192e
- MOVH R4, 2(R3) // b0830002
- MOVH R5, (R3)(R4) // 7ca41b2e
- MOVB R4, 1(R3) // 98830001
- MOVB R5, (R3)(R4) // 7ca419ae
- MOVDBR R5, (R3)(R4) // 7ca41d28
- MOVWBR R5, (R3)(R4) // 7ca41d2c
- MOVHBR R5, (R3)(R4) // 7ca41f2c
-
- MOVDU R4, 8(R3) // f8830009
- MOVDU R5, (R3)(R4) // 7ca4196a
- MOVWU R4, 4(R3) // 94830004
- MOVWU R5, (R3)(R4) // 7ca4196e
- MOVHU R4, 2(R3) // b4830002
- MOVHU R5, (R3)(R4) // 7ca41b6e
- MOVBU R4, 1(R3) // 9c830001
- MOVBU R5, (R3)(R4) // 7ca419ee
-
- ADD $1, R3 // 38630001
- ADD $1, R3, R4 // 38830001
- ADD $-1, R4 // 3884ffff
- ADD $-1, R4, R5 // 38a4ffff
- ADD $65535, R5 // 601fffff7cbf2a14
- ADD $65535, R5, R6 // 601fffff7cdf2a14
- ADD $65536, R6 // 3cc60001
- ADD $65536, R6, R7 // 3ce60001
- ADD $-32767, R5 // 38a58001
- ADD $-32767, R5, R4 // 38858001
- ADD $-32768, R6 // 38c68000
- ADD $-32768, R6, R5 // 38a68000
- ADD $1234567, R5 // 641f001263ffd6877cbf2a14
- ADD $1234567, R5, R6 // 641f001263ffd6877cdf2a14
- ADDIS $8, R3 // 3c630008
- ADDIS $1000, R3, R4 // 3c8303e8
-
- ANDCC $1, R3 // 70630001
- ANDCC $1, R3, R4 // 70640001
- ANDCC $-1, R4 // 3be0ffff7fe42039
- ANDCC $-1, R4, R5 // 3be0ffff7fe52039
- ANDCC $65535, R5 // 70a5ffff
- ANDCC $65535, R5, R6 // 70a6ffff
- ANDCC $65536, R6 // 74c60001
- ANDCC $65536, R6, R7 // 74c70001
- ANDCC $-32767, R5 // 3be080017fe52839
- ANDCC $-32767, R5, R4 // 3be080017fe42839
- ANDCC $-32768, R6 // 3be080007fe63039
- ANDCC $-32768, R5, R6 // 3be080007fe62839
- ANDCC $1234567, R5 // 641f001263ffd6877fe52839
- ANDCC $1234567, R5, R6 // 641f001263ffd6877fe62839
- ANDISCC $1, R3 // 74630001
- ANDISCC $1000, R3, R4 // 746403e8
-
- OR $1, R3 // 60630001
- OR $1, R3, R4 // 60640001
- OR $-1, R4 // 3be0ffff7fe42378
- OR $-1, R4, R5 // 3be0ffff7fe52378
- OR $65535, R5 // 60a5ffff
- OR $65535, R5, R6 // 60a6ffff
- OR $65536, R6 // 64c60001
- OR $65536, R6, R7 // 64c70001
- OR $-32767, R5 // 3be080017fe52b78
- OR $-32767, R5, R6 // 3be080017fe62b78
- OR $-32768, R6 // 3be080007fe63378
- OR $-32768, R6, R7 // 3be080007fe73378
- OR $1234567, R5 // 641f001263ffd6877fe52b78
- OR $1234567, R5, R3 // 641f001263ffd6877fe32b78
-
- XOR $1, R3 // 68630001
- XOR $1, R3, R4 // 68640001
- XOR $-1, R4 // 3be0ffff7fe42278
- XOR $-1, R4, R5 // 3be0ffff7fe52278
- XOR $65535, R5 // 68a5ffff
- XOR $65535, R5, R6 // 68a6ffff
- XOR $65536, R6 // 6cc60001
- XOR $65536, R6, R7 // 6cc70001
- XOR $-32767, R5 // 3be080017fe52a78
- XOR $-32767, R5, R6 // 3be080017fe62a78
- XOR $-32768, R6 // 3be080007fe63278
- XOR $-32768, R6, R7 // 3be080007fe73278
- XOR $1234567, R5 // 641f001263ffd6877fe52a78
- XOR $1234567, R5, R3 // 641f001263ffd6877fe32a78
-
- // TODO: the order of CR operands don't match
- CMP R3, R4 // 7c232000
- CMPU R3, R4 // 7c232040
- CMPW R3, R4 // 7c032000
- CMPWU R3, R4 // 7c032040
-
- // TODO: constants for ADDC?
- ADD R3, R4 // 7c841a14
- ADD R3, R4, R5 // 7ca41a14
- ADDC R3, R4 // 7c841814
- ADDC R3, R4, R5 // 7ca41814
- ADDE R3, R4 // 7c841914
- ADDECC R3, R4 // 7c841915
- ADDEV R3, R4 // 7c841d14
- ADDEVCC R3, R4 // 7c841d15
- ADDV R3, R4 // 7c841e14
- ADDVCC R3, R4 // 7c841e15
- ADDCCC R3, R4, R5 // 7ca41815
- ADDME R3, R4 // 7c8301d4
- ADDMECC R3, R4 // 7c8301d5
- ADDMEV R3, R4 // 7c8305d4
- ADDMEVCC R3, R4 // 7c8305d5
- ADDCV R3, R4 // 7c841c14
- ADDCVCC R3, R4 // 7c841c15
- ADDZE R3, R4 // 7c830194
- ADDZECC R3, R4 // 7c830195
- ADDZEV R3, R4 // 7c830594
- ADDZEVCC R3, R4 // 7c830595
- SUBME R3, R4 // 7c8301d0
- SUBMECC R3, R4 // 7c8301d1
- SUBMEV R3, R4 // 7c8305d0
- SUBZE R3, R4 // 7c830190
- SUBZECC R3, R4 // 7c830191
- SUBZEV R3, R4 // 7c830590
- SUBZEVCC R3, R4 // 7c830591
-
- AND R3, R4 // 7c841838
- AND R3, R4, R5 // 7c851838
- ANDN R3, R4, R5 // 7c851878
- ANDCC R3, R4, R5 // 7c851839
- OR R3, R4 // 7c841b78
- OR R3, R4, R5 // 7c851b78
- ORN R3, R4, R5 // 7c851b38
- ORCC R3, R4, R5 // 7c851b79
- XOR R3, R4 // 7c841a78
- XOR R3, R4, R5 // 7c851a78
- XORCC R3, R4, R5 // 7c851a79
- NAND R3, R4, R5 // 7c851bb8
- NANDCC R3, R4, R5 // 7c851bb9
- EQV R3, R4, R5 // 7c851a38
- EQVCC R3, R4, R5 // 7c851a39
- NOR R3, R4, R5 // 7c8518f8
- NORCC R3, R4, R5 // 7c8518f9
-
- SUB R3, R4 // 7c832050
- SUB R3, R4, R5 // 7ca32050
- SUBC R3, R4 // 7c832010
- SUBC R3, R4, R5 // 7ca32010
-
- MULLW R3, R4 // 7c8419d6
- MULLW R3, R4, R5 // 7ca419d6
- MULLWCC R3, R4, R5 // 7ca419d7
- MULHW R3, R4, R5 // 7ca41896
-
- MULHWU R3, R4, R5 // 7ca41816
- MULLD R3, R4 // 7c8419d2
- MULLD R4, R4, R5 // 7ca421d2
- MULLDCC R3, R4, R5 // 7ca419d3
- MULHD R3, R4, R5 // 7ca41892
- MULHDCC R3, R4, R5 // 7ca41893
-
- MULLWV R3, R4 // 7c841dd6
- MULLWV R3, R4, R5 // 7ca41dd6
- MULLWVCC R3, R4, R5 // 7ca41dd7
- MULHWUCC R3, R4, R5 // 7ca41817
- MULLDV R3, R4, R5 // 7ca41dd2
- MULLDVCC R3, R4, R5 // 7ca41dd3
-
- DIVD R3,R4 // 7c841bd2
- DIVD R3, R4, R5 // 7ca41bd2
- DIVDCC R3,R4, R5 // 7ca41bd3
- DIVDU R3, R4, R5 // 7ca41b92
- DIVDV R3, R4, R5 // 7ca41fd2
- DIVDUCC R3, R4, R5 // 7ca41b93
- DIVDVCC R3, R4, R5 // 7ca41fd3
- DIVDUV R3, R4, R5 // 7ca41f92
- DIVDUVCC R3, R4, R5 // 7ca41f93
- DIVDE R3, R4, R5 // 7ca41b52
- DIVDECC R3, R4, R5 // 7ca41b53
- DIVDEU R3, R4, R5 // 7ca41b12
- DIVDEUCC R3, R4, R5 // 7ca41b13
-
- REM R3, R4, R5 // 7fe41bd67fff19d67cbf2050
- REMU R3, R4, R5 // 7fe41b967fff19d67bff00287cbf2050
- REMD R3, R4, R5 // 7fe41bd27fff19d27cbf2050
- REMDU R3, R4, R5 // 7fe41b927fff19d27cbf2050
-
- MODUD R3, R4, R5 // 7ca41a12
- MODUW R3, R4, R5 // 7ca41a16
- MODSD R3, R4, R5 // 7ca41e12
- MODSW R3, R4, R5 // 7ca41e16
-
- SLW $8, R3, R4 // 5464402e
- SLW R3, R4, R5 // 7c851830
- SLWCC R3, R4 // 7c841831
- SLD $16, R3, R4 // 786483e4
- SLD R3, R4, R5 // 7c851836
- SLDCC R3, R4 // 7c841837
-
- SRW $8, R3, R4 // 5464c23e
- SRW R3, R4, R5 // 7c851c30
- SRWCC R3, R4 // 7c841c31
- SRAW $8, R3, R4 // 7c644670
- SRAW R3, R4, R5 // 7c851e30
- SRAWCC R3, R4 // 7c841e31
- SRD $16, R3, R4 // 78648402
- SRD R3, R4, R5 // 7c851c36
- SRDCC R3, R4 // 7c841c37
- SRAD $16, R3, R4 // 7c648674
- SRAD R3, R4, R5 // 7c851e34
- SRDCC R3, R4 // 7c841c37
- ROTLW $16, R3, R4 // 5464803e
- ROTLW R3, R4, R5 // 5c85183e
- RLWMI $7, R3, $65535, R6 // 50663c3e
- RLWMICC $7, R3, $65535, R6 // 50663c3f
- RLWNM $3, R4, $7, R6 // 54861f7e
- RLWNMCC $3, R4, $7, R6 // 54861f7f
- RLDMI $0, R4, $7, R6 // 7886076c
- RLDMICC $0, R4, $7, R6 // 7886076d
- RLDIMI $0, R4, $7, R6 // 788601cc
- RLDIMICC $0, R4, $7, R6 // 788601cd
- RLDC $0, R4, $15, R6 // 78860728
- RLDCCC $0, R4, $15, R6 // 78860729
- RLDCL $0, R4, $7, R6 // 78860770
- RLDCLCC $0, R4, $15, R6 // 78860721
- RLDCR $0, R4, $-16, R6 // 788606f2
- RLDCRCC $0, R4, $-16, R6 // 788606f3
- RLDICL $0, R4, $15, R6 // 788603c0
- RLDICLCC $0, R4, $15, R6 // 788603c1
- RLDICR $0, R4, $15, R6 // 788603c4
- RLDICRCC $0, R4, $15, R6 // 788603c5
- RLDIC $0, R4, $15, R6 // 788603c8
- RLDICCC $0, R4, $15, R6 // 788603c9
- CLRLSLWI $16, R5, $8, R4 // 54a4861e
- CLRLSLDI $2, R4, $24, R3 // 78831588
-
- BEQ 0(PC) // 41820000
- BGE 0(PC) // 40800000
- BGT 4(PC) // 41810030
- BLE 0(PC) // 40810000
- BLT 0(PC) // 41800000
- BNE 0(PC) // 40820000
- JMP 8(PC) // 48000020
-
- CRAND CR1, CR2, CR3 // 4c620a02
- CRANDN CR1, CR2, CR3 // 4c620902
- CREQV CR1, CR2, CR3 // 4c620a42
- CRNAND CR1, CR2, CR3 // 4c6209c2
- CRNOR CR1, CR2, CR3 // 4c620842
- CROR CR1, CR2, CR3 // 4c620b82
- CRORN CR1, CR2, CR3 // 4c620b42
- CRXOR CR1, CR2, CR3 // 4c620982
-
- ISEL $1, R3, R4, R5 // 7ca3205e
- ISEL $0, R3, R4, R5 // 7ca3201e
- ISEL $2, R3, R4, R5 // 7ca3209e
- ISEL $3, R3, R4, R5 // 7ca320de
- ISEL $4, R3, R4, R5 // 7ca3211e
- POPCNTB R3, R4 // 7c6400f4
- POPCNTW R3, R4 // 7c6402f4
- POPCNTD R3, R4 // 7c6403f4
-
- PASTECC R3, R4 // 7c23270d
- COPY R3, R4 // 7c23260c
-
- // load-and-reserve
- LBAR (R4)(R3*1),$1,R5 // 7ca32069
- LBAR (R4),$0,R5 // 7ca02068
- LBAR (R3),R5 // 7ca01868
- LHAR (R4)(R3*1),$1,R5 // 7ca320e9
- LHAR (R4),$0,R5 // 7ca020e8
- LHAR (R3),R5 // 7ca018e8
- LWAR (R4)(R3*1),$1,R5 // 7ca32029
- LWAR (R4),$0,R5 // 7ca02028
- LWAR (R3),R5 // 7ca01828
- LDAR (R4)(R3*1),$1,R5 // 7ca320a9
- LDAR (R4),$0,R5 // 7ca020a8
- LDAR (R3),R5 // 7ca018a8
-
- STBCCC R3, (R4)(R5) // 7c65256d
- STWCCC R3, (R4)(R5) // 7c65212d
- STDCCC R3, (R4)(R5) // 7c6521ad
- STHCCC R3, (R4)(R5)
-
- SYNC // 7c0004ac
- ISYNC // 4c00012c
- LWSYNC // 7c2004ac
-
- DCBF (R3)(R4) // 7c0418ac
- DCBI (R3)(R4) // 7c041bac
- DCBST (R3)(R4) // 7c04186c
- DCBZ (R3)(R4) // 7c041fec
- DCBT (R3)(R4) // 7c041a2c
- ICBI (R3)(R4) // 7c041fac
-
- // float constants
- FMOVD $(0.0), F1 // f0210cd0
- FMOVD $(-0.0), F1 // f0210cd0fc200850
-
- FMOVD 8(R3), F1 // c8230008
- FMOVD (R3)(R4), F1 // 7c241cae
- FMOVDU 8(R3), F1 // cc230008
- FMOVDU (R3)(R4), F1 // 7c241cee
- FMOVS 4(R3), F1 // c0230004
- FMOVS (R3)(R4), F1 // 7c241c2e
- FMOVSU 4(R3), F1 // c4230004
- FMOVSU (R3)(R4), F1 // 7c241c6e
-
- FMOVD F1, 8(R3) // d8230008
- FMOVD F1, (R3)(R4) // 7c241dae
- FMOVDU F1, 8(R3) // dc230008
- FMOVDU F1, (R3)(R4) // 7c241dee
- FMOVS F1, 4(R3) // d0230004
- FMOVS F1, (R3)(R4) // 7c241d2e
- FMOVSU F1, 4(R3) // d4230004
- FMOVSU F1, (R3)(R4) // 7c241d6e
- FADD F1, F2 // fc42082a
- FADD F1, F2, F3 // fc62082a
- FADDCC F1, F2, F3 // fc62082b
- FADDS F1, F2 // ec42082a
- FADDS F1, F2, F3 // ec62082a
- FADDSCC F1, F2, F3 // ec62082b
- FSUB F1, F2 // fc420828
- FSUB F1, F2, F3 // fc620828
- FSUBCC F1, F2, F3 // fc620829
- FSUBS F1, F2 // ec420828
- FSUBS F1, F2, F3 // ec620828
- FSUBCC F1, F2, F3 // fc620829
- FMUL F1, F2 // fc420072
- FMUL F1, F2, F3 // fc620072
- FMULCC F1, F2, F3 // fc620073
- FMULS F1, F2 // ec420072
- FMULS F1, F2, F3 // ec620072
- FMULSCC F1, F2, F3 // ec620073
- FDIV F1, F2 // fc420824
- FDIV F1, F2, F3 // fc620824
- FDIVCC F1, F2, F3 // fc620825
- FDIVS F1, F2 // ec420824
- FDIVS F1, F2, F3 // ec620824
- FDIVSCC F1, F2, F3 // ec620825
- FMADD F1, F2, F3, F4 // fc8110fa
- FMADDCC F1, F2, F3, F4 // fc8110fb
- FMADDS F1, F2, F3, F4 // ec8110fa
- FMADDSCC F1, F2, F3, F4 // ec8110fb
- FMSUB F1, F2, F3, F4 // fc8110f8
- FMSUBCC F1, F2, F3, F4 // fc8110f9
- FMSUBS F1, F2, F3, F4 // ec8110f8
- FMSUBSCC F1, F2, F3, F4 // ec8110f9
- FNMADD F1, F2, F3, F4 // fc8110fe
- FNMADDCC F1, F2, F3, F4 // fc8110ff
- FNMADDS F1, F2, F3, F4 // ec8110fe
- FNMADDSCC F1, F2, F3, F4 // ec8110ff
- FNMSUB F1, F2, F3, F4 // fc8110fc
- FNMSUBCC F1, F2, F3, F4 // fc8110fd
- FNMSUBS F1, F2, F3, F4 // ec8110fc
- FNMSUBSCC F1, F2, F3, F4 // ec8110fd
- FSEL F1, F2, F3, F4 // fc8110ee
- FSELCC F1, F2, F3, F4 // fc8110ef
- FABS F1, F2 // fc400a10
- FABSCC F1, F2 // fc400a11
- FNEG F1, F2 // fc400850
- FABSCC F1, F2 // fc400a11
- FRSP F1, F2 // fc400818
- FRSPCC F1, F2 // fc400819
- FCTIW F1, F2 // fc40081c
- FCTIWCC F1, F2 // fc40081d
- FCTIWZ F1, F2 // fc40081e
- FCTIWZCC F1, F2 // fc40081f
- FCTID F1, F2 // fc400e5c
- FCTIDCC F1, F2 // fc400e5d
- FCTIDZ F1, F2 // fc400e5e
- FCTIDZCC F1, F2 // fc400e5f
- FCFID F1, F2 // fc400e9c
- FCFIDCC F1, F2 // fc400e9d
- FCFIDU F1, F2 // fc400f9c
- FCFIDUCC F1, F2 // fc400f9d
- FCFIDS F1, F2 // ec400e9c
- FCFIDSCC F1, F2 // ec400e9d
- FRES F1, F2 // ec400830
- FRESCC F1, F2 // ec400831
- FRIM F1, F2 // fc400bd0
- FRIMCC F1, F2 // fc400bd1
- FRIP F1, F2 // fc400b90
- FRIPCC F1, F2 // fc400b91
- FRIZ F1, F2 // fc400b50
- FRIZCC F1, F2 // fc400b51
- FRIN F1, F2 // fc400b10
- FRINCC F1, F2 // fc400b11
- FRSQRTE F1, F2 // fc400834
- FRSQRTECC F1, F2 // fc400835
- FSQRT F1, F2 // fc40082c
- FSQRTCC F1, F2 // fc40082d
- FSQRTS F1, F2 // ec40082c
- FSQRTSCC F1, F2 // ec40082d
- FCPSGN F1, F2 // fc420810
- FCPSGNCC F1, F2 // fc420811
- FCMPO F1, F2 // fc011040
- FCMPU F1, F2 // fc011000
- LVX (R3)(R4), V1 // 7c2418ce
- LVXL (R3)(R4), V1 // 7c241ace
- LVSL (R3)(R4), V1 // 7c24180c
- LVSR (R3)(R4), V1 // 7c24184c
- LVEBX (R3)(R4), V1 // 7c24180e
- LVEHX (R3)(R4), V1 // 7c24184e
- LVEWX (R3)(R4), V1 // 7c24188e
- STVX V1, (R3)(R4) // 7c2419ce
- STVXL V1, (R3)(R4) // 7c241bce
- STVEBX V1, (R3)(R4) // 7c24190e
- STVEHX V1, (R3)(R4) // 7c24194e
- STVEWX V1, (R3)(R4) // 7c24198e
-
- VAND V1, V2, V3 // 10611404
- VANDC V1, V2, V3 // 10611444
- VNAND V1, V2, V3 // 10611584
- VOR V1, V2, V3 // 10611484
- VORC V1, V2, V3 // 10611544
- VXOR V1, V2, V3 // 106114c4
- VNOR V1, V2, V3 // 10611504
- VEQV V1, V2, V3 // 10611684
- VADDUBM V1, V2, V3 // 10611000
- VADDUHM V1, V2, V3 // 10611040
- VADDUWM V1, V2, V3 // 10611080
- VADDUDM V1, V2, V3 // 106110c0
- VADDUQM V1, V2, V3 // 10611100
- VADDCUQ V1, V2, V3 // 10611140
- VADDCUW V1, V2, V3 // 10611180
- VADDUBS V1, V2, V3 // 10611200
- VADDUHS V1, V2, V3 // 10611240
- VADDUWS V1, V2, V3 // 10611280
- VSUBUBM V1, V2, V3 // 10611400
- VSUBUHM V1, V2, V3 // 10611440
- VSUBUWM V1, V2, V3 // 10611480
- VSUBUDM V1, V2, V3 // 106114c0
- VSUBUQM V1, V2, V3 // 10611500
- VSUBCUQ V1, V2, V3 // 10611540
- VSUBCUW V1, V2, V3 // 10611580
- VSUBUBS V1, V2, V3 // 10611600
- VSUBUHS V1, V2, V3 // 10611640
- VSUBUWS V1, V2, V3 // 10611680
- VSUBSBS V1, V2, V3 // 10611700
- VSUBSHS V1, V2, V3 // 10611740
- VSUBSWS V1, V2, V3 // 10611780
- VSUBEUQM V1, V2, V3, V4 // 108110fe
- VSUBECUQ V1, V2, V3, V4 // 108110ff
- VMULESB V1, V2, V3 // 10611308
- VMULOSB V1, V2, V3 // 10611108
- VMULEUB V1, V2, V3 // 10611208
- VMULOUB V1, V2, V3 // 10611008
- VMULESH V1, V2, V3 // 10611348
- VMULOSH V1, V2, V3 // 10611148
- VMULEUH V1, V2, V3 // 10611248
- VMULOUH V1, V2, V3 // 10611048
- VMULESH V1, V2, V3 // 10611348
- VMULOSW V1, V2, V3 // 10611188
- VMULEUW V1, V2, V3 // 10611288
- VMULOUW V1, V2, V3 // 10611088
- VMULUWM V1, V2, V3 // 10611089
- VPMSUMB V1, V2, V3 // 10611408
- VPMSUMH V1, V2, V3 // 10611448
- VPMSUMW V1, V2, V3 // 10611488
- VPMSUMD V1, V2, V3 // 106114c8
- VMSUMUDM V1, V2, V3, V4 // 108110e3
- VRLB V1, V2, V3 // 10611004
- VRLH V1, V2, V3 // 10611044
- VRLW V1, V2, V3 // 10611084
- VRLD V1, V2, V3 // 106110c4
- VSLB V1, V2, V3 // 10611104
- VSLH V1, V2, V3 // 10611144
- VSLW V1, V2, V3 // 10611184
- VSL V1, V2, V3 // 106111c4
- VSLO V1, V2, V3 // 1061140c
- VSRB V1, V2, V3 // 10611204
- VSRH V1, V2, V3 // 10611244
- VSRW V1, V2, V3 // 10611284
- VSR V1, V2, V3 // 106112c4
- VSRO V1, V2, V3 // 1061144c
- VSLD V1, V2, V3 // 106115c4
- VSRAB V1, V2, V3 // 10611304
- VSRAH V1, V2, V3 // 10611344
- VSRAW V1, V2, V3 // 10611384
- VSRAD V1, V2, V3 // 106113c4
- VSLDOI $3, V1, V2, V3 // 106110ec
- VCLZB V1, V2 // 10400f02
- VCLZH V1, V2 // 10400f42
- VCLZW V1, V2 // 10400f82
- VCLZD V1, V2 // 10400fc2
- VPOPCNTB V1, V2 // 10400f03
- VPOPCNTH V1, V2 // 10400f43
- VPOPCNTW V1, V2 // 10400f83
- VPOPCNTD V1, V2 // 10400fc3
- VCMPEQUB V1, V2, V3 // 10611006
- VCMPEQUBCC V1, V2, V3 // 10611406
- VCMPEQUH V1, V2, V3 // 10611046
- VCMPEQUHCC V1, V2, V3 // 10611446
- VCMPEQUW V1, V2, V3 // 10611086
- VCMPEQUWCC V1, V2, V3 // 10611486
- VCMPEQUD V1, V2, V3 // 106110c7
- VCMPEQUDCC V1, V2, V3 // 106114c7
- VCMPGTUB V1, V2, V3 // 10611206
- VCMPGTUBCC V1, V2, V3 // 10611606
- VCMPGTUH V1, V2, V3 // 10611246
- VCMPGTUHCC V1, V2, V3 // 10611646
- VCMPGTUW V1, V2, V3 // 10611286
- VCMPGTUWCC V1, V2, V3 // 10611686
- VCMPGTUD V1, V2, V3 // 106112c7
- VCMPGTUDCC V1, V2, V3 // 106116c7
- VCMPGTSB V1, V2, V3 // 10611306
- VCMPGTSBCC V1, V2, V3 // 10611706
- VCMPGTSH V1, V2, V3 // 10611346
- VCMPGTSHCC V1, V2, V3 // 10611746
- VCMPGTSW V1, V2, V3 // 10611386
- VCMPGTSWCC V1, V2, V3 // 10611786
- VCMPGTSD V1, V2, V3 // 106113c7
- VCMPGTSDCC V1, V2, V3 // 106117c7
- VCMPNEZB V1, V2, V3 // 10611107
- VCMPNEZBCC V1, V2, V3 // 10611507
- VCMPNEB V1, V2, V3 // 10611007
- VCMPNEBCC V1, V2, V3 // 10611407
- VCMPNEH V1, V2, V3 // 10611047
- VCMPNEHCC V1, V2, V3 // 10611447
- VCMPNEW V1, V2, V3 // 10611087
- VCMPNEWCC V1, V2, V3 // 10611487
- VPERM V1, V2, V3, V4 // 108110eb
- VPERMR V1, V2, V3, V4 // 108110fb
- VPERMXOR V1, V2, V3, V4 // 108110ed
- VBPERMQ V1, V2, V3 // 1061154c
- VBPERMD V1, V2, V3 // 106115cc
- VSEL V1, V2, V3, V4 // 108110ea
- VSPLTB $1, V1, V2 // 10410a0c
- VSPLTH $1, V1, V2 // 10410a4c
- VSPLTW $1, V1, V2 // 10410a8c
- VSPLTISB $1, V1 // 1021030c
- VSPLTISW $1, V1 // 1021038c
- VSPLTISH $1, V1 // 1021034c
- VCIPHER V1, V2, V3 // 10611508
- VCIPHERLAST V1, V2, V3 // 10611509
- VNCIPHER V1, V2, V3 // 10611548
- VNCIPHERLAST V1, V2, V3 // 10611549
- VSBOX V1, V2 // 104105c8
- VSHASIGMAW $1, V1, $15, V2 // 10418e82
- VSHASIGMAD $2, V1, $15, V2 // 104196c2
-
- LXVD2X (R3)(R4), VS1 // 7c241e98
- LXV 16(R3), VS1 // f4230011
- LXVL R3, R4, VS1 // 7c23221a
- LXVLL R3, R4, VS1 // 7c23225a
- LXVX R3, R4, VS1 // 7c232218
- LXSDX (R3)(R4), VS1 // 7c241c98
- STXVD2X VS1, (R3)(R4) // 7c241f98
- STXV VS1,16(R3) // f4230015
- STXVL VS1, R3, R4 // 7c23231a
- STXVLL VS1, R3, R4 // 7c23235a
- STXVX VS1, R3, R4 // 7c232318
- STXSDX VS1, (R3)(R4) // 7c241d98
- LXSIWAX (R3)(R4), VS1 // 7c241898
- STXSIWX VS1, (R3)(R4) // 7c241918
- MFVSRD VS1, R3 // 7c230066
- MTVSRD R3, VS1 // 7c230166
- XXLAND VS1, VS2, VS3 // f0611410
- XXLOR VS1, VS2, VS3 // f0611490
- XXLORC VS1, VS2, VS3 // f0611550
- XXLXOR VS1, VS2, VS3 // f06114d0
- XXSEL VS1, VS2, VS3, VS4 // f08110f0
- XXMRGHW VS1, VS2, VS3 // f0611090
- XXSPLTW VS1, $1, VS2 // f0410a90
- XXPERM VS1, VS2, VS3 // f06110d0
- XXSLDWI VS1, VS2, $1, VS3 // f0611110
- XSCVDPSP VS1, VS2 // f0400c24
- XVCVDPSP VS1, VS2 // f0400e24
- XSCVSXDDP VS1, VS2 // f0400de0
- XVCVDPSXDS VS1, VS2 // f0400f60
- XVCVSXDDP VS1, VS2 // f0400fe0
-
- MOVD R3, LR // 7c6803a6
- MOVD R3, CTR // 7c6903a6
- MOVD R3, XER // 7c6103a6
- MOVD LR, R3 // 7c6802a6
- MOVD CTR, R3 // 7c6902a6
- MOVD XER, R3 // 7c6102a6
- MOVFL CR3, CR1 // 4c8c0000
-
- RET
diff --git a/src/cmd/asm/internal/lex/input.go b/src/cmd/asm/internal/lex/input.go
index a43953b515..da4ebe6d6e 100644
--- a/src/cmd/asm/internal/lex/input.go
+++ b/src/cmd/asm/internal/lex/input.go
@@ -109,6 +109,9 @@ func (in *Input) Next() ScanToken {
in.Error("'#' must be first item on line")
}
in.beginningOfLine = in.hash()
+ in.text = "#"
+ return '#'
+
case scanner.Ident:
// Is it a macro name?
name := in.Stack.Text()
diff --git a/src/cmd/asm/internal/lex/lex.go b/src/cmd/asm/internal/lex/lex.go
index f1f7da7911..7cd41a55a9 100644
--- a/src/cmd/asm/internal/lex/lex.go
+++ b/src/cmd/asm/internal/lex/lex.go
@@ -22,11 +22,13 @@ type ScanToken rune
const (
// Asm defines some two-character lexemes. We make up
// a rune/ScanToken value for them - ugly but simple.
- LSH ScanToken = -1000 - iota // << Left shift.
- RSH // >> Logical right shift.
- ARR // -> Used on ARM for shift type 3, arithmetic right shift.
- ROT // @> Used on ARM for shift type 4, rotate right.
- macroName // name of macro that should not be expanded
+ LSH ScanToken = -1000 - iota // << Left shift.
+ RSH // >> Logical right shift.
+ ARR // -> Used on ARM for shift type 3, arithmetic right shift.
+ ROT // @> Used on ARM for shift type 4, rotate right.
+ Include // included file started here
+ BuildComment // //go:build or +build comment
+ macroName // name of macro that should not be expanded
)
// IsRegisterShift reports whether the token is one of the ARM register shift operators.
diff --git a/src/cmd/asm/internal/lex/lex_test.go b/src/cmd/asm/internal/lex/lex_test.go
index f606ffe07b..51679d2fbc 100644
--- a/src/cmd/asm/internal/lex/lex_test.go
+++ b/src/cmd/asm/internal/lex/lex_test.go
@@ -281,6 +281,9 @@ func drain(input *Input) string {
if tok == scanner.EOF {
return buf.String()
}
+ if tok == '#' {
+ continue
+ }
if buf.Len() > 0 {
buf.WriteByte('.')
}
diff --git a/src/cmd/asm/internal/lex/tokenizer.go b/src/cmd/asm/internal/lex/tokenizer.go
index aef9ea8636..861a2d421d 100644
--- a/src/cmd/asm/internal/lex/tokenizer.go
+++ b/src/cmd/asm/internal/lex/tokenizer.go
@@ -107,10 +107,13 @@ func (t *Tokenizer) Next() ScanToken {
if t.tok != scanner.Comment {
break
}
- length := strings.Count(s.TokenText(), "\n")
- t.line += length
- // TODO: If we ever have //go: comments in assembly, will need to keep them here.
- // For now, just discard all comments.
+ text := s.TokenText()
+ t.line += strings.Count(text, "\n")
+ // TODO: Use constraint.IsGoBuild once it exists.
+ if strings.HasPrefix(text, "//go:build") {
+ t.tok = BuildComment
+ break
+ }
}
switch t.tok {
case '\n':
diff --git a/src/cmd/asm/main.go b/src/cmd/asm/main.go
index fd079a2ccd..01c963ac72 100644
--- a/src/cmd/asm/main.go
+++ b/src/cmd/asm/main.go
@@ -52,6 +52,7 @@ func main() {
case "all", "ret":
ctxt.Retpoline = true
}
+ compilingRuntime := objabi.IsRuntimePackagePath(*flags.Importpath)
ctxt.Bso = bufio.NewWriter(os.Stdout)
defer ctxt.Bso.Flush()
@@ -74,7 +75,7 @@ func main() {
var failedFile string
for _, f := range flag.Args() {
lexer := lex.NewLexer(f)
- parser := asm.NewParser(ctxt, architecture, lexer)
+ parser := asm.NewParser(ctxt, architecture, lexer, compilingRuntime)
ctxt.DiagFunc = func(format string, args ...interface{}) {
diag = true
log.Printf(format, args...)
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index ef3ed968e4..7d02ac3c54 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -170,35 +170,51 @@ func usage() {
var ptrSizeMap = map[string]int64{
"386": 4,
+ "alpha": 8,
"amd64": 8,
"arm": 4,
"arm64": 8,
+ "m68k": 4,
"mips": 4,
"mipsle": 4,
"mips64": 8,
"mips64le": 8,
+ "nios2": 4,
+ "ppc": 4,
"ppc64": 8,
"ppc64le": 8,
+ "riscv": 4,
"riscv64": 8,
"s390": 4,
"s390x": 8,
+ "sh": 4,
+ "shbe": 4,
+ "sparc": 4,
"sparc64": 8,
}
var intSizeMap = map[string]int64{
"386": 4,
+ "alpha": 8,
"amd64": 8,
"arm": 4,
"arm64": 8,
+ "m68k": 4,
"mips": 4,
"mipsle": 4,
"mips64": 8,
"mips64le": 8,
+ "nios2": 4,
+ "ppc": 4,
"ppc64": 8,
"ppc64le": 8,
+ "riscv": 4,
"riscv64": 8,
"s390": 4,
"s390x": 8,
+ "sh": 4,
+ "shbe": 4,
+ "sparc": 4,
"sparc64": 8,
}
@@ -224,8 +240,7 @@ var exportHeader = flag.String("exportheader", "", "where to write export header
var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo")
var gccgoprefix = flag.String("gccgoprefix", "", "-fgo-prefix option used with gccgo")
var gccgopkgpath = flag.String("gccgopkgpath", "", "-fgo-pkgpath option used with gccgo")
-var gccgoMangleCheckDone bool
-var gccgoNewmanglingInEffect bool
+var gccgoMangler func(string) string
var importRuntimeCgo = flag.Bool("import_runtime_cgo", true, "import runtime/cgo in generated code")
var importSyscall = flag.Bool("import_syscall", true, "import syscall in generated code")
var goarch, goos string
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index 03b8333b10..b447b07645 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -6,6 +6,7 @@ package main
import (
"bytes"
+ "cmd/internal/pkgpath"
"debug/elf"
"debug/macho"
"debug/pe"
@@ -15,7 +16,6 @@ import (
"go/token"
"internal/xcoff"
"io"
- "io/ioutil"
"os"
"os/exec"
"path/filepath"
@@ -1282,112 +1282,24 @@ func (p *Package) writeExportHeader(fgcch io.Writer) {
fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
}
-// gccgoUsesNewMangling reports whether gccgo uses the new collision-free
-// packagepath mangling scheme (see determineGccgoManglingScheme for more
-// info).
-func gccgoUsesNewMangling() bool {
- if !gccgoMangleCheckDone {
- gccgoNewmanglingInEffect = determineGccgoManglingScheme()
- gccgoMangleCheckDone = true
- }
- return gccgoNewmanglingInEffect
-}
-
-const mangleCheckCode = `
-package läufer
-func Run(x int) int {
- return 1
-}
-`
-
-// determineGccgoManglingScheme performs a runtime test to see which
-// flavor of packagepath mangling gccgo is using. Older versions of
-// gccgo use a simple mangling scheme where there can be collisions
-// between packages whose paths are different but mangle to the same
-// string. More recent versions of gccgo use a new mangler that avoids
-// these collisions. Return value is whether gccgo uses the new mangling.
-func determineGccgoManglingScheme() bool {
-
- // Emit a small Go file for gccgo to compile.
- filepat := "*_gccgo_manglecheck.go"
- var f *os.File
- var err error
- if f, err = ioutil.TempFile(*objDir, filepat); err != nil {
- fatalf("%v", err)
- }
- gofilename := f.Name()
- defer os.Remove(gofilename)
-
- if err = ioutil.WriteFile(gofilename, []byte(mangleCheckCode), 0666); err != nil {
- fatalf("%v", err)
- }
-
- // Compile with gccgo, capturing generated assembly.
- gccgocmd := os.Getenv("GCCGO")
- if gccgocmd == "" {
- gpath, gerr := exec.LookPath("gccgo")
- if gerr != nil {
- fatalf("unable to locate gccgo: %v", gerr)
- }
- gccgocmd = gpath
- }
- cmd := exec.Command(gccgocmd, "-S", "-o", "-", gofilename)
- buf, cerr := cmd.CombinedOutput()
- if cerr != nil {
- fatalf("%s", cerr)
- }
-
- // New mangling: expect go.l..u00e4ufer.Run
- // Old mangling: expect go.l__ufer.Run
- return regexp.MustCompile(`go\.l\.\.u00e4ufer\.Run`).Match(buf)
-}
-
-// gccgoPkgpathToSymbolNew converts a package path to a gccgo-style
-// package symbol.
-func gccgoPkgpathToSymbolNew(ppath string) string {
- bsl := []byte{}
- changed := false
- for _, c := range []byte(ppath) {
- switch {
- case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z',
- '0' <= c && c <= '9', c == '_':
- bsl = append(bsl, c)
- case c == '.':
- bsl = append(bsl, ".x2e"...)
- default:
- changed = true
- encbytes := []byte(fmt.Sprintf("..z%02x", c))
- bsl = append(bsl, encbytes...)
- }
- }
- if !changed {
- return ppath
- }
- return string(bsl)
-}
-
-// gccgoPkgpathToSymbolOld converts a package path to a gccgo-style
-// package symbol using the older mangling scheme.
-func gccgoPkgpathToSymbolOld(ppath string) string {
- clean := func(r rune) rune {
- switch {
- case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z',
- '0' <= r && r <= '9':
- return r
- }
- return '_'
- }
- return strings.Map(clean, ppath)
-}
-
// gccgoPkgpathToSymbol converts a package path to a mangled packagepath
// symbol.
func gccgoPkgpathToSymbol(ppath string) string {
- if gccgoUsesNewMangling() {
- return gccgoPkgpathToSymbolNew(ppath)
- } else {
- return gccgoPkgpathToSymbolOld(ppath)
+ if gccgoMangler == nil {
+ var err error
+ cmd := os.Getenv("GCCGO")
+ if cmd == "" {
+ cmd, err = exec.LookPath("gccgo")
+ if err != nil {
+ fatalf("unable to locate gccgo: %v", err)
+ }
+ }
+ gccgoMangler, err = pkgpath.ToSymbolFunc(cmd, *objDir)
+ if err != nil {
+ fatalf("%v", err)
+ }
}
+ return gccgoMangler(ppath)
}
// Return the package prefix when using gccgo.
diff --git a/src/cmd/compile/internal/gc/align.go b/src/cmd/compile/internal/gc/align.go
index ab578ee8c7..5af403afa3 100644
--- a/src/cmd/compile/internal/gc/align.go
+++ b/src/cmd/compile/internal/gc/align.go
@@ -5,7 +5,9 @@
package gc
import (
+ "bytes"
"cmd/compile/internal/types"
+ "fmt"
"sort"
)
@@ -173,6 +175,91 @@ func widstruct(errtype *types.Type, t *types.Type, o int64, flag int) int64 {
return o
}
+// findTypeLoop searches for an invalid type declaration loop involving
+// type t and reports whether one is found. If so, path contains the
+// loop.
+//
+// path points to a slice used for tracking the sequence of types
+// visited. Using a pointer to a slice allows the slice capacity to
+// grow and limit reallocations.
+func findTypeLoop(t *types.Type, path *[]*types.Type) bool {
+ // We implement a simple DFS loop-finding algorithm. This
+ // could be faster, but type cycles are rare.
+
+ if t.Sym != nil {
+ // Declared type. Check for loops and otherwise
+ // recurse on the type expression used in the type
+ // declaration.
+
+ for i, x := range *path {
+ if x == t {
+ *path = (*path)[i:]
+ return true
+ }
+ }
+
+ *path = append(*path, t)
+ if findTypeLoop(asNode(t.Nod).Name.Param.Ntype.Type, path) {
+ return true
+ }
+ *path = (*path)[:len(*path)-1]
+ } else {
+ // Anonymous type. Recurse on contained types.
+
+ switch t.Etype {
+ case TARRAY:
+ if findTypeLoop(t.Elem(), path) {
+ return true
+ }
+ case TSTRUCT:
+ for _, f := range t.Fields().Slice() {
+ if findTypeLoop(f.Type, path) {
+ return true
+ }
+ }
+ case TINTER:
+ for _, m := range t.Methods().Slice() {
+ if m.Type.IsInterface() { // embedded interface
+ if findTypeLoop(m.Type, path) {
+ return true
+ }
+ }
+ }
+ }
+ }
+
+ return false
+}
+
+func reportTypeLoop(t *types.Type) {
+ if t.Broke() {
+ return
+ }
+
+ var l []*types.Type
+ if !findTypeLoop(t, &l) {
+ Fatalf("failed to find type loop for: %v", t)
+ }
+
+ // Rotate loop so that the earliest type declaration is first.
+ i := 0
+ for j, t := range l[1:] {
+ if typePos(t).Before(typePos(l[i])) {
+ i = j + 1
+ }
+ }
+ l = append(l[i:], l[:i]...)
+
+ var msg bytes.Buffer
+ fmt.Fprintf(&msg, "invalid recursive type %v\n", l[0])
+ for _, t := range l {
+ fmt.Fprintf(&msg, "\t%v: %v refers to\n", linestr(typePos(t)), t)
+ t.SetBroke(true)
+ }
+ fmt.Fprintf(&msg, "\t%v: %v", linestr(typePos(l[0])), l[0])
+ yyerrorl(typePos(l[0]), msg.String())
+}
+
// dowidth calculates and stores the size and alignment for t.
// If sizeCalculationDisabled is set, and the size/alignment
// have not already been calculated, it calls Fatal.
@@ -192,11 +279,7 @@ func dowidth(t *types.Type) {
}
if t.Width == -2 {
- if !t.Broke() {
- t.SetBroke(true)
- yyerrorl(asNode(t.Nod).Pos, "invalid recursive type %v", t)
- }
-
+ reportTypeLoop(t)
t.Width = 0
t.Align = 1
return
@@ -308,10 +391,7 @@ func dowidth(t *types.Type) {
checkwidth(t.Key())
case TFORW: // should have been filled in
- if !t.Broke() {
- t.SetBroke(true)
- yyerror("invalid recursive type %v", t)
- }
+ reportTypeLoop(t)
w = 1 // anything will do
case TANY:
diff --git a/src/cmd/compile/internal/gc/bench_test.go b/src/cmd/compile/internal/gc/bench_test.go
index 09aaf428c3..8c4288128f 100644
--- a/src/cmd/compile/internal/gc/bench_test.go
+++ b/src/cmd/compile/internal/gc/bench_test.go
@@ -7,6 +7,7 @@ package gc
import "testing"
var globl int64
+var globl32 int32
func BenchmarkLoadAdd(b *testing.B) {
x := make([]int64, 1024)
@@ -20,6 +21,18 @@ func BenchmarkLoadAdd(b *testing.B) {
}
}
+// Added for ppc64 extswsli on power9
+func BenchmarkExtShift(b *testing.B) {
+ x := make([]int32, 1024)
+ for i := 0; i < b.N; i++ {
+ var s int64
+ for i := range x {
+ s ^= int64(x[i]+32) * 8
+ }
+ globl = s
+ }
+}
+
func BenchmarkModify(b *testing.B) {
a := make([]int64, 1024)
v := globl
@@ -30,6 +43,17 @@ func BenchmarkModify(b *testing.B) {
}
}
+func BenchmarkMullImm(b *testing.B) {
+ x := make([]int32, 1024)
+ for i := 0; i < b.N; i++ {
+ var s int32
+ for i := range x {
+ s += x[i] * 100
+ }
+ globl32 = s
+ }
+}
+
func BenchmarkConstModify(b *testing.B) {
a := make([]int64, 1024)
for i := 0; i < b.N; i++ {
diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go
index 5ced66c0da..10f21f86df 100644
--- a/src/cmd/compile/internal/gc/bexport.go
+++ b/src/cmd/compile/internal/gc/bexport.go
@@ -81,11 +81,6 @@ func (p *exporter) markType(t *types.Type) {
}
}
-// deltaNewFile is a magic line delta offset indicating a new file.
-// We use -64 because it is rare; see issue 20080 and CL 41619.
-// -64 is the smallest int that fits in a single byte as a varint.
-const deltaNewFile = -64
-
// ----------------------------------------------------------------------------
// Export format
@@ -126,30 +121,6 @@ const (
aliasTag
)
-// untype returns the "pseudo" untyped type for a Ctype (import/export use only).
-// (we can't use a pre-initialized array because we must be sure all types are
-// set up)
-func untype(ctype Ctype) *types.Type {
- switch ctype {
- case CTINT:
- return types.Idealint
- case CTRUNE:
- return types.Idealrune
- case CTFLT:
- return types.Idealfloat
- case CTCPLX:
- return types.Idealcomplex
- case CTSTR:
- return types.Idealstring
- case CTBOOL:
- return types.Idealbool
- case CTNIL:
- return types.Types[TNIL]
- }
- Fatalf("exporter: unknown Ctype")
- return nil
-}
-
var predecl []*types.Type // initialized lazily
func predeclared() []*types.Type {
@@ -184,13 +155,13 @@ func predeclared() []*types.Type {
types.Errortype,
// untyped types
- untype(CTBOOL),
- untype(CTINT),
- untype(CTRUNE),
- untype(CTFLT),
- untype(CTCPLX),
- untype(CTSTR),
- untype(CTNIL),
+ types.UntypedBool,
+ types.UntypedInt,
+ types.UntypedRune,
+ types.UntypedFloat,
+ types.UntypedComplex,
+ types.UntypedString,
+ types.Types[TNIL],
// package unsafe
types.Types[TUNSAFEPTR],
diff --git a/src/cmd/compile/internal/gc/const.go b/src/cmd/compile/internal/gc/const.go
index c0ed8192d9..b92c8d66b5 100644
--- a/src/cmd/compile/internal/gc/const.go
+++ b/src/cmd/compile/internal/gc/const.go
@@ -114,16 +114,16 @@ func (v Val) Interface() interface{} {
type NilVal struct{}
-// Int64 returns n as an int64.
+// Int64Val returns n as an int64.
// n must be an integer or rune constant.
-func (n *Node) Int64() int64 {
+func (n *Node) Int64Val() int64 {
if !Isconst(n, CTINT) {
- Fatalf("Int64(%v)", n)
+ Fatalf("Int64Val(%v)", n)
}
return n.Val().U.(*Mpint).Int64()
}
-// CanInt64 reports whether it is safe to call Int64() on n.
+// CanInt64 reports whether it is safe to call Int64Val() on n.
func (n *Node) CanInt64() bool {
if !Isconst(n, CTINT) {
return false
@@ -131,18 +131,27 @@ func (n *Node) CanInt64() bool {
// if the value inside n cannot be represented as an int64, the
// return value of Int64 is undefined
- return n.Val().U.(*Mpint).CmpInt64(n.Int64()) == 0
+ return n.Val().U.(*Mpint).CmpInt64(n.Int64Val()) == 0
}
-// Bool returns n as a bool.
+// BoolVal returns n as a bool.
// n must be a boolean constant.
-func (n *Node) Bool() bool {
+func (n *Node) BoolVal() bool {
if !Isconst(n, CTBOOL) {
- Fatalf("Bool(%v)", n)
+ Fatalf("BoolVal(%v)", n)
}
return n.Val().U.(bool)
}
+// StringVal returns the value of a literal string Node as a string.
+// n must be a string constant.
+func (n *Node) StringVal() string {
+ if !Isconst(n, CTSTR) {
+ Fatalf("StringVal(%v)", n)
+ }
+ return n.Val().U.(string)
+}
+
// truncate float literal fv to 32-bit or 64-bit precision
// according to type; return truncated value.
func truncfltlit(oldv *Mpflt, t *types.Type) *Mpflt {
@@ -612,7 +621,7 @@ func evconst(n *Node) {
var strs []string
i2 := i1
for i2 < len(s) && Isconst(s[i2], CTSTR) {
- strs = append(strs, strlit(s[i2]))
+ strs = append(strs, s[i2].StringVal())
i2++
}
@@ -635,7 +644,7 @@ func evconst(n *Node) {
switch nl.Type.Etype {
case TSTRING:
if Isconst(nl, CTSTR) {
- setintconst(n, int64(len(strlit(nl))))
+ setintconst(n, int64(len(nl.StringVal())))
}
case TARRAY:
if !hascallchan(nl) {
@@ -1019,17 +1028,17 @@ func nodlit(v Val) *Node {
func idealType(ct Ctype) *types.Type {
switch ct {
case CTSTR:
- return types.Idealstring
+ return types.UntypedString
case CTBOOL:
- return types.Idealbool
+ return types.UntypedBool
case CTINT:
- return types.Idealint
+ return types.UntypedInt
case CTRUNE:
- return types.Idealrune
+ return types.UntypedRune
case CTFLT:
- return types.Idealfloat
+ return types.UntypedFloat
case CTCPLX:
- return types.Idealcomplex
+ return types.UntypedComplex
case CTNIL:
return types.Types[TNIL]
}
@@ -1080,17 +1089,17 @@ func defaultlit2(l *Node, r *Node, force bool) (*Node, *Node) {
func ctype(t *types.Type) Ctype {
switch t {
- case types.Idealbool:
+ case types.UntypedBool:
return CTBOOL
- case types.Idealstring:
+ case types.UntypedString:
return CTSTR
- case types.Idealint:
+ case types.UntypedInt:
return CTINT
- case types.Idealrune:
+ case types.UntypedRune:
return CTRUNE
- case types.Idealfloat:
+ case types.UntypedFloat:
return CTFLT
- case types.Idealcomplex:
+ case types.UntypedComplex:
return CTCPLX
}
Fatalf("bad type %v", t)
@@ -1111,17 +1120,17 @@ func defaultType(t *types.Type) *types.Type {
}
switch t {
- case types.Idealbool:
+ case types.UntypedBool:
return types.Types[TBOOL]
- case types.Idealstring:
+ case types.UntypedString:
return types.Types[TSTRING]
- case types.Idealint:
+ case types.UntypedInt:
return types.Types[TINT]
- case types.Idealrune:
+ case types.UntypedRune:
return types.Runetype
- case types.Idealfloat:
+ case types.UntypedFloat:
return types.Types[TFLOAT64]
- case types.Idealcomplex:
+ case types.UntypedComplex:
return types.Types[TCOMPLEX128]
}
@@ -1129,12 +1138,6 @@ func defaultType(t *types.Type) *types.Type {
return nil
}
-// strlit returns the value of a literal string Node as a string.
-func strlit(n *Node) string {
- return n.Val().U.(string)
-}
-
-// TODO(gri) smallintconst is only used in one place - can we used indexconst?
func smallintconst(n *Node) bool {
if n.Op == OLITERAL && Isconst(n, CTINT) && n.Type != nil {
switch simtype[n.Type.Etype] {
diff --git a/src/cmd/compile/internal/gc/dwinl.go b/src/cmd/compile/internal/gc/dwinl.go
index 27e2cbcd98..5120fa1166 100644
--- a/src/cmd/compile/internal/gc/dwinl.go
+++ b/src/cmd/compile/internal/gc/dwinl.go
@@ -34,7 +34,7 @@ func assembleInlines(fnsym *obj.LSym, dwVars []*dwarf.Var) dwarf.InlCalls {
// Walk progs to build up the InlCalls data structure
var prevpos src.XPos
- for p := fnsym.Func.Text; p != nil; p = p.Link {
+ for p := fnsym.Func().Text; p != nil; p = p.Link {
if p.Pos == prevpos {
continue
}
@@ -150,7 +150,7 @@ func assembleInlines(fnsym *obj.LSym, dwVars []*dwarf.Var) dwarf.InlCalls {
start := int64(-1)
curii := -1
var prevp *obj.Prog
- for p := fnsym.Func.Text; p != nil; prevp, p = p, p.Link {
+ for p := fnsym.Func().Text; p != nil; prevp, p = p, p.Link {
if prevp != nil && p.Pos == prevp.Pos {
continue
}
diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go
index 375331d1f5..c11066a62f 100644
--- a/src/cmd/compile/internal/gc/esc.go
+++ b/src/cmd/compile/internal/gc/esc.go
@@ -169,36 +169,47 @@ func mayAffectMemory(n *Node) bool {
}
}
-func mustHeapAlloc(n *Node) bool {
+// heapAllocReason returns the reason the given Node must be heap
+// allocated, or the empty string if it doesn't.
+func heapAllocReason(n *Node) string {
if n.Type == nil {
- return false
+ return ""
}
// Parameters are always passed via the stack.
if n.Op == ONAME && (n.Class() == PPARAM || n.Class() == PPARAMOUT) {
- return false
+ return ""
}
if n.Type.Width > maxStackVarSize {
- return true
+ return "too large for stack"
}
if (n.Op == ONEW || n.Op == OPTRLIT) && n.Type.Elem().Width >= maxImplicitStackVarSize {
- return true
+ return "too large for stack"
}
if n.Op == OCLOSURE && closureType(n).Size() >= maxImplicitStackVarSize {
- return true
+ return "too large for stack"
}
if n.Op == OCALLPART && partialCallType(n).Size() >= maxImplicitStackVarSize {
- return true
+ return "too large for stack"
}
- if n.Op == OMAKESLICE && !isSmallMakeSlice(n) {
- return true
+ if n.Op == OMAKESLICE {
+ r := n.Right
+ if r == nil {
+ r = n.Left
+ }
+ if !smallintconst(r) {
+ return "non-constant size"
+ }
+ if t := n.Type; t.Elem().Width != 0 && r.Int64Val() >= maxImplicitStackVarSize/t.Elem().Width {
+ return "too large for stack"
+ }
}
- return false
+ return ""
}
// addrescapes tags node n as having had its address taken
diff --git a/src/cmd/compile/internal/gc/escape.go b/src/cmd/compile/internal/gc/escape.go
index f435d8ff6a..93965d4fac 100644
--- a/src/cmd/compile/internal/gc/escape.go
+++ b/src/cmd/compile/internal/gc/escape.go
@@ -771,10 +771,11 @@ func (e *Escape) call(ks []EscHole, call, where *Node) {
var fn *Node
switch call.Op {
case OCALLFUNC:
- if call.Left.Op == ONAME && call.Left.Class() == PFUNC {
- fn = call.Left
- } else if call.Left.Op == OCLOSURE {
- fn = call.Left.Func.Closure.Func.Nname
+ switch v := staticValue(call.Left); {
+ case v.Op == ONAME && v.Class() == PFUNC:
+ fn = v
+ case v.Op == OCLOSURE:
+ fn = v.Func.Closure.Func.Nname
}
case OCALLMETH:
fn = asNode(call.Left.Type.FuncType().Nname)
@@ -1051,11 +1052,7 @@ func (e *Escape) newLoc(n *Node, transient bool) *EscLocation {
}
n.SetOpt(loc)
- if mustHeapAlloc(n) {
- why := "too large for stack"
- if n.Op == OMAKESLICE && (!Isconst(n.Left, CTINT) || !Isconst(n.Right, CTINT)) {
- why = "non-constant size"
- }
+ if why := heapAllocReason(n); why != "" {
e.flow(e.heapHole().addr(n, why), loc)
}
}
diff --git a/src/cmd/compile/internal/gc/export.go b/src/cmd/compile/internal/gc/export.go
index 44bea2b1fd..839c2c2c75 100644
--- a/src/cmd/compile/internal/gc/export.go
+++ b/src/cmd/compile/internal/gc/export.go
@@ -96,7 +96,7 @@ func importsym(ipkg *types.Pkg, s *types.Sym, op Op) *Node {
return n
}
-// pkgtype returns the named type declared by symbol s.
+// importtype returns the named type declared by symbol s.
// If no such type has been declared yet, a forward declaration is returned.
// ipkg is the package being imported
func importtype(ipkg *types.Pkg, pos src.XPos, s *types.Sym) *types.Type {
diff --git a/src/cmd/compile/internal/gc/float_test.go b/src/cmd/compile/internal/gc/float_test.go
index 6ae363be22..c619d25705 100644
--- a/src/cmd/compile/internal/gc/float_test.go
+++ b/src/cmd/compile/internal/gc/float_test.go
@@ -6,17 +6,9 @@ package gc
import (
"math"
- "os"
- "runtime"
"testing"
)
-// For GO386=387, make sure fucomi* opcodes are not used
-// for comparison operations.
-// Note that this test will fail only on a Pentium MMX
-// processor (with GOARCH=386 GO386=387), as it just runs
-// some code and looks for an unimplemented instruction fault.
-
//go:noinline
func compare1(a, b float64) bool {
return a < b
@@ -137,9 +129,6 @@ func TestFloatCompareFolded(t *testing.T) {
}
}
-// For GO386=387, make sure fucomi* opcodes are not used
-// for float->int conversions.
-
//go:noinline
func cvt1(a float64) uint64 {
return uint64(a)
@@ -370,14 +359,6 @@ func TestFloat32StoreToLoadConstantFold(t *testing.T) {
// are not converted to quiet NaN (qNaN) values during compilation.
// See issue #27193 for more information.
- // TODO: this method for detecting 387 won't work if the compiler has been
- // built using GOARCH=386 GO386=387 and either the target is a different
- // architecture or the GO386=387 environment variable is not set when the
- // test is run.
- if runtime.GOARCH == "386" && os.Getenv("GO386") == "387" {
- t.Skip("signaling NaNs are not propagated on 387 (issue #27516)")
- }
-
// signaling NaNs
{
const nan = uint32(0x7f800001) // sNaN
diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go
index d4af451506..9ba1789633 100644
--- a/src/cmd/compile/internal/gc/fmt.go
+++ b/src/cmd/compile/internal/gc/fmt.go
@@ -773,17 +773,17 @@ func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode fmtMode, visited
if int(t.Etype) < len(basicnames) && basicnames[t.Etype] != "" {
var name string
switch t {
- case types.Idealbool:
+ case types.UntypedBool:
name = "untyped bool"
- case types.Idealstring:
+ case types.UntypedString:
name = "untyped string"
- case types.Idealint:
+ case types.UntypedInt:
name = "untyped int"
- case types.Idealrune:
+ case types.UntypedRune:
name = "untyped rune"
- case types.Idealfloat:
+ case types.UntypedFloat:
name = "untyped float"
- case types.Idealcomplex:
+ case types.UntypedComplex:
name = "untyped complex"
default:
name = basicnames[t.Etype]
@@ -1333,7 +1333,7 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
n.Orig.exprfmt(s, prec, mode)
return
}
- if n.Type != nil && n.Type.Etype != TIDEAL && n.Type.Etype != TNIL && n.Type != types.Idealbool && n.Type != types.Idealstring {
+ if n.Type != nil && !n.Type.IsUntyped() {
// Need parens when type begins with what might
// be misinterpreted as a unary operator: * or <-.
if n.Type.IsPtr() || (n.Type.IsChan() && n.Type.ChanDir() == types.Crecv) {
diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go
index 9079ce2afc..2fbdf71055 100644
--- a/src/cmd/compile/internal/gc/go.go
+++ b/src/cmd/compile/internal/gc/go.go
@@ -259,7 +259,6 @@ type Arch struct {
REGSP int
MAXWIDTH int64
- Use387 bool // should 386 backend use 387 FP instructions instead of sse2.
SoftFloat bool
PadFrame func(int64) int64
@@ -328,10 +327,6 @@ var (
BoundsCheckFunc [ssa.BoundsKindCount]*obj.LSym
ExtendCheckFunc [ssa.BoundsKindCount]*obj.LSym
- // GO386=387
- ControlWord64trunc,
- ControlWord32 *obj.LSym
-
// Wasm
WasmMove,
WasmZero,
diff --git a/src/cmd/compile/internal/gc/gsubr.go b/src/cmd/compile/internal/gc/gsubr.go
index 480d411f49..14c217ff3b 100644
--- a/src/cmd/compile/internal/gc/gsubr.go
+++ b/src/cmd/compile/internal/gc/gsubr.go
@@ -199,7 +199,7 @@ func (pp *Progs) settext(fn *Node) {
ptxt := pp.Prog(obj.ATEXT)
pp.Text = ptxt
- fn.Func.lsym.Func.Text = ptxt
+ fn.Func.lsym.Func().Text = ptxt
ptxt.From.Type = obj.TYPE_MEM
ptxt.From.Name = obj.NAME_EXTERN
ptxt.From.Sym = fn.Func.lsym
diff --git a/src/cmd/compile/internal/gc/iexport.go b/src/cmd/compile/internal/gc/iexport.go
index b3f50b63af..df08a4a6c2 100644
--- a/src/cmd/compile/internal/gc/iexport.go
+++ b/src/cmd/compile/internal/gc/iexport.go
@@ -751,11 +751,11 @@ func (w *exportWriter) param(f *types.Field) {
func constTypeOf(typ *types.Type) Ctype {
switch typ {
- case types.Idealint, types.Idealrune:
+ case types.UntypedInt, types.UntypedRune:
return CTINT
- case types.Idealfloat:
+ case types.UntypedFloat:
return CTFLT
- case types.Idealcomplex:
+ case types.UntypedComplex:
return CTCPLX
}
@@ -780,8 +780,8 @@ func constTypeOf(typ *types.Type) Ctype {
}
func (w *exportWriter) value(typ *types.Type, v Val) {
- if typ.IsUntyped() {
- typ = untype(v.Ctype())
+ if vt := idealType(v.Ctype()); typ.IsUntyped() && typ != vt {
+ Fatalf("exporter: untyped type mismatch, have: %v, want: %v", typ, vt)
}
w.typ(typ)
@@ -1017,6 +1017,8 @@ func (w *exportWriter) symIdx(s *types.Sym) {
}
func (w *exportWriter) typeExt(t *types.Type) {
+ // Export whether this type is marked notinheap.
+ w.bool(t.NotInHeap())
// For type T, export the index of type descriptor symbols of T and *T.
if i, ok := typeSymIdx[t]; ok {
w.int64(i[0])
diff --git a/src/cmd/compile/internal/gc/iimport.go b/src/cmd/compile/internal/gc/iimport.go
index 4169222c14..5f107eeec7 100644
--- a/src/cmd/compile/internal/gc/iimport.go
+++ b/src/cmd/compile/internal/gc/iimport.go
@@ -375,7 +375,7 @@ func (p *importReader) value() (typ *types.Type, v Val) {
v.U = p.string()
case CTINT:
x := new(Mpint)
- x.Rune = typ == types.Idealrune
+ x.Rune = typ == types.UntypedRune
p.mpint(&x.Val, typ)
v.U = x
case CTFLT:
@@ -596,7 +596,6 @@ func (r *importReader) typ1() *types.Type {
// Ensure we expand the interface in the frontend (#25055).
checkwidth(t)
-
return t
}
}
@@ -711,6 +710,7 @@ func (r *importReader) symIdx(s *types.Sym) {
}
func (r *importReader) typeExt(t *types.Type) {
+ t.SetNotInHeap(r.bool())
i, pi := r.int64(), r.int64()
if i != -1 && pi != -1 {
typeSymIdx[t] = [2]int64{i, pi}
diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go
index fa5b3ec698..ba12cf40b5 100644
--- a/src/cmd/compile/internal/gc/inl.go
+++ b/src/cmd/compile/internal/gc/inl.go
@@ -325,18 +325,10 @@ func (v *hairyVisitor) visit(n *Node) bool {
break
}
- if fn := n.Left.Func; fn != nil && fn.Inl != nil {
- v.budget -= fn.Inl.Cost
+ if fn := inlCallee(n.Left); fn != nil && fn.Func.Inl != nil {
+ v.budget -= fn.Func.Inl.Cost
break
}
- if n.Left.isMethodExpression() {
- if d := asNode(n.Left.Sym.Def); d != nil && d.Func.Inl != nil {
- v.budget -= d.Func.Inl.Cost
- break
- }
- }
- // TODO(mdempsky): Budget for OCLOSURE calls if we
- // ever allow that. See #15561 and #23093.
// Call cost for non-leaf inlining.
v.budget -= v.extraCallCost
@@ -385,14 +377,11 @@ func (v *hairyVisitor) visit(n *Node) bool {
case OCLOSURE,
OCALLPART,
ORANGE,
- OFOR,
- OFORUNTIL,
OSELECT,
OTYPESW,
OGO,
ODEFER,
ODCLTYPE, // can't print yet
- OBREAK,
ORETJMP:
v.reason = "unhandled op " + n.Op.String()
return true
@@ -400,10 +389,23 @@ func (v *hairyVisitor) visit(n *Node) bool {
case OAPPEND:
v.budget -= inlineExtraAppendCost
- case ODCLCONST, OEMPTY, OFALL, OLABEL:
+ case ODCLCONST, OEMPTY, OFALL:
// These nodes don't produce code; omit from inlining budget.
return false
+ case OLABEL:
+ // TODO(mdempsky): Add support for inlining labeled control statements.
+ if n.labeledControl() != nil {
+ v.reason = "labeled control"
+ return true
+ }
+
+ case OBREAK, OCONTINUE:
+ if n.Sym != nil {
+ // Should have short-circuited due to labeledControl above.
+ Fatalf("unexpected labeled break/continue: %v", n)
+ }
+
case OIF:
if Isconst(n.Left, CTBOOL) {
// This if and the condition cost nothing.
@@ -669,53 +671,11 @@ func inlnode(n *Node, maxCost int32, inlMap map[*Node]bool) *Node {
if Debug['m'] > 3 {
fmt.Printf("%v:call to func %+v\n", n.Line(), n.Left)
}
- if n.Left.Func != nil && n.Left.Func.Inl != nil && !isIntrinsicCall(n) { // normal case
- n = mkinlcall(n, n.Left, maxCost, inlMap)
- } else if n.Left.isMethodExpression() && asNode(n.Left.Sym.Def) != nil {
- n = mkinlcall(n, asNode(n.Left.Sym.Def), maxCost, inlMap)
- } else if n.Left.Op == OCLOSURE {
- if f := inlinableClosure(n.Left); f != nil {
- n = mkinlcall(n, f, maxCost, inlMap)
- }
- } else if n.Left.Op == ONAME && n.Left.Name != nil && n.Left.Name.Defn != nil {
- if d := n.Left.Name.Defn; d.Op == OAS && d.Right.Op == OCLOSURE {
- if f := inlinableClosure(d.Right); f != nil {
- // NB: this check is necessary to prevent indirect re-assignment of the variable
- // having the address taken after the invocation or only used for reads is actually fine
- // but we have no easy way to distinguish the safe cases
- if d.Left.Name.Addrtaken() {
- if Debug['m'] > 1 {
- fmt.Printf("%v: cannot inline escaping closure variable %v\n", n.Line(), n.Left)
- }
- if logopt.Enabled() {
- logopt.LogOpt(n.Pos, "cannotInlineCall", "inline", Curfn.funcname(),
- fmt.Sprintf("%v cannot be inlined (escaping closure variable)", n.Left))
- }
- break
- }
-
- // ensure the variable is never re-assigned
- if unsafe, a := reassigned(n.Left); unsafe {
- if Debug['m'] > 1 {
- if a != nil {
- fmt.Printf("%v: cannot inline re-assigned closure variable at %v: %v\n", n.Line(), a.Line(), a)
- if logopt.Enabled() {
- logopt.LogOpt(n.Pos, "cannotInlineCall", "inline", Curfn.funcname(),
- fmt.Sprintf("%v cannot be inlined (re-assigned closure variable)", a))
- }
- } else {
- fmt.Printf("%v: cannot inline global closure variable %v\n", n.Line(), n.Left)
- if logopt.Enabled() {
- logopt.LogOpt(n.Pos, "cannotInlineCall", "inline", Curfn.funcname(),
- fmt.Sprintf("%v cannot be inlined (global closure variable)", n.Left))
- }
- }
- }
- break
- }
- n = mkinlcall(n, f, maxCost, inlMap)
- }
- }
+ if isIntrinsicCall(n) {
+ break
+ }
+ if fn := inlCallee(n.Left); fn != nil && fn.Func.Inl != nil {
+ n = mkinlcall(n, fn, maxCost, inlMap)
}
case OCALLMETH:
@@ -739,16 +699,73 @@ func inlnode(n *Node, maxCost int32, inlMap map[*Node]bool) *Node {
return n
}
-// inlinableClosure takes an OCLOSURE node and follows linkage to the matching ONAME with
-// the inlinable body. Returns nil if the function is not inlinable.
-func inlinableClosure(n *Node) *Node {
- c := n.Func.Closure
- caninl(c)
- f := c.Func.Nname
- if f == nil || f.Func.Inl == nil {
+// inlCallee takes a function-typed expression and returns the underlying function ONAME
+// that it refers to if statically known. Otherwise, it returns nil.
+func inlCallee(fn *Node) *Node {
+ fn = staticValue(fn)
+ switch {
+ case fn.Op == ONAME && fn.Class() == PFUNC:
+ if fn.isMethodExpression() {
+ return asNode(fn.Sym.Def)
+ }
+ return fn
+ case fn.Op == OCLOSURE:
+ c := fn.Func.Closure
+ caninl(c)
+ return c.Func.Nname
+ }
+ return nil
+}
+
+func staticValue(n *Node) *Node {
+ for {
+ n1 := staticValue1(n)
+ if n1 == nil {
+ return n
+ }
+ n = n1
+ }
+}
+
+// staticValue1 implements a simple SSA-like optimization. If n is a local variable
+// that is initialized and never reassigned, staticValue1 returns the initializer
+// expression. Otherwise, it returns nil.
+func staticValue1(n *Node) *Node {
+ if n.Op != ONAME || n.Class() != PAUTO || n.Name.Addrtaken() {
return nil
}
- return f
+
+ defn := n.Name.Defn
+ if defn == nil {
+ return nil
+ }
+
+ var rhs *Node
+FindRHS:
+ switch defn.Op {
+ case OAS:
+ rhs = defn.Right
+ case OAS2:
+ for i, lhs := range defn.List.Slice() {
+ if lhs == n {
+ rhs = defn.Rlist.Index(i)
+ break FindRHS
+ }
+ }
+ Fatalf("%v missing from LHS of %v", n, defn)
+ default:
+ return nil
+ }
+ if rhs == nil {
+ Fatalf("RHS is nil: %v", defn)
+ }
+
+ unsafe, _ := reassigned(n)
+ if unsafe {
+ return nil
+ }
+
+ return rhs
}
// reassigned takes an ONAME node, walks the function in which it is defined, and returns a boolean
@@ -831,16 +848,19 @@ func (v *reassignVisitor) visitList(l Nodes) *Node {
return nil
}
-func tinlvar(t *types.Field, inlvars map[*Node]*Node) *Node {
- if n := asNode(t.Nname); n != nil && !n.isBlank() {
- inlvar := inlvars[n]
- if inlvar == nil {
- Fatalf("missing inlvar for %v\n", n)
- }
- return inlvar
+func inlParam(t *types.Field, as *Node, inlvars map[*Node]*Node) *Node {
+ n := asNode(t.Nname)
+ if n == nil || n.isBlank() {
+ return nblank
}
- return typecheck(nblank, ctxExpr|ctxAssign)
+ inlvar := inlvars[n]
+ if inlvar == nil {
+ Fatalf("missing inlvar for %v", n)
+ }
+ as.Ninit.Append(nod(ODCL, inlvar, nil))
+ inlvar.Name.Defn = as
+ return inlvar
}
var inlgen int
@@ -970,14 +990,15 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
continue
}
if ln.isParamStackCopy() { // ignore the on-stack copy of a parameter that moved to the heap
- continue
- }
- inlvars[ln] = typecheck(inlvar(ln), ctxExpr)
- if ln.Class() == PPARAM || ln.Name.Param.Stackcopy != nil && ln.Name.Param.Stackcopy.Class() == PPARAM {
- ninit.Append(nod(ODCL, inlvars[ln], nil))
+ // TODO(mdempsky): Remove once I'm confident
+ // this never actually happens. We currently
+ // perform inlining before escape analysis, so
+ // nothing should have moved to the heap yet.
+ Fatalf("impossible: %v", ln)
}
+ inlf := typecheck(inlvar(ln), ctxExpr)
+ inlvars[ln] = inlf
if genDwarfInline > 0 {
- inlf := inlvars[ln]
if ln.Class() == PPARAM {
inlf.Name.SetInlFormal(true)
} else {
@@ -1019,56 +1040,42 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
// Assign arguments to the parameters' temp names.
as := nod(OAS2, nil, nil)
- as.Rlist.Set(n.List.Slice())
+ as.SetColas(true)
+ if n.Op == OCALLMETH {
+ if n.Left.Left == nil {
+ Fatalf("method call without receiver: %+v", n)
+ }
+ as.Rlist.Append(n.Left.Left)
+ }
+ as.Rlist.Append(n.List.Slice()...)
// For non-dotted calls to variadic functions, we assign the
// variadic parameter's temp name separately.
var vas *Node
- if fn.IsMethod() {
- rcv := fn.Type.Recv()
-
- if n.Left.Op == ODOTMETH {
- // For x.M(...), assign x directly to the
- // receiver parameter.
- if n.Left.Left == nil {
- Fatalf("method call without receiver: %+v", n)
- }
- ras := nod(OAS, tinlvar(rcv, inlvars), n.Left.Left)
- ras = typecheck(ras, ctxStmt)
- ninit.Append(ras)
- } else {
- // For T.M(...), add the receiver parameter to
- // as.List, so it's assigned by the normal
- // arguments.
- if as.Rlist.Len() == 0 {
- Fatalf("non-method call to method without first arg: %+v", n)
- }
- as.List.Append(tinlvar(rcv, inlvars))
- }
+ if recv := fn.Type.Recv(); recv != nil {
+ as.List.Append(inlParam(recv, as, inlvars))
}
-
for _, param := range fn.Type.Params().Fields().Slice() {
// For ordinary parameters or variadic parameters in
// dotted calls, just add the variable to the
// assignment list, and we're done.
if !param.IsDDD() || n.IsDDD() {
- as.List.Append(tinlvar(param, inlvars))
+ as.List.Append(inlParam(param, as, inlvars))
continue
}
// Otherwise, we need to collect the remaining values
// to pass as a slice.
- numvals := n.List.Len()
-
x := as.List.Len()
- for as.List.Len() < numvals {
+ for as.List.Len() < as.Rlist.Len() {
as.List.Append(argvar(param.Type, as.List.Len()))
}
varargs := as.List.Slice()[x:]
- vas = nod(OAS, tinlvar(param, inlvars), nil)
+ vas = nod(OAS, nil, nil)
+ vas.Left = inlParam(param, vas, inlvars)
if len(varargs) == 0 {
vas.Right = nodnil()
vas.Right.Type = param.Type
diff --git a/src/cmd/compile/internal/gc/inl_test.go b/src/cmd/compile/internal/gc/inl_test.go
index 9d3b8c59fd..afa6b98315 100644
--- a/src/cmd/compile/internal/gc/inl_test.go
+++ b/src/cmd/compile/internal/gc/inl_test.go
@@ -83,7 +83,7 @@ func TestIntendedInlining(t *testing.T) {
"puintptr.ptr",
"spanOf",
"spanOfUnchecked",
- //"(*gcWork).putFast", // TODO(austin): For debugging #27993
+ "(*gcWork).putFast",
"(*gcWork).tryGetFast",
"(*guintptr).set",
"(*markBits).advance",
@@ -115,6 +115,7 @@ func TestIntendedInlining(t *testing.T) {
"byLiteral.Len",
"byLiteral.Less",
"byLiteral.Swap",
+ "(*dictDecoder).tryWriteCopy",
},
"encoding/base64": {
"assemble32",
diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go
index 1a344c6566..7cce371408 100644
--- a/src/cmd/compile/internal/gc/lex.go
+++ b/src/cmd/compile/internal/gc/lex.go
@@ -48,8 +48,11 @@ const (
Nowritebarrierrec // error on write barrier in this or recursive callees
Yeswritebarrierrec // cancels Nowritebarrierrec in this function and callees
- // Runtime-only type pragmas
+ // Runtime and cgo type pragmas
NotInHeap // values of this type must not be heap allocated
+
+ // Go command pragmas
+ GoBuildPragma
)
const (
@@ -71,6 +74,8 @@ const (
func pragmaFlag(verb string) PragmaFlag {
switch verb {
+ case "go:build":
+ return GoBuildPragma
case "go:nointerface":
if objabi.Fieldtrack_enabled != 0 {
return Nointerface
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
index 7ad3bfe0c8..2fffe625cd 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -516,6 +516,7 @@ func Main(archInit func(*Arch)) {
}
ssaDump = os.Getenv("GOSSAFUNC")
+ ssaDir = os.Getenv("GOSSADIR")
if ssaDump != "" {
if strings.HasSuffix(ssaDump, "+") {
ssaDump = ssaDump[:len(ssaDump)-1]
@@ -967,9 +968,10 @@ func readSymABIs(file, myimportpath string) {
if len(parts) != 3 {
log.Fatalf(`%s:%d: invalid symabi: syntax is "%s sym abi"`, file, lineNum, parts[0])
}
- sym, abi := parts[1], parts[2]
- if abi != "ABI0" { // Only supported external ABI right now
- log.Fatalf(`%s:%d: invalid symabi: unknown abi "%s"`, file, lineNum, abi)
+ sym, abistr := parts[1], parts[2]
+ abi, valid := obj.ParseABI(abistr)
+ if !valid {
+ log.Fatalf(`%s:%d: invalid symabi: unknown abi "%s"`, file, lineNum, abistr)
}
// If the symbol is already prefixed with
@@ -982,9 +984,9 @@ func readSymABIs(file, myimportpath string) {
// Record for later.
if parts[0] == "def" {
- symabiDefs[sym] = obj.ABI0
+ symabiDefs[sym] = abi
} else {
- symabiRefs[sym] = obj.ABI0
+ symabiRefs[sym] = abi
}
default:
log.Fatalf(`%s:%d: invalid symabi type "%s"`, file, lineNum, parts[0])
diff --git a/src/cmd/compile/internal/gc/noder.go b/src/cmd/compile/internal/gc/noder.go
index 5dce533e4b..68d0327cdb 100644
--- a/src/cmd/compile/internal/gc/noder.go
+++ b/src/cmd/compile/internal/gc/noder.go
@@ -242,6 +242,7 @@ func (p *noder) node() {
mkpackage(p.file.PkgName.Value)
if pragma, ok := p.file.Pragma.(*Pragma); ok {
+ pragma.Flag &^= GoBuildPragma
p.checkUnused(pragma)
}
@@ -773,7 +774,7 @@ func (p *noder) sum(x syntax.Expr) *Node {
n := p.expr(x)
if Isconst(n, CTSTR) && n.Sym == nil {
nstr = n
- chunks = append(chunks, strlit(nstr))
+ chunks = append(chunks, nstr.StringVal())
}
for i := len(adds) - 1; i >= 0; i-- {
@@ -783,12 +784,12 @@ func (p *noder) sum(x syntax.Expr) *Node {
if Isconst(r, CTSTR) && r.Sym == nil {
if nstr != nil {
// Collapse r into nstr instead of adding to n.
- chunks = append(chunks, strlit(r))
+ chunks = append(chunks, r.StringVal())
continue
}
nstr = r
- chunks = append(chunks, strlit(nstr))
+ chunks = append(chunks, nstr.StringVal())
} else {
if len(chunks) > 1 {
nstr.SetVal(Val{U: strings.Join(chunks, "")})
diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go
index b55331a948..f6557e2d15 100644
--- a/src/cmd/compile/internal/gc/obj.go
+++ b/src/cmd/compile/internal/gc/obj.go
@@ -272,7 +272,7 @@ func dumpGlobalConst(n *Node) {
default:
return
}
- Ctxt.DwarfIntConst(myimportpath, n.Sym.Name, typesymname(t), n.Int64())
+ Ctxt.DwarfIntConst(myimportpath, n.Sym.Name, typesymname(t), n.Int64Val())
}
func dumpglobls() {
@@ -305,20 +305,21 @@ func dumpglobls() {
// global symbols can't be declared during parallel compilation.
func addGCLocals() {
for _, s := range Ctxt.Text {
- if s.Func == nil {
+ fn := s.Func()
+ if fn == nil {
continue
}
- for _, gcsym := range []*obj.LSym{s.Func.GCArgs, s.Func.GCLocals, s.Func.GCRegs} {
+ for _, gcsym := range []*obj.LSym{fn.GCArgs, fn.GCLocals, fn.GCRegs} {
if gcsym != nil && !gcsym.OnList() {
ggloblsym(gcsym, int32(len(gcsym.P)), obj.RODATA|obj.DUPOK)
}
}
- if x := s.Func.StackObjects; x != nil {
+ if x := fn.StackObjects; x != nil {
attr := int16(obj.RODATA)
ggloblsym(x, int32(len(x.P)), attr)
x.Set(obj.AttrStatic, true)
}
- if x := s.Func.OpenCodedDeferInfo; x != nil {
+ if x := fn.OpenCodedDeferInfo; x != nil {
ggloblsym(x, int32(len(x.P)), obj.RODATA|obj.DUPOK)
}
}
diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go
index 75da154fe2..e562ab7556 100644
--- a/src/cmd/compile/internal/gc/order.go
+++ b/src/cmd/compile/internal/gc/order.go
@@ -1102,7 +1102,7 @@ func (o *Order) expr(n, lhs *Node) *Node {
haslit := false
for _, n1 := range n.List.Slice() {
hasbyte = hasbyte || n1.Op == OBYTES2STR
- haslit = haslit || n1.Op == OLITERAL && len(strlit(n1)) != 0
+ haslit = haslit || n1.Op == OLITERAL && len(n1.StringVal()) != 0
}
if haslit && hasbyte {
@@ -1274,7 +1274,7 @@ func (o *Order) expr(n, lhs *Node) *Node {
var t *types.Type
switch n.Op {
case OSLICELIT:
- t = types.NewArray(n.Type.Elem(), n.Right.Int64())
+ t = types.NewArray(n.Type.Elem(), n.Right.Int64Val())
case OCALLPART:
t = partialCallType(n)
}
diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go
index 74262595b0..353f4b08c9 100644
--- a/src/cmd/compile/internal/gc/pgen.go
+++ b/src/cmd/compile/internal/gc/pgen.go
@@ -231,6 +231,11 @@ func compile(fn *Node) {
return
}
+ // Set up the function's LSym early to avoid data races with the assemblers.
+ // Do this before walk, as walk needs the LSym to set attributes/relocations
+ // (e.g. in markTypeUsedInInterface).
+ fn.Func.initLSym(true)
+
walk(fn)
if nerrors != 0 {
return
@@ -250,9 +255,6 @@ func compile(fn *Node) {
return
}
- // Set up the function's LSym early to avoid data races with the assemblers.
- fn.Func.initLSym(true)
-
// Make sure type syms are declared for all types that might
// be types of stack objects. We need to do this here
// because symbols must be allocated before the parallel
@@ -264,8 +266,8 @@ func compile(fn *Node) {
dtypesym(n.Type)
// Also make sure we allocate a linker symbol
// for the stack object data, for the same reason.
- if fn.Func.lsym.Func.StackObjects == nil {
- fn.Func.lsym.Func.StackObjects = Ctxt.Lookup(fn.Func.lsym.Name + ".stkobj")
+ if fn.Func.lsym.Func().StackObjects == nil {
+ fn.Func.lsym.Func().StackObjects = Ctxt.Lookup(fn.Func.lsym.Name + ".stkobj")
}
}
}
@@ -413,7 +415,7 @@ func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.S
case PAUTO:
if !n.Name.Used() {
// Text == nil -> generating abstract function
- if fnsym.Func.Text != nil {
+ if fnsym.Func().Text != nil {
Fatalf("debuginfo unused node (AllocFrame should truncate fn.Func.Dcl)")
}
continue
@@ -423,7 +425,7 @@ func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.S
continue
}
apdecls = append(apdecls, n)
- fnsym.Func.RecordAutoType(ngotype(n).Linksym())
+ fnsym.Func().RecordAutoType(ngotype(n).Linksym())
}
decls, dwarfVars := createDwarfVars(fnsym, fn.Func, apdecls)
@@ -433,7 +435,7 @@ func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.S
// the function symbol to insure that the type included in DWARF
// processing during linking.
typesyms := []*obj.LSym{}
- for t, _ := range fnsym.Func.Autot {
+ for t, _ := range fnsym.Func().Autot {
typesyms = append(typesyms, t)
}
sort.Sort(obj.BySymName(typesyms))
@@ -442,7 +444,7 @@ func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.S
r.Sym = sym
r.Type = objabi.R_USETYPE
}
- fnsym.Func.Autot = nil
+ fnsym.Func().Autot = nil
var varScopes []ScopeID
for _, decl := range decls {
@@ -520,7 +522,7 @@ func createSimpleVar(fnsym *obj.LSym, n *Node) *dwarf.Var {
}
typename := dwarf.InfoPrefix + typesymname(n.Type)
- delete(fnsym.Func.Autot, ngotype(n).Linksym())
+ delete(fnsym.Func().Autot, ngotype(n).Linksym())
inlIndex := 0
if genDwarfInline > 1 {
if n.Name.InlFormal() || n.Name.InlLocal() {
@@ -665,7 +667,7 @@ func createDwarfVars(fnsym *obj.LSym, fn *Func, apDecls []*Node) ([]*Node, []*dw
ChildIndex: -1,
})
// Record go type of to insure that it gets emitted by the linker.
- fnsym.Func.RecordAutoType(ngotype(n).Linksym())
+ fnsym.Func().RecordAutoType(ngotype(n).Linksym())
}
return decls, vars
@@ -729,7 +731,7 @@ func createComplexVar(fnsym *obj.LSym, fn *Func, varID ssa.VarID) *dwarf.Var {
}
gotype := ngotype(n).Linksym()
- delete(fnsym.Func.Autot, gotype)
+ delete(fnsym.Func().Autot, gotype)
typename := dwarf.InfoPrefix + gotype.Name[len("type."):]
inlIndex := 0
if genDwarfInline > 1 {
diff --git a/src/cmd/compile/internal/gc/plive.go b/src/cmd/compile/internal/gc/plive.go
index a9ea37701e..b471accb65 100644
--- a/src/cmd/compile/internal/gc/plive.go
+++ b/src/cmd/compile/internal/gc/plive.go
@@ -1552,26 +1552,27 @@ func liveness(e *ssafn, f *ssa.Func, pp *Progs) LivenessMap {
// Emit the live pointer map data structures
ls := e.curfn.Func.lsym
- ls.Func.GCArgs, ls.Func.GCLocals, ls.Func.GCRegs = lv.emit()
+ fninfo := ls.Func()
+ fninfo.GCArgs, fninfo.GCLocals, fninfo.GCRegs = lv.emit()
p := pp.Prog(obj.AFUNCDATA)
Addrconst(&p.From, objabi.FUNCDATA_ArgsPointerMaps)
p.To.Type = obj.TYPE_MEM
p.To.Name = obj.NAME_EXTERN
- p.To.Sym = ls.Func.GCArgs
+ p.To.Sym = fninfo.GCArgs
p = pp.Prog(obj.AFUNCDATA)
Addrconst(&p.From, objabi.FUNCDATA_LocalsPointerMaps)
p.To.Type = obj.TYPE_MEM
p.To.Name = obj.NAME_EXTERN
- p.To.Sym = ls.Func.GCLocals
+ p.To.Sym = fninfo.GCLocals
if !go115ReduceLiveness {
p = pp.Prog(obj.AFUNCDATA)
Addrconst(&p.From, objabi.FUNCDATA_RegPointerMaps)
p.To.Type = obj.TYPE_MEM
p.To.Name = obj.NAME_EXTERN
- p.To.Sym = ls.Func.GCRegs
+ p.To.Sym = fninfo.GCRegs
}
return lv.livenessMap
diff --git a/src/cmd/compile/internal/gc/range.go b/src/cmd/compile/internal/gc/range.go
index 5434b0167a..6d22964dcd 100644
--- a/src/cmd/compile/internal/gc/range.go
+++ b/src/cmd/compile/internal/gc/range.go
@@ -112,12 +112,13 @@ func typecheckrangeExpr(n *Node) {
v2 = nil
}
- var why string
if v1 != nil {
if v1.Name != nil && v1.Name.Defn == n {
v1.Type = t1
- } else if v1.Type != nil && assignop(t1, v1.Type, &why) == 0 {
- yyerrorl(n.Pos, "cannot assign type %v to %L in range%s", t1, v1, why)
+ } else if v1.Type != nil {
+ if op, why := assignop(t1, v1.Type); op == OXXX {
+ yyerrorl(n.Pos, "cannot assign type %v to %L in range%s", t1, v1, why)
+ }
}
checkassign(n, v1)
}
@@ -125,8 +126,10 @@ func typecheckrangeExpr(n *Node) {
if v2 != nil {
if v2.Name != nil && v2.Name.Defn == n {
v2.Type = t2
- } else if v2.Type != nil && assignop(t2, v2.Type, &why) == 0 {
- yyerrorl(n.Pos, "cannot assign type %v to %L in range%s", t2, v2, why)
+ } else if v2.Type != nil {
+ if op, why := assignop(t2, v2.Type); op == OXXX {
+ yyerrorl(n.Pos, "cannot assign type %v to %L in range%s", t2, v2, why)
+ }
}
checkassign(n, v2)
}
diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go
index 93dbb9f690..d16a00b787 100644
--- a/src/cmd/compile/internal/gc/reflect.go
+++ b/src/cmd/compile/internal/gc/reflect.go
@@ -61,8 +61,9 @@ const (
MAXELEMSIZE = 128
)
-func structfieldSize() int { return 3 * Widthptr } // Sizeof(runtime.structfield{})
-func imethodSize() int { return 4 + 4 } // Sizeof(runtime.imethod{})
+func structfieldSize() int { return 3 * Widthptr } // Sizeof(runtime.structfield{})
+func imethodSize() int { return 4 + 4 } // Sizeof(runtime.imethod{})
+func commonSize() int { return 4*Widthptr + 8 + 8 } // Sizeof(runtime._type{})
func uncommonSize(t *types.Type) int { // Sizeof(runtime.uncommontype{})
if t.Sym == nil && len(methods(t)) == 0 {
@@ -510,6 +511,7 @@ func dimportpath(p *types.Pkg) {
s := Ctxt.Lookup("type..importpath." + p.Prefix + ".")
ot := dnameData(s, 0, str, "", nil, false)
ggloblsym(s, int32(ot), obj.DUPOK|obj.RODATA)
+ s.Set(obj.AttrContentAddressable, true)
p.Pathsym = s
}
@@ -637,6 +639,7 @@ func dname(name, tag string, pkg *types.Pkg, exported bool) *obj.LSym {
}
ot := dnameData(s, 0, name, tag, pkg, exported)
ggloblsym(s, int32(ot), obj.DUPOK|obj.RODATA)
+ s.Set(obj.AttrContentAddressable, true)
return s
}
@@ -1272,8 +1275,9 @@ func dtypesym(t *types.Type) *obj.LSym {
}
ot = dgopkgpath(lsym, ot, tpkg)
+ xcount := sort.Search(n, func(i int) bool { return !types.IsExported(m[i].name.Name) })
ot = dsymptr(lsym, ot, lsym, ot+3*Widthptr+uncommonSize(t))
- ot = duintptr(lsym, ot, uint64(n))
+ ot = duintptr(lsym, ot, uint64(xcount))
ot = duintptr(lsym, ot, uint64(n))
dataAdd := imethodSize() * n
ot = dextratype(lsym, ot, t, dataAdd)
@@ -1449,6 +1453,20 @@ func dtypesym(t *types.Type) *obj.LSym {
return lsym
}
+// ifaceMethodOffset returns the offset of the i-th method in the interface
+// type descriptor, ityp.
+func ifaceMethodOffset(ityp *types.Type, i int64) int64 {
+ // interface type descriptor layout is struct {
+ // _type // commonSize
+ // pkgpath // 1 word
+ // []imethod // 3 words (pointing to [...]imethod below)
+ // uncommontype // uncommonSize
+ // [...]imethod
+ // }
+ // The size of imethod is 8.
+ return int64(commonSize()+4*Widthptr+uncommonSize(ityp)) + i*8
+}
+
// for each itabEntry, gather the methods on
// the concrete type that implement the interface
func peekitabs() {
diff --git a/src/cmd/compile/internal/gc/scope.go b/src/cmd/compile/internal/gc/scope.go
index d7239d5693..e66b859e10 100644
--- a/src/cmd/compile/internal/gc/scope.go
+++ b/src/cmd/compile/internal/gc/scope.go
@@ -62,9 +62,9 @@ func scopePCs(fnsym *obj.LSym, marks []Mark, dwarfScopes []dwarf.Scope) {
if len(marks) == 0 {
return
}
- p0 := fnsym.Func.Text
+ p0 := fnsym.Func().Text
scope := findScope(marks, p0.Pos)
- for p := fnsym.Func.Text; p != nil; p = p.Link {
+ for p := p0; p != nil; p = p.Link {
if p.Pos == p0.Pos {
continue
}
diff --git a/src/cmd/compile/internal/gc/sinit.go b/src/cmd/compile/internal/gc/sinit.go
index 71ed558461..fda33534b6 100644
--- a/src/cmd/compile/internal/gc/sinit.go
+++ b/src/cmd/compile/internal/gc/sinit.go
@@ -128,7 +128,7 @@ func (s *InitSchedule) staticcopy(l *Node, r *Node) bool {
case OSLICELIT:
// copy slice
a := s.inittemps[r]
- slicesym(l, a, r.Right.Int64())
+ slicesym(l, a, r.Right.Int64Val())
return true
case OARRAYLIT, OSTRUCTLIT:
@@ -205,7 +205,7 @@ func (s *InitSchedule) staticassign(l *Node, r *Node) bool {
case OSTR2BYTES:
if l.Class() == PEXTERN && r.Left.Op == OLITERAL {
- sval := strlit(r.Left)
+ sval := r.Left.StringVal()
slicebytes(l, sval)
return true
}
@@ -213,7 +213,7 @@ func (s *InitSchedule) staticassign(l *Node, r *Node) bool {
case OSLICELIT:
s.initplan(r)
// Init slice.
- bound := r.Right.Int64()
+ bound := r.Right.Int64Val()
ta := types.NewArray(r.Type.Elem(), bound)
ta.SetNoalg(true)
a := staticname(ta)
@@ -278,7 +278,7 @@ func (s *InitSchedule) staticassign(l *Node, r *Node) bool {
return Isconst(val, CTNIL)
}
- markTypeUsedInInterface(val.Type)
+ markTypeUsedInInterface(val.Type, l.Sym.Linksym())
var itab *Node
if l.Type.IsEmptyInterface() {
@@ -413,7 +413,7 @@ func getdyn(n *Node, top bool) initGenType {
if !top {
return initDynamic
}
- if n.Right.Int64()/4 > int64(n.List.Len()) {
+ if n.Right.Int64Val()/4 > int64(n.List.Len()) {
// <25% of entries have explicit values.
// Very rough estimation, it takes 4 bytes of instructions
// to initialize 1 byte of result. So don't use a static
@@ -589,12 +589,12 @@ func isSmallSliceLit(n *Node) bool {
r := n.Right
- return smallintconst(r) && (n.Type.Elem().Width == 0 || r.Int64() <= smallArrayBytes/n.Type.Elem().Width)
+ return smallintconst(r) && (n.Type.Elem().Width == 0 || r.Int64Val() <= smallArrayBytes/n.Type.Elem().Width)
}
func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) {
// make an array type corresponding the number of elements we have
- t := types.NewArray(n.Type.Elem(), n.Right.Int64())
+ t := types.NewArray(n.Type.Elem(), n.Right.Int64Val())
dowidth(t)
if ctxt == inNonInitFunction {
@@ -993,7 +993,7 @@ func oaslit(n *Node, init *Nodes) bool {
func getlit(lit *Node) int {
if smallintconst(lit) {
- return int(lit.Int64())
+ return int(lit.Int64Val())
}
return -1
}
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index d0b3e8df94..d8f627c213 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -9,8 +9,8 @@ import (
"fmt"
"html"
"os"
+ "path/filepath"
"sort"
- "strings"
"bufio"
"bytes"
@@ -27,6 +27,7 @@ var ssaConfig *ssa.Config
var ssaCaches []ssa.Cache
var ssaDump string // early copy of $GOSSAFUNC; the func name to dump output for
+var ssaDir string // optional destination for ssa dump file
var ssaDumpStdout bool // whether to dump to stdout
var ssaDumpCFG string // generate CFGs for these phases
const ssaDumpFile = "ssa.html"
@@ -49,21 +50,16 @@ func initssaconfig() {
// Caching is disabled in the backend, so generating these here avoids allocations.
_ = types.NewPtr(types.Types[TINTER]) // *interface{}
_ = types.NewPtr(types.NewPtr(types.Types[TSTRING])) // **string
- _ = types.NewPtr(types.NewPtr(types.Idealstring)) // **string
_ = types.NewPtr(types.NewSlice(types.Types[TINTER])) // *[]interface{}
_ = types.NewPtr(types.NewPtr(types.Bytetype)) // **byte
_ = types.NewPtr(types.NewSlice(types.Bytetype)) // *[]byte
_ = types.NewPtr(types.NewSlice(types.Types[TSTRING])) // *[]string
- _ = types.NewPtr(types.NewSlice(types.Idealstring)) // *[]string
_ = types.NewPtr(types.NewPtr(types.NewPtr(types.Types[TUINT8]))) // ***uint8
_ = types.NewPtr(types.Types[TINT16]) // *int16
_ = types.NewPtr(types.Types[TINT64]) // *int64
_ = types.NewPtr(types.Errortype) // *error
types.NewPtrCacheEnabled = false
ssaConfig = ssa.NewConfig(thearch.LinkArch.Name, *types_, Ctxt, Debug['N'] == 0)
- if thearch.LinkArch.Name == "386" {
- ssaConfig.Set387(thearch.Use387)
- }
ssaConfig.SoftFloat = thearch.SoftFloat
ssaConfig.Race = flag_race
ssaCaches = make([]ssa.Cache, nBackendWorkers)
@@ -174,10 +170,6 @@ func initssaconfig() {
ExtendCheckFunc[ssa.BoundsSlice3CU] = sysvar("panicExtendSlice3CU")
}
- // GO386=387 runtime definitions
- ControlWord64trunc = sysvar("controlWord64trunc") // uint16
- ControlWord32 = sysvar("controlWord32") // uint16
-
// Wasm (all asm funcs with special ABIs)
WasmMove = sysvar("wasmMove")
WasmZero = sysvar("wasmZero")
@@ -248,7 +240,7 @@ func dvarint(x *obj.LSym, off int, v int64) int {
// - Offset of where argument should be placed in the args frame when making call
func (s *state) emitOpenDeferInfo() {
x := Ctxt.Lookup(s.curfn.Func.lsym.Name + ".opendefer")
- s.curfn.Func.lsym.Func.OpenCodedDeferInfo = x
+ s.curfn.Func.lsym.Func().OpenCodedDeferInfo = x
off := 0
// Compute maxargsize (max size of arguments for all defers)
@@ -347,7 +339,13 @@ func buildssa(fn *Node, worker int) *ssa.Func {
s.f.Entry.Pos = fn.Pos
if printssa {
- s.f.HTMLWriter = ssa.NewHTMLWriter(ssaDumpFile, s.f, ssaDumpCFG)
+ ssaDF := ssaDumpFile
+ if ssaDir != "" {
+ ssaDF = filepath.Join(ssaDir, myimportpath+"."+name+".html")
+ ssaD := filepath.Dir(ssaDF)
+ os.MkdirAll(ssaD, 0755)
+ }
+ s.f.HTMLWriter = ssa.NewHTMLWriter(ssaDF, s.f, ssaDumpCFG)
// TODO: generate and print a mapping from nodes to values and blocks
dumpSourcesColumn(s.f.HTMLWriter, fn)
s.f.HTMLWriter.WriteAST("AST", astBuf)
@@ -1273,7 +1271,7 @@ func (s *state) stmt(n *Node) {
// We're assigning a slicing operation back to its source.
// Don't write back fields we aren't changing. See issue #14855.
i, j, k := rhs.SliceBounds()
- if i != nil && (i.Op == OLITERAL && i.Val().Ctype() == CTINT && i.Int64() == 0) {
+ if i != nil && (i.Op == OLITERAL && i.Val().Ctype() == CTINT && i.Int64Val() == 0) {
// [0:...] is the same as [:...]
i = nil
}
@@ -1303,7 +1301,7 @@ func (s *state) stmt(n *Node) {
case OIF:
if Isconst(n.Left, CTBOOL) {
s.stmtList(n.Left.Ninit)
- if n.Left.Bool() {
+ if n.Left.BoolVal() {
s.stmtList(n.Nbody)
} else {
s.stmtList(n.Rlist)
@@ -2557,22 +2555,22 @@ func (s *state) expr(n *Node) *ssa.Value {
return s.addr(n.Left)
case ORESULT:
- if s.prevCall == nil || s.prevCall.Op != ssa.OpStaticLECall {
+ if s.prevCall == nil || s.prevCall.Op != ssa.OpStaticLECall && s.prevCall.Op != ssa.OpInterLECall && s.prevCall.Op != ssa.OpClosureLECall {
// Do the old thing
addr := s.constOffPtrSP(types.NewPtr(n.Type), n.Xoffset)
- return s.load(n.Type, addr)
+ return s.rawLoad(n.Type, addr)
}
which := s.prevCall.Aux.(*ssa.AuxCall).ResultForOffset(n.Xoffset)
if which == -1 {
// Do the old thing // TODO: Panic instead.
addr := s.constOffPtrSP(types.NewPtr(n.Type), n.Xoffset)
- return s.load(n.Type, addr)
+ return s.rawLoad(n.Type, addr)
}
if canSSAType(n.Type) {
return s.newValue1I(ssa.OpSelectN, n.Type, which, s.prevCall)
} else {
addr := s.newValue1I(ssa.OpSelectNAddr, types.NewPtr(n.Type), which, s.prevCall)
- return s.load(n.Type, addr)
+ return s.rawLoad(n.Type, addr)
}
case ODEREF:
@@ -2612,7 +2610,7 @@ func (s *state) expr(n *Node) *ssa.Value {
// Replace "abc"[1] with 'b'.
// Delayed until now because "abc"[1] is not an ideal constant.
// See test/fixedbugs/issue11370.go.
- return s.newValue0I(ssa.OpConst8, types.Types[TUINT8], int64(int8(strlit(n.Left)[n.Right.Int64()])))
+ return s.newValue0I(ssa.OpConst8, types.Types[TUINT8], int64(int8(n.Left.StringVal()[n.Right.Int64Val()])))
}
a := s.expr(n.Left)
i := s.expr(n.Right)
@@ -2621,7 +2619,7 @@ func (s *state) expr(n *Node) *ssa.Value {
ptrtyp := s.f.Config.Types.BytePtr
ptr := s.newValue1(ssa.OpStringPtr, ptrtyp, a)
if Isconst(n.Right, CTINT) {
- ptr = s.newValue1I(ssa.OpOffPtr, ptrtyp, n.Right.Int64(), ptr)
+ ptr = s.newValue1I(ssa.OpOffPtr, ptrtyp, n.Right.Int64Val(), ptr)
} else {
ptr = s.newValue2(ssa.OpAddPtr, ptrtyp, ptr, i)
}
@@ -4022,11 +4020,6 @@ func init() {
return s.newValue2(ssa.OpMul64uhilo, types.NewTuple(types.Types[TUINT64], types.Types[TUINT64]), args[0], args[1])
},
sys.ArchAMD64, sys.ArchARM64, sys.ArchPPC64LE, sys.ArchPPC64, sys.ArchS390X)
- add("math/big", "divWW",
- func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
- return s.newValue3(ssa.OpDiv128u, types.NewTuple(types.Types[TUINT64], types.Types[TUINT64]), args[0], args[1], args[2])
- },
- sys.ArchAMD64)
}
// findIntrinsic returns a function which builds the SSA equivalent of the
@@ -4256,6 +4249,7 @@ func (s *state) openDeferExit() {
s.lastDeferExit = deferExit
s.lastDeferCount = len(s.openDefers)
zeroval := s.constInt8(types.Types[TUINT8], 0)
+ testLateExpansion := ssa.LateCallExpansionEnabledWithin(s.f)
// Test for and run defers in reverse order
for i := len(s.openDefers) - 1; i >= 0; i-- {
r := s.openDefers[i]
@@ -4293,23 +4287,38 @@ func (s *state) openDeferExit() {
stksize := fn.Type.ArgWidth()
var ACArgs []ssa.Param
var ACResults []ssa.Param
+ var callArgs []*ssa.Value
if r.rcvr != nil {
// rcvr in case of OCALLINTER
v := s.load(r.rcvr.Type.Elem(), r.rcvr)
addr := s.constOffPtrSP(s.f.Config.Types.UintptrPtr, argStart)
ACArgs = append(ACArgs, ssa.Param{Type: types.Types[TUINTPTR], Offset: int32(argStart)})
- s.store(types.Types[TUINTPTR], addr, v)
+ if testLateExpansion {
+ callArgs = append(callArgs, v)
+ } else {
+ s.store(types.Types[TUINTPTR], addr, v)
+ }
}
for j, argAddrVal := range r.argVals {
f := getParam(r.n, j)
pt := types.NewPtr(f.Type)
- addr := s.constOffPtrSP(pt, argStart+f.Offset)
- ACArgs = append(ACArgs, ssa.Param{Type: types.Types[TUINTPTR], Offset: int32(argStart + f.Offset)})
- if !canSSAType(f.Type) {
- s.move(f.Type, addr, argAddrVal)
+ ACArgs = append(ACArgs, ssa.Param{Type: f.Type, Offset: int32(argStart + f.Offset)})
+ if testLateExpansion {
+ var a *ssa.Value
+ if !canSSAType(f.Type) {
+ a = s.newValue2(ssa.OpDereference, f.Type, argAddrVal, s.mem())
+ } else {
+ a = s.load(f.Type, argAddrVal)
+ }
+ callArgs = append(callArgs, a)
} else {
- argVal := s.load(f.Type, argAddrVal)
- s.storeType(f.Type, addr, argVal, 0, false)
+ addr := s.constOffPtrSP(pt, argStart+f.Offset)
+ if !canSSAType(f.Type) {
+ s.move(f.Type, addr, argAddrVal)
+ } else {
+ argVal := s.load(f.Type, argAddrVal)
+ s.storeType(f.Type, addr, argVal, 0, false)
+ }
}
}
var call *ssa.Value
@@ -4317,13 +4326,31 @@ func (s *state) openDeferExit() {
v := s.load(r.closure.Type.Elem(), r.closure)
s.maybeNilCheckClosure(v, callDefer)
codeptr := s.rawLoad(types.Types[TUINTPTR], v)
- call = s.newValue3A(ssa.OpClosureCall, types.TypeMem, ssa.ClosureAuxCall(ACArgs, ACResults), codeptr, v, s.mem())
+ aux := ssa.ClosureAuxCall(ACArgs, ACResults)
+ if testLateExpansion {
+ callArgs = append(callArgs, s.mem())
+ call = s.newValue2A(ssa.OpClosureLECall, aux.LateExpansionResultType(), aux, codeptr, v)
+ call.AddArgs(callArgs...)
+ } else {
+ call = s.newValue3A(ssa.OpClosureCall, types.TypeMem, aux, codeptr, v, s.mem())
+ }
} else {
- // Do a static call if the original call was a static function or method
- call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(fn.Sym.Linksym(), ACArgs, ACResults), s.mem())
+ aux := ssa.StaticAuxCall(fn.Sym.Linksym(), ACArgs, ACResults)
+ if testLateExpansion {
+ callArgs = append(callArgs, s.mem())
+ call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
+ call.AddArgs(callArgs...)
+ } else {
+ // Do a static call if the original call was a static function or method
+ call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, aux, s.mem())
+ }
}
call.AuxInt = stksize
- s.vars[&memVar] = call
+ if testLateExpansion {
+ s.vars[&memVar] = s.newValue1I(ssa.OpSelectN, types.TypeMem, int64(len(ACResults)), call)
+ } else {
+ s.vars[&memVar] = call
+ }
// Make sure that the stack slots with pointers are kept live
// through the call (which is a pre-emption point). Also, we will
// use the first call of the last defer exit to compute liveness
@@ -4380,11 +4407,9 @@ func (s *state) call(n *Node, k callKind, returnResultAddr bool) *ssa.Value {
switch n.Op {
case OCALLFUNC:
+ testLateExpansion = k != callDeferStack && ssa.LateCallExpansionEnabledWithin(s.f)
if k == callNormal && fn.Op == ONAME && fn.Class() == PFUNC {
sym = fn.Sym
- if !returnResultAddr && strings.Contains(sym.Name, "testLateExpansion") {
- testLateExpansion = true
- }
break
}
closure = s.expr(fn)
@@ -4397,11 +4422,9 @@ func (s *state) call(n *Node, k callKind, returnResultAddr bool) *ssa.Value {
if fn.Op != ODOTMETH {
s.Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
}
+ testLateExpansion = k != callDeferStack && ssa.LateCallExpansionEnabledWithin(s.f)
if k == callNormal {
sym = fn.Sym
- if !returnResultAddr && strings.Contains(sym.Name, "testLateExpansion") {
- testLateExpansion = true
- }
break
}
closure = s.getMethodClosure(fn)
@@ -4411,6 +4434,7 @@ func (s *state) call(n *Node, k callKind, returnResultAddr bool) *ssa.Value {
if fn.Op != ODOTINTER {
s.Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", fn.Op)
}
+ testLateExpansion = k != callDeferStack && ssa.LateCallExpansionEnabledWithin(s.f)
var iclosure *ssa.Value
iclosure, rcvr = s.getClosureAndRcvr(fn)
if k == callNormal {
@@ -4429,6 +4453,7 @@ func (s *state) call(n *Node, k callKind, returnResultAddr bool) *ssa.Value {
var call *ssa.Value
if k == callDeferStack {
+ testLateExpansion = ssa.LateCallExpansionEnabledWithin(s.f)
// Make a defer struct d on the stack.
t := deferstruct(stksize)
d := tempAt(n.Pos, s.curfn, t)
@@ -4479,10 +4504,17 @@ func (s *state) call(n *Node, k callKind, returnResultAddr bool) *ssa.Value {
}
// Call runtime.deferprocStack with pointer to _defer record.
- arg0 := s.constOffPtrSP(types.Types[TUINTPTR], Ctxt.FixedFrameSize())
- s.store(types.Types[TUINTPTR], arg0, addr)
ACArgs = append(ACArgs, ssa.Param{Type: types.Types[TUINTPTR], Offset: int32(Ctxt.FixedFrameSize())})
- call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(deferprocStack, ACArgs, ACResults), s.mem())
+ aux := ssa.StaticAuxCall(deferprocStack, ACArgs, ACResults)
+ if testLateExpansion {
+ callArgs = append(callArgs, addr, s.mem())
+ call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
+ call.AddArgs(callArgs...)
+ } else {
+ arg0 := s.constOffPtrSP(types.Types[TUINTPTR], Ctxt.FixedFrameSize())
+ s.store(types.Types[TUINTPTR], arg0, addr)
+ call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, aux, s.mem())
+ }
if stksize < int64(Widthptr) {
// We need room for both the call to deferprocStack and the call to
// the deferred function.
@@ -4549,9 +4581,21 @@ func (s *state) call(n *Node, k callKind, returnResultAddr bool) *ssa.Value {
// call target
switch {
case k == callDefer:
- call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(deferproc, ACArgs, ACResults), s.mem())
+ aux := ssa.StaticAuxCall(deferproc, ACArgs, ACResults)
+ if testLateExpansion {
+ call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
+ call.AddArgs(callArgs...)
+ } else {
+ call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, aux, s.mem())
+ }
case k == callGo:
- call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(newproc, ACArgs, ACResults), s.mem())
+ aux := ssa.StaticAuxCall(newproc, ACArgs, ACResults)
+ if testLateExpansion {
+ call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
+ call.AddArgs(callArgs...)
+ } else {
+ call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, aux, s.mem())
+ }
case closure != nil:
// rawLoad because loading the code pointer from a
// closure is always safe, but IsSanitizerSafeAddr
@@ -4559,18 +4603,25 @@ func (s *state) call(n *Node, k callKind, returnResultAddr bool) *ssa.Value {
// critical that we not clobber any arguments already
// stored onto the stack.
codeptr = s.rawLoad(types.Types[TUINTPTR], closure)
- call = s.newValue3A(ssa.OpClosureCall, types.TypeMem, ssa.ClosureAuxCall(ACArgs, ACResults), codeptr, closure, s.mem())
+ if testLateExpansion {
+ aux := ssa.ClosureAuxCall(ACArgs, ACResults)
+ call = s.newValue2A(ssa.OpClosureLECall, aux.LateExpansionResultType(), aux, codeptr, closure)
+ call.AddArgs(callArgs...)
+ } else {
+ call = s.newValue3A(ssa.OpClosureCall, types.TypeMem, ssa.ClosureAuxCall(ACArgs, ACResults), codeptr, closure, s.mem())
+ }
case codeptr != nil:
- call = s.newValue2A(ssa.OpInterCall, types.TypeMem, ssa.InterfaceAuxCall(ACArgs, ACResults), codeptr, s.mem())
+ if testLateExpansion {
+ aux := ssa.InterfaceAuxCall(ACArgs, ACResults)
+ call = s.newValue1A(ssa.OpInterLECall, aux.LateExpansionResultType(), aux, codeptr)
+ call.AddArgs(callArgs...)
+ } else {
+ call = s.newValue2A(ssa.OpInterCall, types.TypeMem, ssa.InterfaceAuxCall(ACArgs, ACResults), codeptr, s.mem())
+ }
case sym != nil:
if testLateExpansion {
- var tys []*types.Type
aux := ssa.StaticAuxCall(sym.Linksym(), ACArgs, ACResults)
- for i := int64(0); i < aux.NResults(); i++ {
- tys = append(tys, aux.TypeOfResult(i))
- }
- tys = append(tys, types.TypeMem)
- call = s.newValue0A(ssa.OpStaticLECall, types.NewResults(tys), aux)
+ call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
call.AddArgs(callArgs...)
} else {
call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(sym.Linksym(), ACArgs, ACResults), s.mem())
@@ -4611,7 +4662,11 @@ func (s *state) call(n *Node, k callKind, returnResultAddr bool) *ssa.Value {
}
fp := res.Field(0)
if returnResultAddr {
- return s.constOffPtrSP(types.NewPtr(fp.Type), fp.Offset+Ctxt.FixedFrameSize())
+ pt := types.NewPtr(fp.Type)
+ if testLateExpansion {
+ return s.newValue1I(ssa.OpSelectNAddr, pt, 0, call)
+ }
+ return s.constOffPtrSP(pt, fp.Offset+Ctxt.FixedFrameSize())
}
if testLateExpansion {
@@ -4715,7 +4770,7 @@ func (s *state) addr(n *Node) *ssa.Value {
}
case ORESULT:
// load return from callee
- if s.prevCall == nil || s.prevCall.Op != ssa.OpStaticLECall {
+ if s.prevCall == nil || s.prevCall.Op != ssa.OpStaticLECall && s.prevCall.Op != ssa.OpInterLECall && s.prevCall.Op != ssa.OpClosureLECall {
return s.constOffPtrSP(t, n.Xoffset)
}
which := s.prevCall.Aux.(*ssa.AuxCall).ResultForOffset(n.Xoffset)
@@ -5018,15 +5073,22 @@ func (s *state) rtcall(fn *obj.LSym, returns bool, results []*types.Type, args .
s.prevCall = nil
// Write args to the stack
off := Ctxt.FixedFrameSize()
+ testLateExpansion := ssa.LateCallExpansionEnabledWithin(s.f)
var ACArgs []ssa.Param
var ACResults []ssa.Param
+ var callArgs []*ssa.Value
+
for _, arg := range args {
t := arg.Type
off = Rnd(off, t.Alignment())
- ptr := s.constOffPtrSP(t.PtrTo(), off)
size := t.Size()
ACArgs = append(ACArgs, ssa.Param{Type: t, Offset: int32(off)})
- s.store(t, ptr, arg)
+ if testLateExpansion {
+ callArgs = append(callArgs, arg)
+ } else {
+ ptr := s.constOffPtrSP(t.PtrTo(), off)
+ s.store(t, ptr, arg)
+ }
off += size
}
off = Rnd(off, int64(Widthreg))
@@ -5040,8 +5102,17 @@ func (s *state) rtcall(fn *obj.LSym, returns bool, results []*types.Type, args .
}
// Issue call
- call := s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(fn, ACArgs, ACResults), s.mem())
- s.vars[&memVar] = call
+ var call *ssa.Value
+ aux := ssa.StaticAuxCall(fn, ACArgs, ACResults)
+ if testLateExpansion {
+ callArgs = append(callArgs, s.mem())
+ call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
+ call.AddArgs(callArgs...)
+ s.vars[&memVar] = s.newValue1I(ssa.OpSelectN, types.TypeMem, int64(len(ACResults)), call)
+ } else {
+ call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, aux, s.mem())
+ s.vars[&memVar] = call
+ }
if !returns {
// Finish block
@@ -5057,11 +5128,24 @@ func (s *state) rtcall(fn *obj.LSym, returns bool, results []*types.Type, args .
// Load results
res := make([]*ssa.Value, len(results))
- for i, t := range results {
- off = Rnd(off, t.Alignment())
- ptr := s.constOffPtrSP(types.NewPtr(t), off)
- res[i] = s.load(t, ptr)
- off += t.Size()
+ if testLateExpansion {
+ for i, t := range results {
+ off = Rnd(off, t.Alignment())
+ if canSSAType(t) {
+ res[i] = s.newValue1I(ssa.OpSelectN, t, int64(i), call)
+ } else {
+ addr := s.newValue1I(ssa.OpSelectNAddr, types.NewPtr(t), int64(i), call)
+ res[i] = s.rawLoad(t, addr)
+ }
+ off += t.Size()
+ }
+ } else {
+ for i, t := range results {
+ off = Rnd(off, t.Alignment())
+ ptr := s.constOffPtrSP(types.NewPtr(t), off)
+ res[i] = s.load(t, ptr)
+ off += t.Size()
+ }
}
off = Rnd(off, int64(Widthptr))
@@ -5918,9 +6002,7 @@ type SSAGenState struct {
// bstart remembers where each block starts (indexed by block ID)
bstart []*obj.Prog
- // 387 port: maps from SSE registers (REG_X?) to 387 registers (REG_F?)
- SSEto387 map[int16]int16
- // Some architectures require a 64-bit temporary for FP-related register shuffling. Examples include x86-387, PPC, and Sparc V8.
+ // Some architectures require a 64-bit temporary for FP-related register shuffling. Examples include PPC and Sparc V8.
ScratchFpMem *Node
maxarg int64 // largest frame size for arguments to calls made by the function
@@ -6026,7 +6108,7 @@ func emitStackObjects(e *ssafn, pp *Progs) {
// Populate the stack object data.
// Format must match runtime/stack.go:stackObjectRecord.
- x := e.curfn.Func.lsym.Func.StackObjects
+ x := e.curfn.Func.lsym.Func().StackObjects
off := 0
off = duintptr(x, off, uint64(len(vars)))
for _, v := range vars {
@@ -6063,7 +6145,7 @@ func genssa(f *ssa.Func, pp *Progs) {
s.livenessMap = liveness(e, f, pp)
emitStackObjects(e, pp)
- openDeferInfo := e.curfn.Func.lsym.Func.OpenCodedDeferInfo
+ openDeferInfo := e.curfn.Func.lsym.Func().OpenCodedDeferInfo
if openDeferInfo != nil {
// This function uses open-coded defers -- write out the funcdata
// info that we computed at the end of genssa.
@@ -6087,10 +6169,6 @@ func genssa(f *ssa.Func, pp *Progs) {
progToBlock[s.pp.next] = f.Blocks[0]
}
- if thearch.Use387 {
- s.SSEto387 = map[int16]int16{}
- }
-
s.ScratchFpMem = e.scratchFpMem
if Ctxt.Flag_locationlists {
@@ -6272,7 +6350,7 @@ func genssa(f *ssa.Func, pp *Progs) {
// some of the inline marks.
// Use this instruction instead.
p.Pos = p.Pos.WithIsStmt() // promote position to a statement
- pp.curfn.Func.lsym.Func.AddInlMark(p, inlMarks[m])
+ pp.curfn.Func.lsym.Func().AddInlMark(p, inlMarks[m])
// Make the inline mark a real nop, so it doesn't generate any code.
m.As = obj.ANOP
m.Pos = src.NoXPos
@@ -6284,7 +6362,7 @@ func genssa(f *ssa.Func, pp *Progs) {
// Any unmatched inline marks now need to be added to the inlining tree (and will generate a nop instruction).
for _, p := range inlMarkList {
if p.As != obj.ANOP {
- pp.curfn.Func.lsym.Func.AddInlMark(p, inlMarks[p])
+ pp.curfn.Func.lsym.Func().AddInlMark(p, inlMarks[p])
}
}
}
diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go
index b5527e2f83..f4b0c0fae0 100644
--- a/src/cmd/compile/internal/gc/subr.go
+++ b/src/cmd/compile/internal/gc/subr.go
@@ -546,22 +546,19 @@ func methtype(t *types.Type) *types.Type {
// Is type src assignment compatible to type dst?
// If so, return op code to use in conversion.
-// If not, return OXXX.
-func assignop(src, dst *types.Type, why *string) Op {
- if why != nil {
- *why = ""
- }
-
+// If not, return OXXX. In this case, the string return parameter may
+// hold a reason why. In all other cases, it'll be the empty string.
+func assignop(src, dst *types.Type) (Op, string) {
if src == dst {
- return OCONVNOP
+ return OCONVNOP, ""
}
if src == nil || dst == nil || src.Etype == TFORW || dst.Etype == TFORW || src.Orig == nil || dst.Orig == nil {
- return OXXX
+ return OXXX, ""
}
// 1. src type is identical to dst.
if types.Identical(src, dst) {
- return OCONVNOP
+ return OCONVNOP, ""
}
// 2. src and dst have identical underlying types
@@ -575,13 +572,13 @@ func assignop(src, dst *types.Type, why *string) Op {
if src.IsEmptyInterface() {
// Conversion between two empty interfaces
// requires no code.
- return OCONVNOP
+ return OCONVNOP, ""
}
if (src.Sym == nil || dst.Sym == nil) && !src.IsInterface() {
// Conversion between two types, at least one unnamed,
// needs no conversion. The exception is nonempty interfaces
// which need to have their itab updated.
- return OCONVNOP
+ return OCONVNOP, ""
}
}
@@ -590,49 +587,47 @@ func assignop(src, dst *types.Type, why *string) Op {
var missing, have *types.Field
var ptr int
if implements(src, dst, &missing, &have, &ptr) {
- return OCONVIFACE
+ return OCONVIFACE, ""
}
// we'll have complained about this method anyway, suppress spurious messages.
if have != nil && have.Sym == missing.Sym && (have.Type.Broke() || missing.Type.Broke()) {
- return OCONVIFACE
+ return OCONVIFACE, ""
}
- if why != nil {
- if isptrto(src, TINTER) {
- *why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", src)
- } else if have != nil && have.Sym == missing.Sym && have.Nointerface() {
- *why = fmt.Sprintf(":\n\t%v does not implement %v (%v method is marked 'nointerface')", src, dst, missing.Sym)
- } else if have != nil && have.Sym == missing.Sym {
- *why = fmt.Sprintf(":\n\t%v does not implement %v (wrong type for %v method)\n"+
- "\t\thave %v%0S\n\t\twant %v%0S", src, dst, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
- } else if ptr != 0 {
- *why = fmt.Sprintf(":\n\t%v does not implement %v (%v method has pointer receiver)", src, dst, missing.Sym)
- } else if have != nil {
- *why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)\n"+
- "\t\thave %v%0S\n\t\twant %v%0S", src, dst, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
- } else {
- *why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)", src, dst, missing.Sym)
- }
+ var why string
+ if isptrto(src, TINTER) {
+ why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", src)
+ } else if have != nil && have.Sym == missing.Sym && have.Nointerface() {
+ why = fmt.Sprintf(":\n\t%v does not implement %v (%v method is marked 'nointerface')", src, dst, missing.Sym)
+ } else if have != nil && have.Sym == missing.Sym {
+ why = fmt.Sprintf(":\n\t%v does not implement %v (wrong type for %v method)\n"+
+ "\t\thave %v%0S\n\t\twant %v%0S", src, dst, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
+ } else if ptr != 0 {
+ why = fmt.Sprintf(":\n\t%v does not implement %v (%v method has pointer receiver)", src, dst, missing.Sym)
+ } else if have != nil {
+ why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)\n"+
+ "\t\thave %v%0S\n\t\twant %v%0S", src, dst, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
+ } else {
+ why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)", src, dst, missing.Sym)
}
- return OXXX
+ return OXXX, why
}
if isptrto(dst, TINTER) {
- if why != nil {
- *why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", dst)
- }
- return OXXX
+ why := fmt.Sprintf(":\n\t%v is pointer to interface, not interface", dst)
+ return OXXX, why
}
if src.IsInterface() && dst.Etype != TBLANK {
var missing, have *types.Field
var ptr int
- if why != nil && implements(dst, src, &missing, &have, &ptr) {
- *why = ": need type assertion"
+ var why string
+ if implements(dst, src, &missing, &have, &ptr) {
+ why = ": need type assertion"
}
- return OXXX
+ return OXXX, why
}
// 4. src is a bidirectional channel value, dst is a channel type,
@@ -640,7 +635,7 @@ func assignop(src, dst *types.Type, why *string) Op {
// either src or dst is not a named type.
if src.IsChan() && src.ChanDir() == types.Cboth && dst.IsChan() {
if types.Identical(src.Elem(), dst.Elem()) && (src.Sym == nil || dst.Sym == nil) {
- return OCONVNOP
+ return OCONVNOP, ""
}
}
@@ -653,7 +648,7 @@ func assignop(src, dst *types.Type, why *string) Op {
TCHAN,
TINTER,
TSLICE:
- return OCONVNOP
+ return OCONVNOP, ""
}
}
@@ -661,26 +656,23 @@ func assignop(src, dst *types.Type, why *string) Op {
// 7. Any typed value can be assigned to the blank identifier.
if dst.Etype == TBLANK {
- return OCONVNOP
+ return OCONVNOP, ""
}
- return OXXX
+ return OXXX, ""
}
// Can we convert a value of type src to a value of type dst?
// If so, return op code to use in conversion (maybe OCONVNOP).
-// If not, return OXXX.
+// If not, return OXXX. In this case, the string return parameter may
+// hold a reason why. In all other cases, it'll be the empty string.
// srcConstant indicates whether the value of type src is a constant.
-func convertop(srcConstant bool, src, dst *types.Type, why *string) Op {
- if why != nil {
- *why = ""
- }
-
+func convertop(srcConstant bool, src, dst *types.Type) (Op, string) {
if src == dst {
- return OCONVNOP
+ return OCONVNOP, ""
}
if src == nil || dst == nil {
- return OXXX
+ return OXXX, ""
}
// Conversions from regular to go:notinheap are not allowed
@@ -688,23 +680,19 @@ func convertop(srcConstant bool, src, dst *types.Type, why *string) Op {
// rules.
// (a) Disallow (*T) to (*U) where T is go:notinheap but U isn't.
if src.IsPtr() && dst.IsPtr() && dst.Elem().NotInHeap() && !src.Elem().NotInHeap() {
- if why != nil {
- *why = fmt.Sprintf(":\n\t%v is incomplete (or unallocatable), but %v is not", dst.Elem(), src.Elem())
- }
- return OXXX
+ why := fmt.Sprintf(":\n\t%v is incomplete (or unallocatable), but %v is not", dst.Elem(), src.Elem())
+ return OXXX, why
}
// (b) Disallow string to []T where T is go:notinheap.
if src.IsString() && dst.IsSlice() && dst.Elem().NotInHeap() && (dst.Elem().Etype == types.Bytetype.Etype || dst.Elem().Etype == types.Runetype.Etype) {
- if why != nil {
- *why = fmt.Sprintf(":\n\t%v is incomplete (or unallocatable)", dst.Elem())
- }
- return OXXX
+ why := fmt.Sprintf(":\n\t%v is incomplete (or unallocatable)", dst.Elem())
+ return OXXX, why
}
// 1. src can be assigned to dst.
- op := assignop(src, dst, why)
+ op, why := assignop(src, dst)
if op != OXXX {
- return op
+ return op, why
}
// The rules for interfaces are no different in conversions
@@ -712,60 +700,57 @@ func convertop(srcConstant bool, src, dst *types.Type, why *string) Op {
// with the good message from assignop.
// Otherwise clear the error.
if src.IsInterface() || dst.IsInterface() {
- return OXXX
- }
- if why != nil {
- *why = ""
+ return OXXX, why
}
// 2. Ignoring struct tags, src and dst have identical underlying types.
if types.IdenticalIgnoreTags(src.Orig, dst.Orig) {
- return OCONVNOP
+ return OCONVNOP, ""
}
// 3. src and dst are unnamed pointer types and, ignoring struct tags,
// their base types have identical underlying types.
if src.IsPtr() && dst.IsPtr() && src.Sym == nil && dst.Sym == nil {
if types.IdenticalIgnoreTags(src.Elem().Orig, dst.Elem().Orig) {
- return OCONVNOP
+ return OCONVNOP, ""
}
}
// 4. src and dst are both integer or floating point types.
if (src.IsInteger() || src.IsFloat()) && (dst.IsInteger() || dst.IsFloat()) {
if simtype[src.Etype] == simtype[dst.Etype] {
- return OCONVNOP
+ return OCONVNOP, ""
}
- return OCONV
+ return OCONV, ""
}
// 5. src and dst are both complex types.
if src.IsComplex() && dst.IsComplex() {
if simtype[src.Etype] == simtype[dst.Etype] {
- return OCONVNOP
+ return OCONVNOP, ""
}
- return OCONV
+ return OCONV, ""
}
// Special case for constant conversions: any numeric
// conversion is potentially okay. We'll validate further
// within evconst. See #38117.
if srcConstant && (src.IsInteger() || src.IsFloat() || src.IsComplex()) && (dst.IsInteger() || dst.IsFloat() || dst.IsComplex()) {
- return OCONV
+ return OCONV, ""
}
// 6. src is an integer or has type []byte or []rune
// and dst is a string type.
if src.IsInteger() && dst.IsString() {
- return ORUNESTR
+ return ORUNESTR, ""
}
if src.IsSlice() && dst.IsString() {
if src.Elem().Etype == types.Bytetype.Etype {
- return OBYTES2STR
+ return OBYTES2STR, ""
}
if src.Elem().Etype == types.Runetype.Etype {
- return ORUNES2STR
+ return ORUNES2STR, ""
}
}
@@ -773,21 +758,21 @@ func convertop(srcConstant bool, src, dst *types.Type, why *string) Op {
// String to slice.
if src.IsString() && dst.IsSlice() {
if dst.Elem().Etype == types.Bytetype.Etype {
- return OSTR2BYTES
+ return OSTR2BYTES, ""
}
if dst.Elem().Etype == types.Runetype.Etype {
- return OSTR2RUNES
+ return OSTR2RUNES, ""
}
}
// 8. src is a pointer or uintptr and dst is unsafe.Pointer.
if (src.IsPtr() || src.IsUintptr()) && dst.IsUnsafePtr() {
- return OCONVNOP
+ return OCONVNOP, ""
}
// 9. src is unsafe.Pointer and dst is a pointer or uintptr.
if src.IsUnsafePtr() && (dst.IsPtr() || dst.IsUintptr()) {
- return OCONVNOP
+ return OCONVNOP, ""
}
// src is map and dst is a pointer to corresponding hmap.
@@ -795,10 +780,10 @@ func convertop(srcConstant bool, src, dst *types.Type, why *string) Op {
// go gc maps are implemented as a pointer to a hmap struct.
if src.Etype == TMAP && dst.IsPtr() &&
src.MapType().Hmap == dst.Elem() {
- return OCONVNOP
+ return OCONVNOP, ""
}
- return OXXX
+ return OXXX, ""
}
func assignconv(n *Node, t *types.Type, context string) *Node {
@@ -825,7 +810,7 @@ func assignconvfn(n *Node, t *types.Type, context func() string) *Node {
// Convert ideal bool from comparison to plain bool
// if the next step is non-bool (like interface{}).
- if n.Type == types.Idealbool && !t.IsBoolean() {
+ if n.Type == types.UntypedBool && !t.IsBoolean() {
if n.Op == ONAME || n.Op == OLITERAL {
r := nod(OCONVNOP, n, nil)
r.Type = types.Types[TBOOL]
@@ -839,8 +824,7 @@ func assignconvfn(n *Node, t *types.Type, context func() string) *Node {
return n
}
- var why string
- op := assignop(n.Type, t, &why)
+ op, why := assignop(n.Type, t)
if op == OXXX {
yyerror("cannot use %L as type %v in %s%s", n, t, context(), why)
op = OCONV
@@ -1040,25 +1024,24 @@ func calcHasCall(n *Node) bool {
return false
}
-func badtype(op Op, tl *types.Type, tr *types.Type) {
- fmt_ := ""
+func badtype(op Op, tl, tr *types.Type) {
+ var s string
if tl != nil {
- fmt_ += fmt.Sprintf("\n\t%v", tl)
+ s += fmt.Sprintf("\n\t%v", tl)
}
if tr != nil {
- fmt_ += fmt.Sprintf("\n\t%v", tr)
+ s += fmt.Sprintf("\n\t%v", tr)
}
// common mistake: *struct and *interface.
if tl != nil && tr != nil && tl.IsPtr() && tr.IsPtr() {
if tl.Elem().IsStruct() && tr.Elem().IsInterface() {
- fmt_ += "\n\t(*struct vs *interface)"
+ s += "\n\t(*struct vs *interface)"
} else if tl.Elem().IsInterface() && tr.Elem().IsStruct() {
- fmt_ += "\n\t(*interface vs *struct)"
+ s += "\n\t(*interface vs *struct)"
}
}
- s := fmt_
yyerror("illegal types for operand: %v%s", op, s)
}
@@ -1921,3 +1904,13 @@ func ifaceData(pos src.XPos, n *Node, t *types.Type) *Node {
ind.SetBounded(true)
return ind
}
+
+// typePos returns the position associated with t.
+// This is where t was declared or where it appeared as a type expression.
+func typePos(t *types.Type) src.XPos {
+ n := asNode(t.Nod)
+ if n == nil || !n.Pos.IsKnown() {
+ Fatalf("bad type: %v", t)
+ }
+ return n.Pos
+}
diff --git a/src/cmd/compile/internal/gc/swt.go b/src/cmd/compile/internal/gc/swt.go
index 138b0acc53..8d9fbe300e 100644
--- a/src/cmd/compile/internal/gc/swt.go
+++ b/src/cmd/compile/internal/gc/swt.go
@@ -189,16 +189,19 @@ func typecheckExprSwitch(n *Node) {
continue
}
- switch {
- case nilonly != "" && !n1.isNil():
+ if nilonly != "" && !n1.isNil() {
yyerrorl(ncase.Pos, "invalid case %v in switch (can only compare %s %v to nil)", n1, nilonly, n.Left)
- case t.IsInterface() && !n1.Type.IsInterface() && !IsComparable(n1.Type):
+ } else if t.IsInterface() && !n1.Type.IsInterface() && !IsComparable(n1.Type) {
yyerrorl(ncase.Pos, "invalid case %L in switch (incomparable type)", n1)
- case assignop(n1.Type, t, nil) == 0 && assignop(t, n1.Type, nil) == 0:
- if n.Left != nil {
- yyerrorl(ncase.Pos, "invalid case %v in switch on %v (mismatched types %v and %v)", n1, n.Left, n1.Type, t)
- } else {
- yyerrorl(ncase.Pos, "invalid case %v in switch (mismatched types %v and bool)", n1, n1.Type)
+ } else {
+ op1, _ := assignop(n1.Type, t)
+ op2, _ := assignop(t, n1.Type)
+ if op1 == OXXX && op2 == OXXX {
+ if n.Left != nil {
+ yyerrorl(ncase.Pos, "invalid case %v in switch on %v (mismatched types %v and %v)", n1, n.Left, n1.Type, t)
+ } else {
+ yyerrorl(ncase.Pos, "invalid case %v in switch (mismatched types %v and bool)", n1, n1.Type)
+ }
}
}
@@ -358,8 +361,8 @@ func (s *exprSwitch) flush() {
// all we need here is consistency. We respect this
// sorting below.
sort.Slice(cc, func(i, j int) bool {
- si := strlit(cc[i].lo)
- sj := strlit(cc[j].lo)
+ si := cc[i].lo.StringVal()
+ sj := cc[j].lo.StringVal()
if len(si) != len(sj) {
return len(si) < len(sj)
}
@@ -368,7 +371,7 @@ func (s *exprSwitch) flush() {
// runLen returns the string length associated with a
// particular run of exprClauses.
- runLen := func(run []exprClause) int64 { return int64(len(strlit(run[0].lo))) }
+ runLen := func(run []exprClause) int64 { return int64(len(run[0].lo.StringVal())) }
// Collapse runs of consecutive strings with the same length.
var runs [][]exprClause
@@ -405,7 +408,7 @@ func (s *exprSwitch) flush() {
merged := cc[:1]
for _, c := range cc[1:] {
last := &merged[len(merged)-1]
- if last.jmp == c.jmp && last.hi.Int64()+1 == c.lo.Int64() {
+ if last.jmp == c.jmp && last.hi.Int64Val()+1 == c.lo.Int64Val() {
last.hi = c.lo
} else {
merged = append(merged, c)
@@ -440,7 +443,7 @@ func (c *exprClause) test(exprname *Node) *Node {
// Optimize "switch true { ...}" and "switch false { ... }".
if Isconst(exprname, CTBOOL) && !c.lo.Type.IsInterface() {
- if exprname.Val().U.(bool) {
+ if exprname.BoolVal() {
return c.lo
} else {
return nodl(c.pos, ONOT, c.lo, nil)
diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go
index 8e87fc9df0..a4b462da1d 100644
--- a/src/cmd/compile/internal/gc/typecheck.go
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -361,7 +361,7 @@ func typecheck1(n *Node, top int) (res *Node) {
ok |= ctxExpr
if n.Type == nil && n.Val().Ctype() == CTSTR {
- n.Type = types.Idealstring
+ n.Type = types.UntypedString
}
case ONONAME:
@@ -623,8 +623,8 @@ func typecheck1(n *Node, top int) (res *Node) {
// no defaultlit for left
// the outer context gives the type
n.Type = l.Type
- if (l.Type == types.Idealfloat || l.Type == types.Idealcomplex) && r.Op == OLITERAL {
- n.Type = types.Idealint
+ if (l.Type == types.UntypedFloat || l.Type == types.UntypedComplex) && r.Op == OLITERAL {
+ n.Type = types.UntypedInt
}
break
@@ -674,8 +674,8 @@ func typecheck1(n *Node, top int) (res *Node) {
// The conversion allocates, so only do it if the concrete type is huge.
converted := false
if r.Type.Etype != TBLANK {
- aop = assignop(l.Type, r.Type, nil)
- if aop != 0 {
+ aop, _ = assignop(l.Type, r.Type)
+ if aop != OXXX {
if r.Type.IsInterface() && !l.Type.IsInterface() && !IsComparable(l.Type) {
yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(l.Type))
n.Type = nil
@@ -696,8 +696,8 @@ func typecheck1(n *Node, top int) (res *Node) {
}
if !converted && l.Type.Etype != TBLANK {
- aop = assignop(r.Type, l.Type, nil)
- if aop != 0 {
+ aop, _ = assignop(r.Type, l.Type)
+ if aop != OXXX {
if l.Type.IsInterface() && !r.Type.IsInterface() && !IsComparable(r.Type) {
yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(r.Type))
n.Type = nil
@@ -777,7 +777,7 @@ func typecheck1(n *Node, top int) (res *Node) {
if iscmp[n.Op] {
evconst(n)
- t = types.Idealbool
+ t = types.UntypedBool
if n.Op != OLITERAL {
l, r = defaultlit2(l, r, true)
n.Left = l
@@ -1046,13 +1046,13 @@ func typecheck1(n *Node, top int) (res *Node) {
}
if !n.Bounded() && Isconst(n.Right, CTINT) {
- x := n.Right.Int64()
+ x := n.Right.Int64Val()
if x < 0 {
yyerror("invalid %s index %v (index must be non-negative)", why, n.Right)
} else if t.IsArray() && x >= t.NumElem() {
yyerror("invalid array index %v (out of bounds for %d-element array)", n.Right, t.NumElem())
- } else if Isconst(n.Left, CTSTR) && x >= int64(len(strlit(n.Left))) {
- yyerror("invalid string index %v (out of bounds for %d-byte string)", n.Right, len(strlit(n.Left)))
+ } else if Isconst(n.Left, CTSTR) && x >= int64(len(n.Left.StringVal())) {
+ yyerror("invalid string index %v (out of bounds for %d-byte string)", n.Right, len(n.Left.StringVal()))
} else if n.Right.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 {
yyerror("invalid %s index %v (index too large)", why, n.Right)
}
@@ -1148,11 +1148,11 @@ func typecheck1(n *Node, top int) (res *Node) {
l = defaultlit(l, types.Types[TINT])
c = defaultlit(c, types.Types[TINT])
- if Isconst(l, CTINT) && l.Int64() < 0 {
+ if Isconst(l, CTINT) && l.Int64Val() < 0 {
Fatalf("len for OSLICEHEADER must be non-negative")
}
- if Isconst(c, CTINT) && c.Int64() < 0 {
+ if Isconst(c, CTINT) && c.Int64Val() < 0 {
Fatalf("cap for OSLICEHEADER must be non-negative")
}
@@ -1201,7 +1201,7 @@ func typecheck1(n *Node, top int) (res *Node) {
if n.Left.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 {
Fatalf("len for OMAKESLICECOPY too large")
}
- if n.Left.Int64() < 0 {
+ if n.Left.Int64Val() < 0 {
Fatalf("len for OMAKESLICECOPY must be non-negative")
}
}
@@ -1458,7 +1458,7 @@ func typecheck1(n *Node, top int) (res *Node) {
// Determine result type.
switch t.Etype {
case TIDEAL:
- n.Type = types.Idealfloat
+ n.Type = types.UntypedFloat
case TCOMPLEX64:
n.Type = types.Types[TFLOAT32]
case TCOMPLEX128:
@@ -1504,7 +1504,7 @@ func typecheck1(n *Node, top int) (res *Node) {
return n
case TIDEAL:
- t = types.Idealcomplex
+ t = types.UntypedComplex
case TFLOAT32:
t = types.Types[TCOMPLEX64]
@@ -1691,7 +1691,7 @@ func typecheck1(n *Node, top int) (res *Node) {
return n
}
var why string
- n.Op = convertop(n.Left.Op == OLITERAL, t, n.Type, &why)
+ n.Op, why = convertop(n.Left.Op == OLITERAL, t, n.Type)
if n.Op == OXXX {
if !n.Diag() && !n.Type.Broke() && !n.Left.Diag() {
yyerror("cannot convert %L to type %v%s", n.Left, n.Type, why)
@@ -1770,7 +1770,7 @@ func typecheck1(n *Node, top int) (res *Node) {
n.Type = nil
return n
}
- if !checkmake(t, "len", l) || r != nil && !checkmake(t, "cap", r) {
+ if !checkmake(t, "len", &l) || r != nil && !checkmake(t, "cap", &r) {
n.Type = nil
return n
}
@@ -1794,7 +1794,7 @@ func typecheck1(n *Node, top int) (res *Node) {
n.Type = nil
return n
}
- if !checkmake(t, "size", l) {
+ if !checkmake(t, "size", &l) {
n.Type = nil
return n
}
@@ -1815,7 +1815,7 @@ func typecheck1(n *Node, top int) (res *Node) {
n.Type = nil
return n
}
- if !checkmake(t, "buffer", l) {
+ if !checkmake(t, "buffer", &l) {
n.Type = nil
return n
}
@@ -2187,14 +2187,14 @@ func checksliceindex(l *Node, r *Node, tp *types.Type) bool {
}
if r.Op == OLITERAL {
- if r.Int64() < 0 {
+ if r.Int64Val() < 0 {
yyerror("invalid slice index %v (index must be non-negative)", r)
return false
- } else if tp != nil && tp.NumElem() >= 0 && r.Int64() > tp.NumElem() {
+ } else if tp != nil && tp.NumElem() >= 0 && r.Int64Val() > tp.NumElem() {
yyerror("invalid slice index %v (out of bounds for %d-element array)", r, tp.NumElem())
return false
- } else if Isconst(l, CTSTR) && r.Int64() > int64(len(strlit(l))) {
- yyerror("invalid slice index %v (out of bounds for %d-byte string)", r, len(strlit(l)))
+ } else if Isconst(l, CTSTR) && r.Int64Val() > int64(len(l.StringVal())) {
+ yyerror("invalid slice index %v (out of bounds for %d-byte string)", r, len(l.StringVal()))
return false
} else if r.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 {
yyerror("invalid slice index %v (index too large)", r)
@@ -2724,9 +2724,9 @@ func errorDetails(nl Nodes, tstruct *types.Type, isddd bool) string {
// e.g in error messages about wrong arguments to return.
func sigrepr(t *types.Type, isddd bool) string {
switch t {
- case types.Idealstring:
+ case types.UntypedString:
return "string"
- case types.Idealbool:
+ case types.UntypedBool:
return "bool"
}
@@ -3267,9 +3267,7 @@ func typecheckas(n *Node) {
}
func checkassignto(src *types.Type, dst *Node) {
- var why string
-
- if assignop(src, dst.Type, &why) == 0 {
+ if op, why := assignop(src, dst.Type); op == OXXX {
yyerror("cannot assign %v to %L in multiple assignment%s", src, dst, why)
return
}
@@ -3450,9 +3448,8 @@ func stringtoruneslit(n *Node) *Node {
}
var l []*Node
- s := strlit(n.Left)
i := 0
- for _, r := range s {
+ for _, r := range n.Left.StringVal() {
l = append(l, nod(OKEY, nodintconst(int64(i)), nodintconst(int64(r))))
i++
}
@@ -3729,7 +3726,8 @@ ret:
n.SetWalkdef(1)
}
-func checkmake(t *types.Type, arg string, n *Node) bool {
+func checkmake(t *types.Type, arg string, np **Node) bool {
+ n := *np
if !n.Type.IsInteger() && n.Type.Etype != TIDEAL {
yyerror("non-integer %s argument in make(%v) - %v", arg, t, n.Type)
return false
@@ -3739,12 +3737,12 @@ func checkmake(t *types.Type, arg string, n *Node) bool {
// to avoid redundant "constant NNN overflows int" errors.
switch consttype(n) {
case CTINT, CTRUNE, CTFLT, CTCPLX:
- n.SetVal(toint(n.Val()))
- if n.Val().U.(*Mpint).CmpInt64(0) < 0 {
+ v := toint(n.Val()).U.(*Mpint)
+ if v.CmpInt64(0) < 0 {
yyerror("negative %s argument in make(%v)", arg, t)
return false
}
- if n.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 {
+ if v.Cmp(maxintval[TINT]) > 0 {
yyerror("%s argument too large in make(%v)", arg, t)
return false
}
@@ -3756,6 +3754,7 @@ func checkmake(t *types.Type, arg string, n *Node) bool {
// for instance, indexlit might be called here and incorporate some
// of the bounds checks done for make.
n = defaultlit(n, types.Types[TINT])
+ *np = n
return true
}
@@ -3902,7 +3901,7 @@ func deadcodefn(fn *Node) {
return
}
case OFOR:
- if !Isconst(n.Left, CTBOOL) || n.Left.Bool() {
+ if !Isconst(n.Left, CTBOOL) || n.Left.BoolVal() {
return
}
default:
@@ -3932,7 +3931,7 @@ func deadcodeslice(nn Nodes) {
n.Left = deadcodeexpr(n.Left)
if Isconst(n.Left, CTBOOL) {
var body Nodes
- if n.Left.Bool() {
+ if n.Left.BoolVal() {
n.Rlist = Nodes{}
body = n.Nbody
} else {
@@ -3975,7 +3974,7 @@ func deadcodeexpr(n *Node) *Node {
n.Left = deadcodeexpr(n.Left)
n.Right = deadcodeexpr(n.Right)
if Isconst(n.Left, CTBOOL) {
- if n.Left.Bool() {
+ if n.Left.BoolVal() {
return n.Right // true && x => x
} else {
return n.Left // false && x => false
@@ -3985,7 +3984,7 @@ func deadcodeexpr(n *Node) *Node {
n.Left = deadcodeexpr(n.Left)
n.Right = deadcodeexpr(n.Right)
if Isconst(n.Left, CTBOOL) {
- if n.Left.Bool() {
+ if n.Left.BoolVal() {
return n.Left // true || x => true
} else {
return n.Right // false || x => x
diff --git a/src/cmd/compile/internal/gc/universe.go b/src/cmd/compile/internal/gc/universe.go
index 04861c8dd4..ff8cabd8e3 100644
--- a/src/cmd/compile/internal/gc/universe.go
+++ b/src/cmd/compile/internal/gc/universe.go
@@ -123,21 +123,21 @@ func lexinit() {
asNode(s2.Def).SetSubOp(s.op)
}
- types.Idealstring = types.New(TSTRING)
- types.Idealbool = types.New(TBOOL)
+ types.UntypedString = types.New(TSTRING)
+ types.UntypedBool = types.New(TBOOL)
types.Types[TANY] = types.New(TANY)
s := builtinpkg.Lookup("true")
s.Def = asTypesNode(nodbool(true))
asNode(s.Def).Sym = lookup("true")
asNode(s.Def).Name = new(Name)
- asNode(s.Def).Type = types.Idealbool
+ asNode(s.Def).Type = types.UntypedBool
s = builtinpkg.Lookup("false")
s.Def = asTypesNode(nodbool(false))
asNode(s.Def).Sym = lookup("false")
asNode(s.Def).Name = new(Name)
- asNode(s.Def).Type = types.Idealbool
+ asNode(s.Def).Type = types.UntypedBool
s = lookup("_")
s.Block = -100
@@ -351,7 +351,7 @@ func typeinit() {
sizeofString = Rnd(sliceLenOffset+int64(Widthptr), int64(Widthptr))
dowidth(types.Types[TSTRING])
- dowidth(types.Idealstring)
+ dowidth(types.UntypedString)
}
func makeErrorInterface() *types.Type {
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index 933f16d9a0..9df288ea65 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -336,19 +336,6 @@ func walkstmt(n *Node) *Node {
return n
}
-func isSmallMakeSlice(n *Node) bool {
- if n.Op != OMAKESLICE {
- return false
- }
- r := n.Right
- if r == nil {
- r = n.Left
- }
- t := n.Type
-
- return smallintconst(r) && (t.Elem().Width == 0 || r.Int64() < maxImplicitStackVarSize/t.Elem().Width)
-}
-
// walk the whole tree of the body of an
// expression or simple statement.
// the types expressions are calculated.
@@ -565,6 +552,7 @@ opswitch:
case OCALLINTER, OCALLFUNC, OCALLMETH:
if n.Op == OCALLINTER {
usemethod(n)
+ markUsedIfaceMethod(n)
}
if n.Op == OCALLFUNC && n.Left.Op == OCLOSURE {
@@ -805,8 +793,8 @@ opswitch:
fromType := n.Left.Type
toType := n.Type
- if !fromType.IsInterface() {
- markTypeUsedInInterface(fromType)
+ if !fromType.IsInterface() && !Curfn.Func.Nname.isBlank() { // skip unnamed functions (func _())
+ markTypeUsedInInterface(fromType, Curfn.Func.lsym)
}
// typeword generates the type word of the interface value.
@@ -1013,7 +1001,7 @@ opswitch:
// The SSA backend will handle those.
switch et {
case TINT64:
- c := n.Right.Int64()
+ c := n.Right.Int64Val()
if c < 0 {
c = -c
}
@@ -1021,7 +1009,7 @@ opswitch:
break opswitch
}
case TUINT64:
- c := uint64(n.Right.Int64())
+ c := uint64(n.Right.Int64Val())
if c != 0 && c&(c-1) == 0 {
break opswitch
}
@@ -1068,7 +1056,7 @@ opswitch:
yyerror("index out of bounds")
}
} else if Isconst(n.Left, CTSTR) {
- n.SetBounded(bounded(r, int64(len(strlit(n.Left)))))
+ n.SetBounded(bounded(r, int64(len(n.Left.StringVal()))))
if Debug['m'] != 0 && n.Bounded() && !Isconst(n.Right, CTINT) {
Warn("index bounds check elided")
}
@@ -1338,8 +1326,8 @@ opswitch:
yyerror("%v can't be allocated in Go; it is incomplete (or unallocatable)", t.Elem())
}
if n.Esc == EscNone {
- if !isSmallMakeSlice(n) {
- Fatalf("non-small OMAKESLICE with EscNone: %v", n)
+ if why := heapAllocReason(n); why != "" {
+ Fatalf("%v has EscNone, but %v", n, why)
}
// var arr [r]T
// n = arr[:l]
@@ -1503,7 +1491,7 @@ opswitch:
case OSTR2BYTES:
s := n.Left
if Isconst(s, CTSTR) {
- sc := strlit(s)
+ sc := s.StringVal()
// Allocate a [n]byte of the right size.
t := types.NewArray(types.Types[TUINT8], int64(len(sc)))
@@ -1621,8 +1609,27 @@ opswitch:
// markTypeUsedInInterface marks that type t is converted to an interface.
// This information is used in the linker in dead method elimination.
-func markTypeUsedInInterface(t *types.Type) {
- typenamesym(t).Linksym().Set(obj.AttrUsedInIface, true)
+func markTypeUsedInInterface(t *types.Type, from *obj.LSym) {
+ tsym := typenamesym(t).Linksym()
+ // Emit a marker relocation. The linker will know the type is converted
+ // to an interface if "from" is reachable.
+ r := obj.Addrel(from)
+ r.Sym = tsym
+ r.Type = objabi.R_USEIFACE
+}
+
+// markUsedIfaceMethod marks that an interface method is used in the current
+// function. n is OCALLINTER node.
+func markUsedIfaceMethod(n *Node) {
+ ityp := n.Left.Left.Type
+ tsym := typenamesym(ityp).Linksym()
+ r := obj.Addrel(Curfn.Func.lsym)
+ r.Sym = tsym
+ // n.Left.Xoffset is the method index * Widthptr (the offset of code pointer
+ // in itab).
+ midx := n.Left.Xoffset / int64(Widthptr)
+ r.Add = ifaceMethodOffset(ityp, midx)
+ r.Type = objabi.R_USEIFACEMETHOD
}
// rtconvfn returns the parameter and result types that will be used by a
@@ -1912,7 +1919,7 @@ func walkprint(nn *Node, init *Nodes) *Node {
for i := 0; i < len(s); {
var strs []string
for i < len(s) && Isconst(s[i], CTSTR) {
- strs = append(strs, strlit(s[i]))
+ strs = append(strs, s[i].StringVal())
i++
}
if len(strs) > 0 {
@@ -1981,7 +1988,7 @@ func walkprint(nn *Node, init *Nodes) *Node {
case TSTRING:
cs := ""
if Isconst(n, CTSTR) {
- cs = strlit(n)
+ cs = n.StringVal()
}
switch cs {
case " ":
@@ -2150,7 +2157,7 @@ func reorder3(all []*Node) []*Node {
// The result of reorder3save MUST be assigned back to n, e.g.
// n.Left = reorder3save(n.Left, all, i, early)
func reorder3save(n *Node, all []*Node, i int, early *[]*Node) *Node {
- if !aliased(n, all, i) {
+ if !aliased(n, all[:i]) {
return n
}
@@ -2182,73 +2189,75 @@ func outervalue(n *Node) *Node {
}
}
-// Is it possible that the computation of n might be
-// affected by writes in as up to but not including the ith element?
-func aliased(n *Node, all []*Node, i int) bool {
- if n == nil {
+// Is it possible that the computation of r might be
+// affected by assignments in all?
+func aliased(r *Node, all []*Node) bool {
+ if r == nil {
return false
}
// Treat all fields of a struct as referring to the whole struct.
// We could do better but we would have to keep track of the fields.
- for n.Op == ODOT {
- n = n.Left
+ for r.Op == ODOT {
+ r = r.Left
}
// Look for obvious aliasing: a variable being assigned
// during the all list and appearing in n.
- // Also record whether there are any writes to main memory.
- // Also record whether there are any writes to variables
- // whose addresses have been taken.
+ // Also record whether there are any writes to addressable
+ // memory (either main memory or variables whose addresses
+ // have been taken).
memwrite := false
- varwrite := false
- for _, an := range all[:i] {
- a := outervalue(an.Left)
-
- for a.Op == ODOT {
- a = a.Left
+ for _, as := range all {
+ // We can ignore assignments to blank.
+ if as.Left.isBlank() {
+ continue
}
- if a.Op != ONAME {
+ l := outervalue(as.Left)
+ if l.Op != ONAME {
memwrite = true
continue
}
- switch n.Class() {
+ switch l.Class() {
default:
- varwrite = true
+ Fatalf("unexpected class: %v, %v", l, l.Class())
+
+ case PAUTOHEAP, PEXTERN:
+ memwrite = true
continue
case PAUTO, PPARAM, PPARAMOUT:
- if n.Name.Addrtaken() {
- varwrite = true
+ if l.Name.Addrtaken() {
+ memwrite = true
continue
}
- if vmatch2(a, n) {
- // Direct hit.
+ if vmatch2(l, r) {
+ // Direct hit: l appears in r.
return true
}
}
}
- // The variables being written do not appear in n.
- // However, n might refer to computed addresses
+ // The variables being written do not appear in r.
+ // However, r might refer to computed addresses
// that are being written.
// If no computed addresses are affected by the writes, no aliasing.
- if !memwrite && !varwrite {
+ if !memwrite {
return false
}
- // If n does not refer to computed addresses
- // (that is, if n only refers to variables whose addresses
+ // If r does not refer to computed addresses
+ // (that is, if r only refers to variables whose addresses
// have not been taken), no aliasing.
- if varexpr(n) {
+ if varexpr(r) {
return false
}
- // Otherwise, both the writes and n refer to computed memory addresses.
+ // Otherwise, both the writes and r refer to computed memory addresses.
// Assume that they might conflict.
return true
}
@@ -2636,7 +2645,7 @@ func addstr(n *Node, init *Nodes) *Node {
sz := int64(0)
for _, n1 := range n.List.Slice() {
if n1.Op == OLITERAL {
- sz += int64(len(strlit(n1)))
+ sz += int64(len(n1.StringVal()))
}
}
@@ -3430,7 +3439,7 @@ func walkcompare(n *Node, init *Nodes) *Node {
func tracecmpArg(n *Node, t *types.Type, init *Nodes) *Node {
// Ugly hack to avoid "constant -1 overflows uintptr" errors, etc.
- if n.Op == OLITERAL && n.Type.IsSigned() && n.Int64() < 0 {
+ if n.Op == OLITERAL && n.Type.IsSigned() && n.Int64Val() < 0 {
n = copyexpr(n, n.Type, init)
}
@@ -3500,7 +3509,7 @@ func walkcompareString(n *Node, init *Nodes) *Node {
// Length-only checks are ok, though.
maxRewriteLen = 0
}
- if s := strlit(cs); len(s) <= maxRewriteLen {
+ if s := cs.StringVal(); len(s) <= maxRewriteLen {
if len(s) > 0 {
ncs = safeexpr(ncs, init)
}
@@ -3595,7 +3604,7 @@ func bounded(n *Node, max int64) bool {
bits := int32(8 * n.Type.Width)
if smallintconst(n) {
- v := n.Int64()
+ v := n.Int64Val()
return 0 <= v && v < max
}
@@ -3603,9 +3612,9 @@ func bounded(n *Node, max int64) bool {
case OAND:
v := int64(-1)
if smallintconst(n.Left) {
- v = n.Left.Int64()
+ v = n.Left.Int64Val()
} else if smallintconst(n.Right) {
- v = n.Right.Int64()
+ v = n.Right.Int64Val()
}
if 0 <= v && v < max {
@@ -3614,7 +3623,7 @@ func bounded(n *Node, max int64) bool {
case OMOD:
if !sign && smallintconst(n.Right) {
- v := n.Right.Int64()
+ v := n.Right.Int64Val()
if 0 <= v && v <= max {
return true
}
@@ -3622,7 +3631,7 @@ func bounded(n *Node, max int64) bool {
case ODIV:
if !sign && smallintconst(n.Right) {
- v := n.Right.Int64()
+ v := n.Right.Int64Val()
for bits > 0 && v >= 2 {
bits--
v >>= 1
@@ -3631,7 +3640,7 @@ func bounded(n *Node, max int64) bool {
case ORSH:
if !sign && smallintconst(n.Right) {
- v := n.Right.Int64()
+ v := n.Right.Int64Val()
if v > int64(bits) {
return true
}
@@ -3687,6 +3696,8 @@ func usemethod(n *Node) {
// Also need to check for reflect package itself (see Issue #38515).
if s := res0.Type.Sym; s != nil && s.Name == "Method" && isReflectPkg(s.Pkg) {
Curfn.Func.SetReflectMethod(true)
+ // The LSym is initialized at this point. We need to set the attribute on the LSym.
+ Curfn.Func.lsym.Set(obj.AttrReflectMethod, true)
}
}
@@ -3870,6 +3881,16 @@ func wrapCall(n *Node, init *Nodes) *Node {
}
isBuiltinCall := n.Op != OCALLFUNC && n.Op != OCALLMETH && n.Op != OCALLINTER
+
+ // Turn f(a, b, []T{c, d, e}...) back into f(a, b, c, d, e).
+ if !isBuiltinCall && n.IsDDD() {
+ last := n.List.Len() - 1
+ if va := n.List.Index(last); va.Op == OSLICELIT {
+ n.List.Set(append(n.List.Slice()[:last], va.List.Slice()...))
+ n.SetIsDDD(false)
+ }
+ }
+
// origArgs keeps track of what argument is uintptr-unsafe/unsafe-uintptr conversion.
origArgs := make([]*Node, n.List.Len())
t := nod(OTFUNC, nil, nil)
diff --git a/src/cmd/compile/internal/logopt/log_opts.go b/src/cmd/compile/internal/logopt/log_opts.go
index 22a94b0f2d..37a049d640 100644
--- a/src/cmd/compile/internal/logopt/log_opts.go
+++ b/src/cmd/compile/internal/logopt/log_opts.go
@@ -19,6 +19,7 @@ import (
"strconv"
"strings"
"sync"
+ "unicode"
)
// This implements (non)optimization logging for -json option to the Go compiler
@@ -223,11 +224,11 @@ type Diagnostic struct {
// A LoggedOpt is what the compiler produces and accumulates,
// to be converted to JSON for human or IDE consumption.
type LoggedOpt struct {
- pos src.XPos // Source code position at which the event occurred. If it is inlined, outer and all inlined locations will appear in JSON.
- pass string // For human/adhoc consumption; does not appear in JSON (yet)
- fname string // For human/adhoc consumption; does not appear in JSON (yet)
- what string // The (non) optimization; "nilcheck", "boundsCheck", "inline", "noInline"
- target []interface{} // Optional target(s) or parameter(s) of "what" -- what was inlined, why it was not, size of copy, etc. 1st is most important/relevant.
+ pos src.XPos // Source code position at which the event occurred. If it is inlined, outer and all inlined locations will appear in JSON.
+ compilerPass string // Compiler pass. For human/adhoc consumption; does not appear in JSON (yet)
+ functionName string // Function name. For human/adhoc consumption; does not appear in JSON (yet)
+ what string // The (non) optimization; "nilcheck", "boundsCheck", "inline", "noInline"
+ target []interface{} // Optional target(s) or parameter(s) of "what" -- what was inlined, why it was not, size of copy, etc. 1st is most important/relevant.
}
type logFormat uint8
@@ -240,12 +241,13 @@ const (
var Format = None
var dest string
+// LogJsonOption parses and validates the version,directory value attached to the -json compiler flag.
func LogJsonOption(flagValue string) {
version, directory := parseLogFlag("json", flagValue)
if version != 0 {
log.Fatal("-json version must be 0")
}
- checkLogPath("json", directory)
+ dest = checkLogPath(directory)
Format = Json0
}
@@ -268,51 +270,80 @@ func parseLogFlag(flag, value string) (version int, directory string) {
return
}
+// isWindowsDriveURI returns true if the file URI is of the format used by
+// Windows URIs. The url.Parse package does not specially handle Windows paths
+// (see golang/go#6027), so we check if the URI path has a drive prefix (e.g. "/C:").
+// (copied from tools/internal/span/uri.go)
+// this is less comprehensive that the processing in filepath.IsAbs on Windows.
+func isWindowsDriveURIPath(uri string) bool {
+ if len(uri) < 4 {
+ return false
+ }
+ return uri[0] == '/' && unicode.IsLetter(rune(uri[1])) && uri[2] == ':'
+}
+
+func parseLogPath(destination string) (string, string) {
+ if filepath.IsAbs(destination) {
+ return filepath.Clean(destination), ""
+ }
+ if strings.HasPrefix(destination, "file://") { // IKWIAD, or Windows C:\foo\bar\baz
+ uri, err := url.Parse(destination)
+ if err != nil {
+ return "", fmt.Sprintf("optimizer logging destination looked like file:// URI but failed to parse: err=%v", err)
+ }
+ destination = uri.Host + uri.Path
+ if isWindowsDriveURIPath(destination) {
+ // strip leading / from /C:
+ // unlike tools/internal/span/uri.go, do not uppercase the drive letter -- let filepath.Clean do what it does.
+ destination = destination[1:]
+ }
+ return filepath.Clean(destination), ""
+ }
+ return "", fmt.Sprintf("optimizer logging destination %s was neither %s-prefixed directory nor file://-prefixed file URI", destination, string(filepath.Separator))
+}
+
// checkLogPath does superficial early checking of the string specifying
// the directory to which optimizer logging is directed, and if
// it passes the test, stores the string in LO_dir
-func checkLogPath(flag, destination string) {
- sep := string(os.PathSeparator)
- if strings.HasPrefix(destination, "/") || strings.HasPrefix(destination, sep) {
- err := os.MkdirAll(destination, 0755)
- if err != nil {
- log.Fatalf("optimizer logging destination ',' but could not create : err=%v", err)
- }
- } else if strings.HasPrefix(destination, "file://") { // IKWIAD, or Windows C:\foo\bar\baz
- uri, err := url.Parse(destination)
- if err != nil {
- log.Fatalf("optimizer logging destination looked like file:// URI but failed to parse: err=%v", err)
- }
- destination = uri.Host + uri.Path
- err = os.MkdirAll(destination, 0755)
- if err != nil {
- log.Fatalf("optimizer logging destination ',' but could not create %s: err=%v", destination, err)
- }
- } else {
- log.Fatalf("optimizer logging destination %s was neither %s-prefixed directory nor file://-prefixed file URI", destination, sep)
+func checkLogPath(destination string) string {
+ path, complaint := parseLogPath(destination)
+ if complaint != "" {
+ log.Fatalf(complaint)
}
- dest = destination
+ err := os.MkdirAll(path, 0755)
+ if err != nil {
+ log.Fatalf("optimizer logging destination ',' but could not create : err=%v", err)
+ }
+ return path
}
var loggedOpts []*LoggedOpt
var mu = sync.Mutex{} // mu protects loggedOpts.
-func NewLoggedOpt(pos src.XPos, what, pass, fname string, args ...interface{}) *LoggedOpt {
+// NewLoggedOpt allocates a new LoggedOpt, to later be passed to either NewLoggedOpt or LogOpt as "args".
+// Pos is the source position (including inlining), what is the message, pass is which pass created the message,
+// funcName is the name of the function
+// A typical use for this to accumulate an explanation for a missed optimization, for example, why did something escape?
+func NewLoggedOpt(pos src.XPos, what, pass, funcName string, args ...interface{}) *LoggedOpt {
pass = strings.Replace(pass, " ", "_", -1)
- return &LoggedOpt{pos, pass, fname, what, args}
+ return &LoggedOpt{pos, pass, funcName, what, args}
}
-func LogOpt(pos src.XPos, what, pass, fname string, args ...interface{}) {
+// Logopt logs information about a (usually missed) optimization performed by the compiler.
+// Pos is the source position (including inlining), what is the message, pass is which pass created the message,
+// funcName is the name of the function
+func LogOpt(pos src.XPos, what, pass, funcName string, args ...interface{}) {
if Format == None {
return
}
- lo := NewLoggedOpt(pos, what, pass, fname, args...)
+ lo := NewLoggedOpt(pos, what, pass, funcName, args...)
mu.Lock()
defer mu.Unlock()
// Because of concurrent calls from back end, no telling what the order will be, but is stable-sorted by outer Pos before use.
loggedOpts = append(loggedOpts, lo)
}
+// Enabled returns whether optimization logging is enabled.
func Enabled() bool {
switch Format {
case None:
@@ -459,11 +490,13 @@ func FlushLoggedOpts(ctxt *obj.Link, slashPkgPath string) {
}
}
+// newPointRange returns a single-position Range for the compiler source location p.
func newPointRange(p src.Pos) Range {
return Range{Start: Position{p.Line(), p.Col()},
End: Position{p.Line(), p.Col()}}
}
+// newLocation returns the Location for the compiler source location p
func newLocation(p src.Pos) Location {
loc := Location{URI: uriIfy(uprootedPath(p.Filename())), Range: newPointRange(p)}
return loc
diff --git a/src/cmd/compile/internal/logopt/logopt_test.go b/src/cmd/compile/internal/logopt/logopt_test.go
index df3e70a614..fca85c10fb 100644
--- a/src/cmd/compile/internal/logopt/logopt_test.go
+++ b/src/cmd/compile/internal/logopt/logopt_test.go
@@ -55,6 +55,34 @@ func wantN(t *testing.T, out string, desired string, n int) {
}
}
+func TestPathStuff(t *testing.T) {
+ sep := string(filepath.Separator)
+ if path, whine := parseLogPath("file:///c:foo"); path != "c:foo" || whine != "" { // good path
+ t.Errorf("path='%s', whine='%s'", path, whine)
+ }
+ if path, whine := parseLogPath("file:///foo"); path != sep+"foo" || whine != "" { // good path
+ t.Errorf("path='%s', whine='%s'", path, whine)
+ }
+ if path, whine := parseLogPath("foo"); path != "" || whine == "" { // BAD path
+ t.Errorf("path='%s', whine='%s'", path, whine)
+ }
+ if sep == "\\" { // On WINDOWS ONLY
+ if path, whine := parseLogPath("C:/foo"); path != "C:\\foo" || whine != "" { // good path
+ t.Errorf("path='%s', whine='%s'", path, whine)
+ }
+ if path, whine := parseLogPath("c:foo"); path != "" || whine == "" { // BAD path
+ t.Errorf("path='%s', whine='%s'", path, whine)
+ }
+ if path, whine := parseLogPath("/foo"); path != "" || whine == "" { // BAD path
+ t.Errorf("path='%s', whine='%s'", path, whine)
+ }
+ } else { // ON UNIX ONLY
+ if path, whine := parseLogPath("/foo"); path != sep+"foo" || whine != "" { // good path
+ t.Errorf("path='%s', whine='%s'", path, whine)
+ }
+ }
+}
+
func TestLogOpt(t *testing.T) {
t.Parallel()
@@ -180,12 +208,11 @@ func s15a8(x *[15]int64) [15]int64 {
`"relatedInformation":[{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":11},"end":{"line":4,"character":11}}},"message":"inlineLoc"}]}`)
want(t, slogged, `{"range":{"start":{"line":11,"character":6},"end":{"line":11,"character":6}},"severity":3,"code":"isInBounds","source":"go compiler","message":""}`)
want(t, slogged, `{"range":{"start":{"line":7,"character":6},"end":{"line":7,"character":6}},"severity":3,"code":"canInlineFunction","source":"go compiler","message":"cost: 35"}`)
- want(t, slogged, `{"range":{"start":{"line":21,"character":21},"end":{"line":21,"character":21}},"severity":3,"code":"cannotInlineCall","source":"go compiler","message":"foo cannot be inlined (escaping closure variable)"}`)
// escape analysis explanation
want(t, slogged, `{"range":{"start":{"line":7,"character":13},"end":{"line":7,"character":13}},"severity":3,"code":"leak","source":"go compiler","message":"parameter z leaks to ~r2 with derefs=0",`+
`"relatedInformation":[`+
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: y = z:"},`+
- `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from y = \u003cN\u003e (assign-pair)"},`+
+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from y := z (assign-pair)"},`+
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: ~r1 = y:"},`+
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":11},"end":{"line":4,"character":11}}},"message":"inlineLoc"},`+
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from y.b (dot of pointer)"},`+
diff --git a/src/cmd/compile/internal/ppc64/ssa.go b/src/cmd/compile/internal/ppc64/ssa.go
index 4a83a0bdd7..1ece4d999f 100644
--- a/src/cmd/compile/internal/ppc64/ssa.go
+++ b/src/cmd/compile/internal/ppc64/ssa.go
@@ -570,9 +570,9 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
r1 := v.Args[0].Reg()
shifts := v.AuxInt
p := s.Prog(v.Op.Asm())
- // clrlslwi ra,rs,sh,mb will become rlwinm ra,rs,sh,mb-sh,31-n as described in ISA
- p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: ssa.GetPPC64Shiftsh(shifts)}
- p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: ssa.GetPPC64Shiftmb(shifts)})
+ // clrlslwi ra,rs,mb,sh will become rlwinm ra,rs,sh,mb-sh,31-sh as described in ISA
+ p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: ssa.GetPPC64Shiftmb(shifts)}
+ p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: ssa.GetPPC64Shiftsh(shifts)})
p.Reg = r1
p.To.Type = obj.TYPE_REG
p.To.Reg = r
@@ -582,9 +582,9 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
r1 := v.Args[0].Reg()
shifts := v.AuxInt
p := s.Prog(v.Op.Asm())
- // clrlsldi ra,rs,sh,mb will become rldic ra,rs,sh,mb-sh
- p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: ssa.GetPPC64Shiftsh(shifts)}
- p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: ssa.GetPPC64Shiftmb(shifts)})
+ // clrlsldi ra,rs,mb,sh will become rldic ra,rs,sh,mb-sh
+ p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: ssa.GetPPC64Shiftmb(shifts)}
+ p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: ssa.GetPPC64Shiftsh(shifts)})
p.Reg = r1
p.To.Type = obj.TYPE_REG
p.To.Reg = r
@@ -677,7 +677,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.From.Reg = v.Args[0].Reg()
case ssa.OpPPC64ADDconst, ssa.OpPPC64ANDconst, ssa.OpPPC64ORconst, ssa.OpPPC64XORconst,
- ssa.OpPPC64SRADconst, ssa.OpPPC64SRAWconst, ssa.OpPPC64SRDconst, ssa.OpPPC64SRWconst, ssa.OpPPC64SLDconst, ssa.OpPPC64SLWconst:
+ ssa.OpPPC64SRADconst, ssa.OpPPC64SRAWconst, ssa.OpPPC64SRDconst, ssa.OpPPC64SRWconst,
+ ssa.OpPPC64SLDconst, ssa.OpPPC64SLWconst, ssa.OpPPC64EXTSWSLconst, ssa.OpPPC64MULLWconst, ssa.OpPPC64MULLDconst:
p := s.Prog(v.Op.Asm())
p.Reg = v.Args[0].Reg()
p.From.Type = obj.TYPE_CONST
diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go
index 4eed612977..0664c0ba46 100644
--- a/src/cmd/compile/internal/ssa/compile.go
+++ b/src/cmd/compile/internal/ssa/compile.go
@@ -47,6 +47,9 @@ func Compile(f *Func) {
stack := make([]byte, 16384)
n := runtime.Stack(stack, false)
stack = stack[:n]
+ if f.HTMLWriter != nil {
+ f.HTMLWriter.flushPhases()
+ }
f.Fatalf("panic during %s while compiling %s:\n\n%v\n\n%s\n", phaseName, f.Name, err, stack)
}
}()
@@ -201,6 +204,13 @@ func (p *pass) addDump(s string) {
p.dump[s] = true
}
+func (p *pass) String() string {
+ if p == nil {
+ return "nil pass"
+ }
+ return p.name
+}
+
// Run consistency checker between each phase
var (
checkEnabled = false
@@ -431,9 +441,9 @@ var passes = [...]pass{
{name: "nilcheckelim", fn: nilcheckelim},
{name: "prove", fn: prove},
{name: "early fuse", fn: fuseEarly},
+ {name: "expand calls", fn: expandCalls, required: true},
{name: "decompose builtin", fn: decomposeBuiltIn, required: true},
{name: "softfloat", fn: softfloat, required: true},
- {name: "expand calls", fn:expandCalls, required: true},
{name: "late opt", fn: opt, required: true}, // TODO: split required rules and optimizing rules
{name: "dead auto elim", fn: elimDeadAutosGeneric},
{name: "generic deadcode", fn: deadcode, required: true}, // remove dead stores, which otherwise mess up store chain
diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go
index 7f01f8047f..f1a748309c 100644
--- a/src/cmd/compile/internal/ssa/config.go
+++ b/src/cmd/compile/internal/ssa/config.go
@@ -38,7 +38,6 @@ type Config struct {
useSSE bool // Use SSE for non-float operations
useAvg bool // Use optimizations that need Avg* operations
useHmul bool // Use optimizations that need Hmul* operations
- use387 bool // GO386=387
SoftFloat bool //
Race bool // race detector enabled
NeedsFpScratch bool // No direct move between GP and FP register sets
@@ -196,6 +195,14 @@ const (
ClassParamOut // return value
)
+const go116lateCallExpansion = true
+
+// LateCallExpansionEnabledWithin returns true if late call expansion should be tested
+// within compilation of a function/method triggered by GOSSAHASH (defaults to "yes").
+func LateCallExpansionEnabledWithin(f *Func) bool {
+ return go116lateCallExpansion && f.DebugTest // Currently set up for GOSSAHASH bug searches
+}
+
// NewConfig returns a new configuration object for the given architecture.
func NewConfig(arch string, types Types, ctxt *obj.Link, optimize bool) *Config {
c := &Config{arch: arch, Types: types}
@@ -379,9 +386,4 @@ func NewConfig(arch string, types Types, ctxt *obj.Link, optimize bool) *Config
return c
}
-func (c *Config) Set387(b bool) {
- c.NeedsFpScratch = b
- c.use387 = b
-}
-
func (c *Config) Ctxt() *obj.Link { return c.ctxt }
diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go
index 34cff51c00..bbd9aeee51 100644
--- a/src/cmd/compile/internal/ssa/expand_calls.go
+++ b/src/cmd/compile/internal/ssa/expand_calls.go
@@ -4,14 +4,85 @@
package ssa
-import "cmd/compile/internal/types"
+import (
+ "cmd/compile/internal/types"
+ "cmd/internal/src"
+ "fmt"
+ "sort"
+)
// expandCalls converts LE (Late Expansion) calls that act like they receive value args into a lower-level form
-// that is more oriented to a platform's ABI. The SelectN operations that extract results are also rewritten into
-// more appropriate forms.
+// that is more oriented to a platform's ABI. The SelectN operations that extract results are rewritten into
+// more appropriate forms, and any StructMake or ArrayMake inputs are decomposed until non-struct values are
+// reached (for now, Strings, Slices, Complex, and Interface are not decomposed because they are rewritten in
+// a subsequent phase, but that may need to change for a register ABI in case one of those composite values is
+// split between registers and memory).
+//
+// TODO: when it comes time to use registers, might want to include builtin selectors as well, but currently that happens in lower.
func expandCalls(f *Func) {
+ if !LateCallExpansionEnabledWithin(f) {
+ return
+ }
canSSAType := f.fe.CanSSA
+ regSize := f.Config.RegSize
sp, _ := f.spSb()
+
+ debug := f.pass.debug > 0
+
+ // For 32-bit, need to deal with decomposition of 64-bit integers
+ tUint32 := types.Types[types.TUINT32]
+ tInt32 := types.Types[types.TINT32]
+ var hiOffset, lowOffset int64
+ if f.Config.BigEndian {
+ lowOffset = 4
+ } else {
+ hiOffset = 4
+ }
+
+ // intPairTypes returns the pair of 32-bit int types needed to encode a 64-bit integer type on a target
+ // that has no 64-bit integer registers.
+ intPairTypes := func(et types.EType) (tHi, tLo *types.Type) {
+ tHi = tUint32
+ if et == types.TINT64 {
+ tHi = tInt32
+ }
+ tLo = tUint32
+ return
+ }
+
+ // isAlreadyExpandedAggregateType returns whether a type is an SSA-able "aggregate" (multiple register) type
+ // that was expanded in an earlier phase (small user-defined arrays and structs, lowered in decomposeUser).
+ // Other aggregate types are expanded in decomposeBuiltin, which comes later.
+ isAlreadyExpandedAggregateType := func(t *types.Type) bool {
+ if !canSSAType(t) {
+ return false
+ }
+ return t.IsStruct() || t.IsArray() || regSize == 4 && t.Size() > 4 && t.IsInteger()
+ }
+
+ // removeTrivialWrapperTypes unwraps layers of
+ // struct { singleField SomeType } and [1]SomeType
+ // until a non-wrapper type is reached. This is useful
+ // for working with assignments to/from interface data
+ // fields (either second operand to OpIMake or OpIData)
+ // where the wrapping or type conversion can be elided
+ // because of type conversions/assertions in source code
+ // that do not appear in SSA.
+ removeTrivialWrapperTypes := func(t *types.Type) *types.Type {
+ for {
+ if t.IsStruct() && t.NumFields() == 1 {
+ t = t.Field(0).Type
+ continue
+ }
+ if t.IsArray() && t.NumElem() == 1 {
+ t = t.Elem()
+ continue
+ }
+ break
+ }
+ return t
+ }
+
// Calls that need lowering have some number of inputs, including a memory input,
// and produce a tuple of (value1, value2, ..., mem) where valueK may or may not be SSA-able.
@@ -21,31 +92,285 @@ func expandCalls(f *Func) {
// With the current ABI, the outputs need to be converted to loads, which will all use the call's
// memory output as their input.
- // Step 1: find all references to calls as values and rewrite those.
+ // rewriteSelect recursively walks leaf selector to a root (OpSelectN) through
+ // a chain of Struct/Array Select operations. If the chain of selectors does not
+ // end in OpSelectN, it does nothing (this can happen depending on compiler phase ordering).
+ // It emits the code necessary to implement the leaf select operation that leads to the call.
+ // TODO when registers really arrive, must also decompose anything split across two registers or registers and memory.
+ var rewriteSelect func(leaf *Value, selector *Value, offset int64)
+ rewriteSelect = func(leaf *Value, selector *Value, offset int64) {
+ switch selector.Op {
+ case OpSelectN:
+ // TODO these may be duplicated. Should memoize. Intermediate selectors will go dead, no worries there.
+ call := selector.Args[0]
+ aux := call.Aux.(*AuxCall)
+ which := selector.AuxInt
+ if which == aux.NResults() { // mem is after the results.
+ // rewrite v as a Copy of call -- the replacement call will produce a mem.
+ leaf.copyOf(call)
+ } else {
+ leafType := removeTrivialWrapperTypes(leaf.Type)
+ pt := types.NewPtr(leafType)
+ if canSSAType(leafType) {
+ off := f.ConstOffPtrSP(pt, offset+aux.OffsetOfResult(which), sp)
+ // Any selection right out of the arg area/registers has to be same Block as call, use call as mem input.
+ if leaf.Block == call.Block {
+ leaf.reset(OpLoad)
+ leaf.SetArgs2(off, call)
+ leaf.Type = leafType
+ } else {
+ w := call.Block.NewValue2(leaf.Pos, OpLoad, leafType, off, call)
+ leaf.copyOf(w)
+ }
+ } else {
+ panic("Should not have non-SSA-able OpSelectN")
+ }
+ }
+ case OpStructSelect:
+ w := selector.Args[0]
+ if w.Type.Etype != types.TSTRUCT {
+ fmt.Printf("Bad type for w:\nv=%v\nsel=%v\nw=%v\n,f=%s\n", leaf.LongString(), selector.LongString(), w.LongString(), f.Name)
+ }
+ rewriteSelect(leaf, w, offset+w.Type.FieldOff(int(selector.AuxInt)))
+
+ case OpInt64Hi:
+ w := selector.Args[0]
+ rewriteSelect(leaf, w, offset+hiOffset)
+
+ case OpInt64Lo:
+ w := selector.Args[0]
+ rewriteSelect(leaf, w, offset+lowOffset)
+
+ case OpArraySelect:
+ w := selector.Args[0]
+ rewriteSelect(leaf, w, offset+selector.Type.Size()*selector.AuxInt)
+ default:
+ // Ignore dead ends; on 32-bit, these can occur running before decompose builtins.
+ }
+ }
+
+ // storeArg converts stores of SSA-able aggregate arguments (passed to a call) into a series of stores of
+ // smaller types into individual parameter slots.
+ // TODO when registers really arrive, must also decompose anything split across two registers or registers and memory.
+ var storeArg func(pos src.XPos, b *Block, a *Value, t *types.Type, offset int64, mem *Value) *Value
+ storeArg = func(pos src.XPos, b *Block, a *Value, t *types.Type, offset int64, mem *Value) *Value {
+ switch a.Op {
+ case OpArrayMake0, OpStructMake0:
+ return mem
+ case OpStructMake1, OpStructMake2, OpStructMake3, OpStructMake4:
+ for i := 0; i < t.NumFields(); i++ {
+ fld := t.Field(i)
+ mem = storeArg(pos, b, a.Args[i], fld.Type, offset+fld.Offset, mem)
+ }
+ return mem
+ case OpArrayMake1:
+ return storeArg(pos, b, a.Args[0], t.Elem(), offset, mem)
+
+ case OpInt64Make:
+ tHi, tLo := intPairTypes(t.Etype)
+ mem = storeArg(pos, b, a.Args[0], tHi, offset+hiOffset, mem)
+ return storeArg(pos, b, a.Args[1], tLo, offset+lowOffset, mem)
+ }
+ dst := f.ConstOffPtrSP(types.NewPtr(t), offset, sp)
+ x := b.NewValue3A(pos, OpStore, types.TypeMem, t, dst, a, mem)
+ if debug {
+ fmt.Printf("storeArg(%v) returns %s\n", a, x.LongString())
+ }
+ return x
+ }
+
+ // offsetFrom creates an offset from a pointer, simplifying chained offsets and offsets from SP
+ // TODO should also optimize offsets from SB?
+ offsetFrom := func(dst *Value, offset int64, t *types.Type) *Value {
+ pt := types.NewPtr(t)
+ if offset == 0 && dst.Type == pt { // this is not actually likely
+ return dst
+ }
+ if dst.Op != OpOffPtr {
+ return dst.Block.NewValue1I(dst.Pos.WithNotStmt(), OpOffPtr, pt, offset, dst)
+ }
+ // Simplify OpOffPtr
+ from := dst.Args[0]
+ offset += dst.AuxInt
+ if from == sp {
+ return f.ConstOffPtrSP(pt, offset, sp)
+ }
+ return dst.Block.NewValue1I(dst.Pos.WithNotStmt(), OpOffPtr, pt, offset, from)
+ }
+
+ // splitStore converts a store of an SSA-able aggregate into a series of smaller stores, emitting
+ // appropriate Struct/Array Select operations (which will soon go dead) to obtain the parts.
+ var splitStore func(dst, src, mem, v *Value, t *types.Type, offset int64, firstStorePos src.XPos) *Value
+ splitStore = func(dst, src, mem, v *Value, t *types.Type, offset int64, firstStorePos src.XPos) *Value {
+ // TODO might be worth commoning up duplicate selectors, but since they go dead, maybe no point.
+ pos := v.Pos.WithNotStmt()
+ switch t.Etype {
+ case types.TINT64, types.TUINT64:
+ if t.Width == regSize {
+ break
+ }
+ tHi, tLo := intPairTypes(t.Etype)
+ sel := src.Block.NewValue1(pos, OpInt64Hi, tHi, src)
+ mem = splitStore(dst, sel, mem, v, tHi, offset+hiOffset, firstStorePos)
+ firstStorePos = firstStorePos.WithNotStmt()
+ sel = src.Block.NewValue1(pos, OpInt64Lo, tLo, src)
+ return splitStore(dst, sel, mem, v, tLo, offset+lowOffset, firstStorePos)
+
+ case types.TARRAY:
+ elt := t.Elem()
+ if src.Op == OpIData && t.NumElem() == 1 && t.Width == regSize && elt.Width == regSize {
+ t = removeTrivialWrapperTypes(t)
+ if t.Etype == types.TSTRUCT || t.Etype == types.TARRAY {
+ f.Fatalf("Did not expect to find IDATA-immediate with non-trivial struct/array in it")
+ }
+ break // handle the leaf type.
+ }
+ for i := int64(0); i < t.NumElem(); i++ {
+ sel := src.Block.NewValue1I(pos, OpArraySelect, elt, i, src)
+ mem = splitStore(dst, sel, mem, v, elt, offset+i*elt.Width, firstStorePos)
+ firstStorePos = firstStorePos.WithNotStmt()
+ }
+ return mem
+ case types.TSTRUCT:
+ if src.Op == OpIData && t.NumFields() == 1 && t.Field(0).Type.Width == t.Width && t.Width == regSize {
+ // This peculiar test deals with accesses to immediate interface data.
+ // It works okay because everything is the same size.
+ // Example code that triggers this can be found in go/constant/value.go, function ToComplex
+ // v119 (+881) = IData v6
+ // v121 (+882) = StaticLECall {AuxCall{"".itof([intVal,0])[floatVal,8]}} [16] v119 v1
+ // This corresponds to the generic rewrite rule "(StructSelect [0] (IData x)) => (IData x)"
+ // Guard against "struct{struct{*foo}}"
+ t = removeTrivialWrapperTypes(t)
+ if t.Etype == types.TSTRUCT || t.Etype == types.TARRAY {
+ f.Fatalf("Did not expect to find IDATA-immediate with non-trivial struct/array in it")
+ }
+ break // handle the leaf type.
+ }
+ for i := 0; i < t.NumFields(); i++ {
+ fld := t.Field(i)
+ sel := src.Block.NewValue1I(pos, OpStructSelect, fld.Type, int64(i), src)
+ mem = splitStore(dst, sel, mem, v, fld.Type, offset+fld.Offset, firstStorePos)
+ firstStorePos = firstStorePos.WithNotStmt()
+ }
+ return mem
+ }
+ // Default, including for aggregates whose single element exactly fills their container
+ // TODO this will be a problem for cast interfaces containing floats when we move to registers.
+ x := v.Block.NewValue3A(firstStorePos, OpStore, types.TypeMem, t, offsetFrom(dst, offset, t), src, mem)
+ if debug {
+ fmt.Printf("splitStore(%v, %v, %v, %v) returns %s\n", dst, src, mem, v, x.LongString())
+ }
+ return x
+ }
+
+ // rewriteArgs removes all the Args from a call and converts the call args into appropriate
+ // stores (or later, register movement). Extra args for interface and closure calls are ignored,
+ // but removed.
+ rewriteArgs := func(v *Value, firstArg int) *Value {
+ // Thread the stores on the memory arg
+ aux := v.Aux.(*AuxCall)
+ pos := v.Pos.WithNotStmt()
+ m0 := v.Args[len(v.Args)-1]
+ mem := m0
+ for i, a := range v.Args {
+ if i < firstArg {
+ continue
+ }
+ if a == m0 { // mem is last.
+ break
+ }
+ auxI := int64(i - firstArg)
+ if a.Op == OpDereference {
+ if a.MemoryArg() != m0 {
+ f.Fatalf("Op...LECall and OpDereference have mismatched mem, %s and %s", v.LongString(), a.LongString())
+ }
+ // "Dereference" of addressed (probably not-SSA-eligible) value becomes Move
+ // TODO this will be more complicated with registers in the picture.
+ src := a.Args[0]
+ dst := f.ConstOffPtrSP(src.Type, aux.OffsetOfArg(auxI), sp)
+ if a.Uses == 1 && a.Block == v.Block {
+ a.reset(OpMove)
+ a.Pos = pos
+ a.Type = types.TypeMem
+ a.Aux = aux.TypeOfArg(auxI)
+ a.AuxInt = aux.SizeOfArg(auxI)
+ a.SetArgs3(dst, src, mem)
+ mem = a
+ } else {
+ mem = v.Block.NewValue3A(pos, OpMove, types.TypeMem, aux.TypeOfArg(auxI), dst, src, mem)
+ mem.AuxInt = aux.SizeOfArg(auxI)
+ }
+ } else {
+ mem = storeArg(pos, v.Block, a, aux.TypeOfArg(auxI), aux.OffsetOfArg(auxI), mem)
+ }
+ }
+ v.resetArgs()
+ return mem
+ }
+
+ // Step 0: rewrite the calls to convert incoming args to stores.
for _, b := range f.Blocks {
for _, v := range b.Values {
switch v.Op {
- case OpSelectN:
- call := v.Args[0]
- aux := call.Aux.(*AuxCall)
- which := v.AuxInt
- t := v.Type
- if which == aux.NResults() { // mem is after the results.
- // rewrite v as a Copy of call -- the replacement call will produce a mem.
- v.copyOf(call)
- } else {
- pt := types.NewPtr(t)
- if canSSAType(t) {
- off := f.ConstOffPtrSP(pt, aux.OffsetOfResult(which), sp)
- v.reset(OpLoad)
- v.SetArgs2(off, call)
- } else {
- panic("Should not have non-SSA-able OpSelectN")
+ case OpStaticLECall:
+ mem := rewriteArgs(v, 0)
+ v.SetArgs1(mem)
+ case OpClosureLECall:
+ code := v.Args[0]
+ context := v.Args[1]
+ mem := rewriteArgs(v, 2)
+ v.SetArgs3(code, context, mem)
+ case OpInterLECall:
+ code := v.Args[0]
+ mem := rewriteArgs(v, 1)
+ v.SetArgs2(code, mem)
+ }
+ }
+ }
+
+ // Step 1: any stores of aggregates remaining are believed to be sourced from call results.
+ // Decompose those stores into a series of smaller stores, adding selection ops as necessary.
+ for _, b := range f.Blocks {
+ for _, v := range b.Values {
+ if v.Op == OpStore {
+ t := v.Aux.(*types.Type)
+ if isAlreadyExpandedAggregateType(t) {
+ dst, src, mem := v.Args[0], v.Args[1], v.Args[2]
+ mem = splitStore(dst, src, mem, v, t, 0, v.Pos)
+ v.copyOf(mem)
+ }
+ }
+ }
+ }
+
+ val2Preds := make(map[*Value]int32) // Used to accumulate dependency graph of selection operations for topological ordering.
+
+ // Step 2: accumulate selection operations for rewrite in topological order.
+ // Any select-for-addressing applied to call results can be transformed directly.
+ // TODO this is overkill; with the transformation of aggregate references into series of leaf references, it is only necessary to remember and recurse on the leaves.
+ for _, b := range f.Blocks {
+ for _, v := range b.Values {
+ // Accumulate chains of selectors for processing in topological order
+ switch v.Op {
+ case OpStructSelect, OpArraySelect, OpInt64Hi, OpInt64Lo:
+ w := v.Args[0]
+ switch w.Op {
+ case OpStructSelect, OpArraySelect, OpInt64Hi, OpInt64Lo, OpSelectN:
+ val2Preds[w] += 1
+ if debug {
+ fmt.Printf("v2p[%s] = %d\n", w.LongString(), val2Preds[w])
+ }
+ }
+ fallthrough
+ case OpSelectN:
+ if _, ok := val2Preds[v]; !ok {
+ val2Preds[v] = 0
+ if debug {
+ fmt.Printf("v2p[%s] = %d\n", v.LongString(), val2Preds[v])
}
}
- v.Type = t // not right for the mem operand yet, but will be when call is rewritten.
-
case OpSelectNAddr:
+ // Do these directly, there are no chains of selectors.
call := v.Args[0]
which := v.AuxInt
aux := call.Aux.(*AuxCall)
@@ -56,44 +381,72 @@ func expandCalls(f *Func) {
}
}
- // Step 2: rewrite the calls
+ // Compilation must be deterministic
+ var ordered []*Value
+ less := func(i, j int) bool { return ordered[i].ID < ordered[j].ID }
+
+ // Step 3: Rewrite in topological order. All chains of selectors end up in same block as the call.
+ for len(val2Preds) > 0 {
+ ordered = ordered[:0]
+ for v, n := range val2Preds {
+ if n == 0 {
+ ordered = append(ordered, v)
+ }
+ }
+ sort.Slice(ordered, less)
+ for _, v := range ordered {
+ for {
+ w := v.Args[0]
+ if debug {
+ fmt.Printf("About to rewrite %s, args[0]=%s\n", v.LongString(), w.LongString())
+ }
+ delete(val2Preds, v)
+ rewriteSelect(v, v, 0)
+ v = w
+ n, ok := val2Preds[v]
+ if !ok {
+ break
+ }
+ if n != 1 {
+ val2Preds[v] = n - 1
+ break
+ }
+ // Loop on new v; val2Preds[v] == 1 will be deleted in that iteration, no need to store zero.
+ }
+ }
+ }
+
+ // Step 4: rewrite the calls themselves, correcting the type
for _, b := range f.Blocks {
for _, v := range b.Values {
switch v.Op {
case OpStaticLECall:
- // Thread the stores on the memory arg
- m0 := v.Args[len(v.Args)-1]
- mem := m0
- pos := v.Pos.WithNotStmt()
- aux := v.Aux.(*AuxCall)
- auxInt := v.AuxInt
- for i, a := range v.Args {
- if a == m0 {
- break
- }
- if a.Op == OpDereference {
- // "Dereference" of addressed (probably not-SSA-eligible) value becomes Move
- src := a.Args[0]
- dst := f.ConstOffPtrSP(src.Type, aux.OffsetOfArg(int64(i)), sp)
- a.reset(OpMove)
- a.Pos = pos
- a.Type = types.TypeMem
- a.Aux = aux.TypeOfArg(int64(i))
- a.AuxInt = aux.SizeOfArg(int64(i))
- a.SetArgs3(dst, src, mem)
- mem = a
- } else {
- // Add a new store.
- t := aux.TypeOfArg(int64(i))
- dst := f.ConstOffPtrSP(types.NewPtr(t), aux.OffsetOfArg(int64(i)), sp)
- mem = b.NewValue3A(pos, OpStore, types.TypeMem, t, dst, a, mem)
- }
- }
- v.reset(OpStaticCall)
+ v.Op = OpStaticCall
v.Type = types.TypeMem
- v.Aux = aux
- v.AuxInt = auxInt
- v.SetArgs1(mem)
+ case OpClosureLECall:
+ v.Op = OpClosureCall
+ v.Type = types.TypeMem
+ case OpInterLECall:
+ v.Op = OpInterCall
+ v.Type = types.TypeMem
+ }
+ }
+ }
+
+ // Step 5: elide any copies introduced.
+ for _, b := range f.Blocks {
+ for _, v := range b.Values {
+ for i, a := range v.Args {
+ if a.Op != OpCopy {
+ continue
+ }
+ aa := copySource(a)
+ v.SetArg(i, aa)
+ for a.Uses == 0 {
+ b := a.Args[0]
+ a.reset(OpInvalid)
+ a = b
+ }
}
}
}
diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go
index 0df7b4a5d7..ec2c67c1fa 100644
--- a/src/cmd/compile/internal/ssa/func.go
+++ b/src/cmd/compile/internal/ssa/func.go
@@ -672,7 +672,7 @@ func (f *Func) Idom() []*Block {
return f.cachedIdom
}
-// sdom returns a sparse tree representing the dominator relationships
+// Sdom returns a sparse tree representing the dominator relationships
// among the blocks of f.
func (f *Func) Sdom() SparseTree {
if f.cachedSdom == nil {
diff --git a/src/cmd/compile/internal/ssa/gen/386.rules b/src/cmd/compile/internal/ssa/gen/386.rules
index 4a8244eb27..6a0b87cab4 100644
--- a/src/cmd/compile/internal/ssa/gen/386.rules
+++ b/src/cmd/compile/internal/ssa/gen/386.rules
@@ -38,10 +38,8 @@
(Xor(32|16|8) ...) => (XORL ...)
(Neg(32|16|8) ...) => (NEGL ...)
-(Neg32F x) && !config.use387 => (PXOR x (MOVSSconst [float32(math.Copysign(0, -1))]))
-(Neg64F x) && !config.use387 => (PXOR x (MOVSDconst [math.Copysign(0, -1)]))
-(Neg32F x) && config.use387 => (FCHS x)
-(Neg64F x) && config.use387 => (FCHS x)
+(Neg32F x) => (PXOR x (MOVSSconst [float32(math.Copysign(0, -1))]))
+(Neg64F x) => (PXOR x (MOVSDconst [math.Copysign(0, -1)]))
(Com(32|16|8) ...) => (NOTL ...)
@@ -670,8 +668,8 @@
// Merge load/store to op
((ADD|AND|OR|XOR|SUB|MUL)L x l:(MOVLload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && clobber(l) => ((ADD|AND|OR|XOR|SUB|MUL)Lload x [off] {sym} ptr mem)
-((ADD|SUB|MUL|DIV)SD x l:(MOVSDload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l) => ((ADD|SUB|MUL|DIV)SDload x [off] {sym} ptr mem)
-((ADD|SUB|MUL|DIV)SS x l:(MOVSSload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l) => ((ADD|SUB|MUL|DIV)SSload x [off] {sym} ptr mem)
+((ADD|SUB|MUL|DIV)SD x l:(MOVSDload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && clobber(l) => ((ADD|SUB|MUL|DIV)SDload x [off] {sym} ptr mem)
+((ADD|SUB|MUL|DIV)SS x l:(MOVSSload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && clobber(l) => ((ADD|SUB|MUL|DIV)SSload x [off] {sym} ptr mem)
(MOVLstore {sym} [off] ptr y:((ADD|AND|OR|XOR)Lload x [off] {sym} ptr mem) mem) && y.Uses==1 && clobber(y) => ((ADD|AND|OR|XOR)Lmodify [off] {sym} ptr x mem)
(MOVLstore {sym} [off] ptr y:((ADD|SUB|AND|OR|XOR)L l:(MOVLload [off] {sym} ptr mem) x) mem) && y.Uses==1 && l.Uses==1 && clobber(y, l) =>
((ADD|SUB|AND|OR|XOR)Lmodify [off] {sym} ptr x mem)
diff --git a/src/cmd/compile/internal/ssa/gen/386Ops.go b/src/cmd/compile/internal/ssa/gen/386Ops.go
index ddabde7d3d..737b99c371 100644
--- a/src/cmd/compile/internal/ssa/gen/386Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/386Ops.go
@@ -51,17 +51,6 @@ var regNames386 = []string{
"SB",
}
-// Notes on 387 support.
-// - The 387 has a weird stack-register setup for floating-point registers.
-// We use these registers when SSE registers are not available (when GO386=387).
-// - We use the same register names (X0-X7) but they refer to the 387
-// floating-point registers. That way, most of the SSA backend is unchanged.
-// - The instruction generation pass maintains an SSE->387 register mapping.
-// This mapping is updated whenever the FP stack is pushed or popped so that
-// we can always find a given SSE register even when the TOS pointer has changed.
-// - To facilitate the mapping from SSE to 387, we enforce that
-// every basic block starts and ends with an empty floating-point stack.
-
func init() {
// Make map from reg names to reg integers.
if len(regNames386) > 64 {
@@ -552,9 +541,6 @@ func init() {
{name: "FlagGT_UGT"}, // signed > and unsigned <
{name: "FlagGT_ULT"}, // signed > and unsigned >
- // Special op for -x on 387
- {name: "FCHS", argLength: 1, reg: fp11},
-
// Special ops for PIC floating-point constants.
// MOVSXconst1 loads the address of the constant-pool entry into a register.
// MOVSXconst2 loads the constant from that address.
diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules
index 67c69674f7..8a253035e0 100644
--- a/src/cmd/compile/internal/ssa/gen/AMD64.rules
+++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules
@@ -1224,178 +1224,180 @@
(LEAQ [off+int32(scale)*8] {sym} x)
// Absorb InvertFlags into branches.
-(LT (InvertFlags cmp) yes no) -> (GT cmp yes no)
-(GT (InvertFlags cmp) yes no) -> (LT cmp yes no)
-(LE (InvertFlags cmp) yes no) -> (GE cmp yes no)
-(GE (InvertFlags cmp) yes no) -> (LE cmp yes no)
-(ULT (InvertFlags cmp) yes no) -> (UGT cmp yes no)
-(UGT (InvertFlags cmp) yes no) -> (ULT cmp yes no)
-(ULE (InvertFlags cmp) yes no) -> (UGE cmp yes no)
-(UGE (InvertFlags cmp) yes no) -> (ULE cmp yes no)
-(EQ (InvertFlags cmp) yes no) -> (EQ cmp yes no)
-(NE (InvertFlags cmp) yes no) -> (NE cmp yes no)
+(LT (InvertFlags cmp) yes no) => (GT cmp yes no)
+(GT (InvertFlags cmp) yes no) => (LT cmp yes no)
+(LE (InvertFlags cmp) yes no) => (GE cmp yes no)
+(GE (InvertFlags cmp) yes no) => (LE cmp yes no)
+(ULT (InvertFlags cmp) yes no) => (UGT cmp yes no)
+(UGT (InvertFlags cmp) yes no) => (ULT cmp yes no)
+(ULE (InvertFlags cmp) yes no) => (UGE cmp yes no)
+(UGE (InvertFlags cmp) yes no) => (ULE cmp yes no)
+(EQ (InvertFlags cmp) yes no) => (EQ cmp yes no)
+(NE (InvertFlags cmp) yes no) => (NE cmp yes no)
// Constant comparisons.
-(CMPQconst (MOVQconst [x]) [y]) && x==y -> (FlagEQ)
-(CMPQconst (MOVQconst [x]) [y]) && x (FlagLT_ULT)
-(CMPQconst (MOVQconst [x]) [y]) && xuint64(y) -> (FlagLT_UGT)
-(CMPQconst (MOVQconst [x]) [y]) && x>y && uint64(x) (FlagGT_ULT)
-(CMPQconst (MOVQconst [x]) [y]) && x>y && uint64(x)>uint64(y) -> (FlagGT_UGT)
-(CMPLconst (MOVLconst [x]) [y]) && int32(x)==int32(y) -> (FlagEQ)
-(CMPLconst (MOVLconst [x]) [y]) && int32(x) (FlagLT_ULT)
-(CMPLconst (MOVLconst [x]) [y]) && int32(x)uint32(y) -> (FlagLT_UGT)
-(CMPLconst (MOVLconst [x]) [y]) && int32(x)>int32(y) && uint32(x) (FlagGT_ULT)
-(CMPLconst (MOVLconst [x]) [y]) && int32(x)>int32(y) && uint32(x)>uint32(y) -> (FlagGT_UGT)
-(CMPWconst (MOVLconst [x]) [y]) && int16(x)==int16(y) -> (FlagEQ)
-(CMPWconst (MOVLconst [x]) [y]) && int16(x) (FlagLT_ULT)
-(CMPWconst (MOVLconst [x]) [y]) && int16(x)uint16(y) -> (FlagLT_UGT)
-(CMPWconst (MOVLconst [x]) [y]) && int16(x)>int16(y) && uint16(x) (FlagGT_ULT)
-(CMPWconst (MOVLconst [x]) [y]) && int16(x)>int16(y) && uint16(x)>uint16(y) -> (FlagGT_UGT)
-(CMPBconst (MOVLconst [x]) [y]) && int8(x)==int8(y) -> (FlagEQ)
-(CMPBconst (MOVLconst [x]) [y]) && int8(x) (FlagLT_ULT)
-(CMPBconst (MOVLconst [x]) [y]) && int8(x)uint8(y) -> (FlagLT_UGT)
-(CMPBconst (MOVLconst [x]) [y]) && int8(x)>int8(y) && uint8(x) (FlagGT_ULT)
-(CMPBconst (MOVLconst [x]) [y]) && int8(x)>int8(y) && uint8(x)>uint8(y) -> (FlagGT_UGT)
+(CMPQconst (MOVQconst [x]) [y]) && x==int64(y) => (FlagEQ)
+(CMPQconst (MOVQconst [x]) [y]) && x (FlagLT_ULT)
+(CMPQconst (MOVQconst [x]) [y]) && xuint64(int64(y)) => (FlagLT_UGT)
+(CMPQconst (MOVQconst [x]) [y]) && x>int64(y) && uint64(x) (FlagGT_ULT)
+(CMPQconst (MOVQconst [x]) [y]) && x>int64(y) && uint64(x)>uint64(int64(y)) => (FlagGT_UGT)
+(CMPLconst (MOVLconst [x]) [y]) && x==y => (FlagEQ)
+(CMPLconst (MOVLconst [x]) [y]) && x (FlagLT_ULT)
+(CMPLconst (MOVLconst [x]) [y]) && xuint32(y) => (FlagLT_UGT)
+(CMPLconst (MOVLconst [x]) [y]) && x>y && uint32(x) (FlagGT_ULT)
+(CMPLconst (MOVLconst [x]) [y]) && x>y && uint32(x)>uint32(y) => (FlagGT_UGT)
+(CMPWconst (MOVLconst [x]) [y]) && int16(x)==y => (FlagEQ)
+(CMPWconst (MOVLconst [x]) [y]) && int16(x) (FlagLT_ULT)
+(CMPWconst (MOVLconst [x]) [y]) && int16(x)uint16(y) => (FlagLT_UGT)
+(CMPWconst (MOVLconst [x]) [y]) && int16(x)>y && uint16(x) (FlagGT_ULT)
+(CMPWconst (MOVLconst [x]) [y]) && int16(x)>y && uint16(x)>uint16(y) => (FlagGT_UGT)
+(CMPBconst (MOVLconst [x]) [y]) && int8(x)==y => (FlagEQ)
+(CMPBconst (MOVLconst [x]) [y]) && int8(x) (FlagLT_ULT)
+(CMPBconst (MOVLconst [x]) [y]) && int8(x)uint8(y) => (FlagLT_UGT)
+(CMPBconst (MOVLconst [x]) [y]) && int8(x)>y && uint8(x) (FlagGT_ULT)
+(CMPBconst (MOVLconst [x]) [y]) && int8(x)>y && uint8(x)>uint8(y) => (FlagGT_UGT)
// CMPQconst requires a 32 bit const, but we can still constant-fold 64 bit consts.
// In theory this applies to any of the simplifications above,
// but CMPQ is the only one I've actually seen occur.
-(CMPQ (MOVQconst [x]) (MOVQconst [y])) && x==y -> (FlagEQ)
-(CMPQ (MOVQconst [x]) (MOVQconst [y])) && x (FlagLT_ULT)
-(CMPQ (MOVQconst [x]) (MOVQconst [y])) && xuint64(y) -> (FlagLT_UGT)
-(CMPQ (MOVQconst [x]) (MOVQconst [y])) && x>y && uint64(x) (FlagGT_ULT)
-(CMPQ (MOVQconst [x]) (MOVQconst [y])) && x>y && uint64(x)>uint64(y) -> (FlagGT_UGT)
+(CMPQ (MOVQconst [x]) (MOVQconst [y])) && x==y => (FlagEQ)
+(CMPQ (MOVQconst [x]) (MOVQconst [y])) && x (FlagLT_ULT)
+(CMPQ (MOVQconst [x]) (MOVQconst [y])) && xuint64(y) => (FlagLT_UGT)
+(CMPQ (MOVQconst [x]) (MOVQconst [y])) && x>y && uint64(x) (FlagGT_ULT)
+(CMPQ (MOVQconst [x]) (MOVQconst [y])) && x>y && uint64(x)>uint64(y) => (FlagGT_UGT)
// Other known comparisons.
-(CMPQconst (MOVBQZX _) [c]) && 0xFF < c -> (FlagLT_ULT)
-(CMPQconst (MOVWQZX _) [c]) && 0xFFFF < c -> (FlagLT_ULT)
-(CMPQconst (MOVLQZX _) [c]) && 0xFFFFFFFF < c -> (FlagLT_ULT)
-(CMPLconst (SHRLconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 32 && (1< (FlagLT_ULT)
-(CMPQconst (SHRQconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 64 && (1< (FlagLT_ULT)
-(CMPQconst (ANDQconst _ [m]) [n]) && 0 <= m && m < n -> (FlagLT_ULT)
-(CMPQconst (ANDLconst _ [m]) [n]) && 0 <= m && m < n -> (FlagLT_ULT)
-(CMPLconst (ANDLconst _ [m]) [n]) && 0 <= int32(m) && int32(m) < int32(n) -> (FlagLT_ULT)
-(CMPWconst (ANDLconst _ [m]) [n]) && 0 <= int16(m) && int16(m) < int16(n) -> (FlagLT_ULT)
-(CMPBconst (ANDLconst _ [m]) [n]) && 0 <= int8(m) && int8(m) < int8(n) -> (FlagLT_ULT)
+(CMPQconst (MOVBQZX _) [c]) && 0xFF < c => (FlagLT_ULT)
+(CMPQconst (MOVWQZX _) [c]) && 0xFFFF < c => (FlagLT_ULT)
+(CMPLconst (SHRLconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 32 && (1< (FlagLT_ULT)
+(CMPQconst (SHRQconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 64 && (1< (FlagLT_ULT)
+(CMPQconst (ANDQconst _ [m]) [n]) && 0 <= m && m < n => (FlagLT_ULT)
+(CMPQconst (ANDLconst _ [m]) [n]) && 0 <= m && m < n => (FlagLT_ULT)
+(CMPLconst (ANDLconst _ [m]) [n]) && 0 <= m && m < n => (FlagLT_ULT)
+(CMPWconst (ANDLconst _ [m]) [n]) && 0 <= int16(m) && int16(m) < n => (FlagLT_ULT)
+(CMPBconst (ANDLconst _ [m]) [n]) && 0 <= int8(m) && int8(m) < n => (FlagLT_ULT)
// TESTQ c c sets flags like CMPQ c 0.
-(TEST(Q|L)const [c] (MOV(Q|L)const [c])) && c == 0 -> (FlagEQ)
-(TEST(Q|L)const [c] (MOV(Q|L)const [c])) && c < 0 -> (FlagLT_UGT)
-(TEST(Q|L)const [c] (MOV(Q|L)const [c])) && c > 0 -> (FlagGT_UGT)
+(TESTQconst [c] (MOVQconst [d])) && int64(c) == d && c == 0 => (FlagEQ)
+(TESTLconst [c] (MOVLconst [c])) && c == 0 => (FlagEQ)
+(TESTQconst [c] (MOVQconst [d])) && int64(c) == d && c < 0 => (FlagLT_UGT)
+(TESTLconst [c] (MOVLconst [c])) && c < 0 => (FlagLT_UGT)
+(TESTQconst [c] (MOVQconst [d])) && int64(c) == d && c > 0 => (FlagGT_UGT)
+(TESTLconst [c] (MOVLconst [c])) && c > 0 => (FlagGT_UGT)
// TODO: DIVxU also.
// Absorb flag constants into SBB ops.
-(SBBQcarrymask (FlagEQ)) -> (MOVQconst [0])
-(SBBQcarrymask (FlagLT_ULT)) -> (MOVQconst [-1])
-(SBBQcarrymask (FlagLT_UGT)) -> (MOVQconst [0])
-(SBBQcarrymask (FlagGT_ULT)) -> (MOVQconst [-1])
-(SBBQcarrymask (FlagGT_UGT)) -> (MOVQconst [0])
-(SBBLcarrymask (FlagEQ)) -> (MOVLconst [0])
-(SBBLcarrymask (FlagLT_ULT)) -> (MOVLconst [-1])
-(SBBLcarrymask (FlagLT_UGT)) -> (MOVLconst [0])
-(SBBLcarrymask (FlagGT_ULT)) -> (MOVLconst [-1])
-(SBBLcarrymask (FlagGT_UGT)) -> (MOVLconst [0])
+(SBBQcarrymask (FlagEQ)) => (MOVQconst [0])
+(SBBQcarrymask (FlagLT_ULT)) => (MOVQconst [-1])
+(SBBQcarrymask (FlagLT_UGT)) => (MOVQconst [0])
+(SBBQcarrymask (FlagGT_ULT)) => (MOVQconst [-1])
+(SBBQcarrymask (FlagGT_UGT)) => (MOVQconst [0])
+(SBBLcarrymask (FlagEQ)) => (MOVLconst [0])
+(SBBLcarrymask (FlagLT_ULT)) => (MOVLconst [-1])
+(SBBLcarrymask (FlagLT_UGT)) => (MOVLconst [0])
+(SBBLcarrymask (FlagGT_ULT)) => (MOVLconst [-1])
+(SBBLcarrymask (FlagGT_UGT)) => (MOVLconst [0])
// Absorb flag constants into branches.
-((EQ|LE|GE|ULE|UGE) (FlagEQ) yes no) -> (First yes no)
-((NE|LT|GT|ULT|UGT) (FlagEQ) yes no) -> (First no yes)
-((NE|LT|LE|ULT|ULE) (FlagLT_ULT) yes no) -> (First yes no)
-((EQ|GT|GE|UGT|UGE) (FlagLT_ULT) yes no) -> (First no yes)
-((NE|LT|LE|UGT|UGE) (FlagLT_UGT) yes no) -> (First yes no)
-((EQ|GT|GE|ULT|ULE) (FlagLT_UGT) yes no) -> (First no yes)
-((NE|GT|GE|ULT|ULE) (FlagGT_ULT) yes no) -> (First yes no)
-((EQ|LT|LE|UGT|UGE) (FlagGT_ULT) yes no) -> (First no yes)
-((NE|GT|GE|UGT|UGE) (FlagGT_UGT) yes no) -> (First yes no)
-((EQ|LT|LE|ULT|ULE) (FlagGT_UGT) yes no) -> (First no yes)
+((EQ|LE|GE|ULE|UGE) (FlagEQ) yes no) => (First yes no)
+((NE|LT|GT|ULT|UGT) (FlagEQ) yes no) => (First no yes)
+((NE|LT|LE|ULT|ULE) (FlagLT_ULT) yes no) => (First yes no)
+((EQ|GT|GE|UGT|UGE) (FlagLT_ULT) yes no) => (First no yes)
+((NE|LT|LE|UGT|UGE) (FlagLT_UGT) yes no) => (First yes no)
+((EQ|GT|GE|ULT|ULE) (FlagLT_UGT) yes no) => (First no yes)
+((NE|GT|GE|ULT|ULE) (FlagGT_ULT) yes no) => (First yes no)
+((EQ|LT|LE|UGT|UGE) (FlagGT_ULT) yes no) => (First no yes)
+((NE|GT|GE|UGT|UGE) (FlagGT_UGT) yes no) => (First yes no)
+((EQ|LT|LE|ULT|ULE) (FlagGT_UGT) yes no) => (First no yes)
// Absorb flag constants into SETxx ops.
-((SETEQ|SETLE|SETGE|SETBE|SETAE) (FlagEQ)) -> (MOVLconst [1])
-((SETNE|SETL|SETG|SETB|SETA) (FlagEQ)) -> (MOVLconst [0])
-((SETNE|SETL|SETLE|SETB|SETBE) (FlagLT_ULT)) -> (MOVLconst [1])
-((SETEQ|SETG|SETGE|SETA|SETAE) (FlagLT_ULT)) -> (MOVLconst [0])
-((SETNE|SETL|SETLE|SETA|SETAE) (FlagLT_UGT)) -> (MOVLconst [1])
-((SETEQ|SETG|SETGE|SETB|SETBE) (FlagLT_UGT)) -> (MOVLconst [0])
-((SETNE|SETG|SETGE|SETB|SETBE) (FlagGT_ULT)) -> (MOVLconst [1])
-((SETEQ|SETL|SETLE|SETA|SETAE) (FlagGT_ULT)) -> (MOVLconst [0])
-((SETNE|SETG|SETGE|SETA|SETAE) (FlagGT_UGT)) -> (MOVLconst [1])
-((SETEQ|SETL|SETLE|SETB|SETBE) (FlagGT_UGT)) -> (MOVLconst [0])
+((SETEQ|SETLE|SETGE|SETBE|SETAE) (FlagEQ)) => (MOVLconst [1])
+((SETNE|SETL|SETG|SETB|SETA) (FlagEQ)) => (MOVLconst [0])
+((SETNE|SETL|SETLE|SETB|SETBE) (FlagLT_ULT)) => (MOVLconst [1])
+((SETEQ|SETG|SETGE|SETA|SETAE) (FlagLT_ULT)) => (MOVLconst [0])
+((SETNE|SETL|SETLE|SETA|SETAE) (FlagLT_UGT)) => (MOVLconst [1])
+((SETEQ|SETG|SETGE|SETB|SETBE) (FlagLT_UGT)) => (MOVLconst [0])
+((SETNE|SETG|SETGE|SETB|SETBE) (FlagGT_ULT)) => (MOVLconst [1])
+((SETEQ|SETL|SETLE|SETA|SETAE) (FlagGT_ULT)) => (MOVLconst [0])
+((SETNE|SETG|SETGE|SETA|SETAE) (FlagGT_UGT)) => (MOVLconst [1])
+((SETEQ|SETL|SETLE|SETB|SETBE) (FlagGT_UGT)) => (MOVLconst [0])
-(SETEQstore [off] {sym} ptr (FlagEQ) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
-(SETEQstore [off] {sym} ptr (FlagLT_ULT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
-(SETEQstore [off] {sym} ptr (FlagLT_UGT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
-(SETEQstore [off] {sym} ptr (FlagGT_ULT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
-(SETEQstore [off] {sym} ptr (FlagGT_UGT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
+(SETEQstore [off] {sym} ptr (FlagEQ) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
+(SETEQstore [off] {sym} ptr (FlagLT_ULT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
+(SETEQstore [off] {sym} ptr (FlagLT_UGT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
+(SETEQstore [off] {sym} ptr (FlagGT_ULT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
+(SETEQstore [off] {sym} ptr (FlagGT_UGT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
-(SETNEstore [off] {sym} ptr (FlagEQ) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
-(SETNEstore [off] {sym} ptr (FlagLT_ULT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
-(SETNEstore [off] {sym} ptr (FlagLT_UGT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
-(SETNEstore [off] {sym} ptr (FlagGT_ULT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
-(SETNEstore [off] {sym} ptr (FlagGT_UGT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
+(SETNEstore [off] {sym} ptr (FlagEQ) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
+(SETNEstore [off] {sym} ptr (FlagLT_ULT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
+(SETNEstore [off] {sym} ptr (FlagLT_UGT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
+(SETNEstore [off] {sym} ptr (FlagGT_ULT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
+(SETNEstore [off] {sym} ptr (FlagGT_UGT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
-(SETLstore [off] {sym} ptr (FlagEQ) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
-(SETLstore [off] {sym} ptr (FlagLT_ULT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
-(SETLstore [off] {sym} ptr (FlagLT_UGT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
-(SETLstore [off] {sym} ptr (FlagGT_ULT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
-(SETLstore [off] {sym} ptr (FlagGT_UGT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
+(SETLstore [off] {sym} ptr (FlagEQ) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
+(SETLstore [off] {sym} ptr (FlagLT_ULT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
+(SETLstore [off] {sym} ptr (FlagLT_UGT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
+(SETLstore [off] {sym} ptr (FlagGT_ULT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
+(SETLstore [off] {sym} ptr (FlagGT_UGT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
-(SETLEstore [off] {sym} ptr (FlagEQ) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
-(SETLEstore [off] {sym} ptr (FlagLT_ULT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
-(SETLEstore [off] {sym} ptr (FlagLT_UGT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
-(SETLEstore [off] {sym} ptr (FlagGT_ULT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
-(SETLEstore [off] {sym} ptr (FlagGT_UGT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
+(SETLEstore [off] {sym} ptr (FlagEQ) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
+(SETLEstore [off] {sym} ptr (FlagLT_ULT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
+(SETLEstore [off] {sym} ptr (FlagLT_UGT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
+(SETLEstore [off] {sym} ptr (FlagGT_ULT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
+(SETLEstore [off] {sym} ptr (FlagGT_UGT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
-(SETGstore [off] {sym} ptr (FlagEQ) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
-(SETGstore [off] {sym} ptr (FlagLT_ULT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
-(SETGstore [off] {sym} ptr (FlagLT_UGT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
-(SETGstore [off] {sym} ptr (FlagGT_ULT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
-(SETGstore [off] {sym} ptr (FlagGT_UGT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
+(SETGstore [off] {sym} ptr (FlagEQ) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
+(SETGstore [off] {sym} ptr (FlagLT_ULT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
+(SETGstore [off] {sym} ptr (FlagLT_UGT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
+(SETGstore [off] {sym} ptr (FlagGT_ULT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
+(SETGstore [off] {sym} ptr (FlagGT_UGT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
-(SETGEstore [off] {sym} ptr (FlagEQ) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
-(SETGEstore [off] {sym} ptr (FlagLT_ULT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
-(SETGEstore [off] {sym} ptr (FlagLT_UGT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
-(SETGEstore [off] {sym} ptr (FlagGT_ULT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
-(SETGEstore [off] {sym} ptr (FlagGT_UGT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
+(SETGEstore [off] {sym} ptr (FlagEQ) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
+(SETGEstore [off] {sym} ptr (FlagLT_ULT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
+(SETGEstore [off] {sym} ptr (FlagLT_UGT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
+(SETGEstore [off] {sym} ptr (FlagGT_ULT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
+(SETGEstore [off] {sym} ptr (FlagGT_UGT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
-(SETBstore [off] {sym} ptr (FlagEQ) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
-(SETBstore [off] {sym} ptr (FlagLT_ULT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
-(SETBstore [off] {sym} ptr (FlagLT_UGT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
-(SETBstore [off] {sym} ptr (FlagGT_ULT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
-(SETBstore [off] {sym} ptr (FlagGT_UGT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
+(SETBstore [off] {sym} ptr (FlagEQ) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
+(SETBstore [off] {sym} ptr (FlagLT_ULT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
+(SETBstore [off] {sym} ptr (FlagLT_UGT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
+(SETBstore [off] {sym} ptr (FlagGT_ULT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
+(SETBstore [off] {sym} ptr (FlagGT_UGT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
-(SETBEstore [off] {sym} ptr (FlagEQ) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
-(SETBEstore [off] {sym} ptr (FlagLT_ULT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
-(SETBEstore [off] {sym} ptr (FlagLT_UGT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
-(SETBEstore [off] {sym} ptr (FlagGT_ULT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
-(SETBEstore [off] {sym} ptr (FlagGT_UGT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
+(SETBEstore [off] {sym} ptr (FlagEQ) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
+(SETBEstore [off] {sym} ptr (FlagLT_ULT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
+(SETBEstore [off] {sym} ptr (FlagLT_UGT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
+(SETBEstore [off] {sym} ptr (FlagGT_ULT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
+(SETBEstore [off] {sym} ptr (FlagGT_UGT) mem) => (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
-(SETAstore [off] {sym} ptr (FlagEQ) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
-(SETAstore [off] {sym} ptr (FlagLT_ULT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [0]) mem)
-(SETAstore [off] {sym} ptr (FlagLT_UGT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst [1]) mem)
-(SETAstore [off] {sym} ptr (FlagGT_ULT) mem) -> (MOVBstore [off] {sym} ptr (MOVLconst