mirror of
https://github.com/golang/go.git
synced 2026-02-01 16:42:04 +03:00
Compare commits
176 Commits
dev.garbag
...
go1.8.7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
357c914136 | ||
|
|
9574ce9cf6 | ||
|
|
44821583bc | ||
|
|
96c72e9468 | ||
|
|
89e6a4d6d0 | ||
|
|
a5a3be1636 | ||
|
|
45a42c9be5 | ||
|
|
6c733cd93b | ||
|
|
d4ccbd8833 | ||
|
|
79be6cb389 | ||
|
|
b838f943ab | ||
|
|
3be9637d56 | ||
|
|
2eac89d5c8 | ||
|
|
142d449081 | ||
|
|
533ee44cd4 | ||
|
|
8093678ae1 | ||
|
|
0bf8909ff8 | ||
|
|
b3b1e12b13 | ||
|
|
1ab2a4e85f | ||
|
|
25be91ae4f | ||
|
|
82cfda2910 | ||
|
|
9ccc2921dd | ||
|
|
ead964dc80 | ||
|
|
7e9658fea9 | ||
|
|
7e2cd1d81e | ||
|
|
f5bcb9b8fe | ||
|
|
4be3fc33ef | ||
|
|
a4544a0f8a | ||
|
|
9d1d78c34c | ||
|
|
d45b26b1b7 | ||
|
|
f3e6216450 | ||
|
|
352996a381 | ||
|
|
bb5055d6f1 | ||
|
|
439c0c8be8 | ||
|
|
e396667ba3 | ||
|
|
daf6706f37 | ||
|
|
958c64bbab | ||
|
|
195e20a976 | ||
|
|
f55bc1c4eb | ||
|
|
51f508bb4a | ||
|
|
243dee1737 | ||
|
|
a43c0d2dc8 | ||
|
|
1054085dcf | ||
|
|
18a13d373a | ||
|
|
6efa2f22ac | ||
|
|
fb9770f09b | ||
|
|
b6a8fc8d8c | ||
|
|
59870f9e19 | ||
|
|
c9688ddb6b | ||
|
|
38d35f49e7 | ||
|
|
8babce23e3 | ||
|
|
853d533ed6 | ||
|
|
166f2159d8 | ||
|
|
95a5b80e6d | ||
|
|
fe79c75268 | ||
|
|
d7989b784e | ||
|
|
056be9f79c | ||
|
|
02240408a1 | ||
|
|
04017ffadf | ||
|
|
2d0043014f | ||
|
|
3ca0d34fa1 | ||
|
|
84192f2734 | ||
|
|
752b8b773d | ||
|
|
ff5695d0fd | ||
|
|
517a38c630 | ||
|
|
dc70a5efd1 | ||
|
|
77476e81d9 | ||
|
|
bf71119d54 | ||
|
|
11a224bc56 | ||
|
|
3a8841bcaf | ||
|
|
6c5abcf21a | ||
|
|
43fa04c23c | ||
|
|
e35c01b404 | ||
|
|
c955eb1935 | ||
|
|
f8ed4539eb | ||
|
|
d43130743c | ||
|
|
0a5cec792f | ||
|
|
8890527476 | ||
|
|
ea6781bcd0 | ||
|
|
2327d696c1 | ||
|
|
ba48d2002e | ||
|
|
b43fabfb30 | ||
|
|
6a712dfac1 | ||
|
|
865536b197 | ||
|
|
bae53daa72 | ||
|
|
d4ee1f4a40 | ||
|
|
991ee8f4ac | ||
|
|
cd6b6202dd | ||
|
|
606eb9b0c1 | ||
|
|
bcda91c18d | ||
|
|
7d7a0a9d64 | ||
|
|
cedc511a6e | ||
|
|
ae13ccfd6d | ||
|
|
7cec9a583d | ||
|
|
d84dee069a | ||
|
|
f1e44a4b74 | ||
|
|
3ade54063e | ||
|
|
0545006bdb | ||
|
|
1363eeba65 | ||
|
|
1edfd64761 | ||
|
|
6eb0f5440e | ||
|
|
c543cc353d | ||
|
|
f0749fe163 | ||
|
|
ba878ac0c8 | ||
|
|
6177f6d448 | ||
|
|
67cd1fa780 | ||
|
|
758a7281ab | ||
|
|
470704531d | ||
|
|
648bb34484 | ||
|
|
d8d2f036a5 | ||
|
|
3e55059f30 | ||
|
|
0949659952 | ||
|
|
4cffe2b604 | ||
|
|
6bdb0c11c7 | ||
|
|
09096bd3eb | ||
|
|
96ea0918e6 | ||
|
|
2a5f65a98c | ||
|
|
21a8db1c5f | ||
|
|
2f6c20b46c | ||
|
|
78860b2ad2 | ||
|
|
2b283cedef | ||
|
|
1cf08182f9 | ||
|
|
b531eb3062 | ||
|
|
165cfbc409 | ||
|
|
ea73649343 | ||
|
|
1db16711f5 | ||
|
|
3717b429f2 | ||
|
|
98842cabb6 | ||
|
|
314180e7f6 | ||
|
|
aad06da2b9 | ||
|
|
be9dcfec29 | ||
|
|
a96e117a58 | ||
|
|
4cce27a3fa | ||
|
|
1be957d703 | ||
|
|
ec654e2251 | ||
|
|
256a605faa | ||
|
|
e8d5989ed1 | ||
|
|
ea7d9e6a52 | ||
|
|
59f181b6fd | ||
|
|
d18087cb25 | ||
|
|
6593d8650d | ||
|
|
c1730ae424 | ||
|
|
d10eddcba3 | ||
|
|
2c8b70eacf | ||
|
|
fcfd91858b | ||
|
|
81a61a96c9 | ||
|
|
f674537cc9 | ||
|
|
d8711919db | ||
|
|
48d8edb5b2 | ||
|
|
92ecd78933 | ||
|
|
787125abab | ||
|
|
5b708a6b6a | ||
|
|
e83d506714 | ||
|
|
76f981c8d8 | ||
|
|
e395e3246a | ||
|
|
6a3c6c0de8 | ||
|
|
467109bf56 | ||
|
|
b2a3b54b95 | ||
|
|
593ea3b360 | ||
|
|
0642b8a2f1 | ||
|
|
4601eae6ba | ||
|
|
4c4c5fc7a3 | ||
|
|
22689c4450 | ||
|
|
9cf06ed6cd | ||
|
|
9c3630f578 | ||
|
|
4f0aac52d9 | ||
|
|
333f764df3 | ||
|
|
39e31d5ec0 | ||
|
|
08da8201ca | ||
|
|
fdde7ba2a2 | ||
|
|
f65abf6ddc | ||
|
|
641ef2a733 | ||
|
|
0724aa813f | ||
|
|
ac05542985 | ||
|
|
b842c9aac7 | ||
|
|
3de6e96e4b |
54
README.md
54
README.md
@@ -5,39 +5,37 @@ reliable, and efficient software.
|
||||
|
||||

|
||||
|
||||
For documentation about how to install and use Go,
|
||||
visit https://golang.org/ or load doc/install-source.html
|
||||
in your web browser.
|
||||
|
||||
Our canonical Git repository is located at https://go.googlesource.com/go.
|
||||
There is a mirror of the repository at https://github.com/golang/go.
|
||||
|
||||
Unless otherwise noted, the Go source files are distributed under the
|
||||
BSD-style license found in the LICENSE file.
|
||||
|
||||
### Download and Install
|
||||
|
||||
#### Binary Distributions
|
||||
|
||||
Official binary distributions are available at https://golang.org/dl/.
|
||||
|
||||
After downloading a binary release, visit https://golang.org/doc/install
|
||||
or load doc/install.html in your web browser for installation
|
||||
instructions.
|
||||
|
||||
#### Install From Source
|
||||
|
||||
If a binary distribution is not available for your combination of
|
||||
operating system and architecture, visit
|
||||
https://golang.org/doc/install/source or load doc/install-source.html
|
||||
in your web browser for source installation instructions.
|
||||
|
||||
### Contributing
|
||||
|
||||
Go is the work of hundreds of contributors. We appreciate your help!
|
||||
|
||||
To contribute, please read the contribution guidelines:
|
||||
https://golang.org/doc/contribute.html
|
||||
|
||||
##### Note that we do not accept pull requests and that we use the issue tracker for bug reports and proposals only. Please ask questions on https://forum.golangbridge.org or https://groups.google.com/forum/#!forum/golang-nuts.
|
||||
|
||||
Unless otherwise noted, the Go source files are distributed
|
||||
under the BSD-style license found in the LICENSE file.
|
||||
|
||||
--
|
||||
|
||||
## Binary Distribution Notes
|
||||
|
||||
If you have just untarred a binary Go distribution, you need to set
|
||||
the environment variable $GOROOT to the full path of the go
|
||||
directory (the one containing this file). You can omit the
|
||||
variable if you unpack it into /usr/local/go, or if you rebuild
|
||||
from sources by running all.bash (see doc/install-source.html).
|
||||
You should also add the Go binary directory $GOROOT/bin
|
||||
to your shell's path.
|
||||
|
||||
For example, if you extracted the tar file into $HOME/go, you might
|
||||
put the following in your .profile:
|
||||
|
||||
export GOROOT=$HOME/go
|
||||
export PATH=$PATH:$GOROOT/bin
|
||||
|
||||
See https://golang.org/doc/install or doc/install.html for more details.
|
||||
Note that the Go project does not use GitHub pull requests, and that
|
||||
we use the issue tracker for bug reports and proposals only. See
|
||||
https://golang.org/wiki/Questions for a list of places to ask
|
||||
questions about the Go language.
|
||||
|
||||
@@ -22,8 +22,6 @@ using the go <code>tool</code> subcommand, such as <code>go tool vet</code>.
|
||||
This style of invocation allows, for instance, checking a single source file
|
||||
rather than an entire package: <code>go tool vet myprogram.go</code> as
|
||||
compared to <code>go vet mypackage</code>.
|
||||
Some of the commands, such as <code>yacc</code>, are accessible only through
|
||||
the go <code>tool</code> subcommand.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -95,12 +93,6 @@ gofmt</a> command with more general options.</td>
|
||||
calls whose arguments do not align with the format string.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><a href="/cmd/yacc/">yacc</a></td>
|
||||
<td> </td>
|
||||
<td>Yacc is a version of yacc that generates parsers implemented in Go.</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -148,29 +148,26 @@ These actions are explicitly forbidden in Go spaces:
|
||||
|
||||
<p>
|
||||
The Go spaces are not free speech venues; they are for discussion about Go.
|
||||
These spaces have moderators.
|
||||
The goal of the moderators is to facilitate civil discussion about Go.
|
||||
Each of these spaces have their own moderators.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
When using the official Go spaces you should act in the spirit of the “Gopher
|
||||
values”.
|
||||
If you conduct yourself in a way that is explicitly forbidden by the CoC,
|
||||
you will be warned and asked to stop.
|
||||
If you do not stop, you will be removed from our community spaces temporarily.
|
||||
Repeated, willful breaches of the CoC will result in a permanent ban.
|
||||
If a reported conflict cannot be resolved amicably, the CoC Working Group
|
||||
may make a recommendation to the relevant forum moderators.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Moderators are held to a higher standard than other community members.
|
||||
If a moderator creates an inappropriate situation, they should expect less
|
||||
leeway than others, and should expect to be removed from their position if they
|
||||
cannot adhere to the CoC.
|
||||
CoC Working Group members and forum moderators are held to a higher standard than other community members.
|
||||
If a working group member or moderator creates an inappropriate situation, they
|
||||
should expect less leeway than others, and should expect to be removed from
|
||||
their position if they cannot adhere to the CoC.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Complaints about moderator actions must be handled using the reporting process
|
||||
below.
|
||||
Complaints about working group member or moderator actions must be handled
|
||||
using the reporting process below.
|
||||
</p>
|
||||
|
||||
<h2 id="reporting">Reporting issues</h2>
|
||||
@@ -185,8 +182,6 @@ satisfaction of all parties. They are:
|
||||
<ul>
|
||||
<li>Aditya Mukerjee <dev@chimeracoder.net>
|
||||
<li>Andrew Gerrand <adg@golang.org>
|
||||
<li>Dave Cheney <dave@cheney.net>
|
||||
<li>Jason Buberel <jbuberel@google.com>
|
||||
<li>Peggy Li <peggyli.224@gmail.com>
|
||||
<li>Sarah Adams <sadams.codes@gmail.com>
|
||||
<li>Steve Francia <steve.francia@gmail.com>
|
||||
@@ -201,13 +196,10 @@ particular individual or group.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>Mail <a href="mailto:conduct@golang.org">conduct@golang.org</a> or
|
||||
<a href="https://golang.org/s/conduct-report">submit an anonymous report</a>.
|
||||
<li>Mail <a href="mailto:conduct@golang.org">conduct@golang.org</a>.
|
||||
<ul>
|
||||
<li>Your message will reach the Working Group.
|
||||
<li>Reports are confidential within the Working Group.
|
||||
<li>Should you choose to remain anonymous then the Working Group cannot
|
||||
notify you of the outcome of your report.
|
||||
<li>You may contact a member of the group directly if you do not feel
|
||||
comfortable contacting the group as a whole. That member will then raise
|
||||
the issue with the Working Group as a whole, preserving the privacy of the
|
||||
@@ -229,11 +221,8 @@ particular individual or group.
|
||||
<li>The Working Group will reach a decision as to how to act. These may include:
|
||||
<ul>
|
||||
<li>Nothing.
|
||||
<li>A request for a private or public apology.
|
||||
<li>A private or public warning.
|
||||
<li>An imposed vacation (for instance, asking someone to abstain for a week
|
||||
from a mailing list or IRC).
|
||||
<li>A permanent or temporary ban from some or all Go spaces.
|
||||
<li>Passing the report along to the offender.
|
||||
<li>A recommendation of action to the relevant forum moderators.
|
||||
</ul>
|
||||
<li>The Working Group will reach out to the original reporter to let them know
|
||||
the decision.
|
||||
@@ -246,7 +235,6 @@ particular individual or group.
|
||||
conflicts in the most harmonious way possible.</b>
|
||||
We hope that in most cases issues may be resolved through polite discussion and
|
||||
mutual agreement.
|
||||
Bannings and other forceful measures are to be employed only as a last resort.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -34,6 +34,7 @@ We encourage all Go users to subscribe to
|
||||
<p>A <a href="/doc/devel/release.html">summary</a> of the changes between Go releases. Notes for the major releases:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="/doc/go1.8">Go 1.8</a> <small>(February 2017)</small></li>
|
||||
<li><a href="/doc/go1.7">Go 1.7</a> <small>(August 2016)</small></li>
|
||||
<li><a href="/doc/go1.6">Go 1.6</a> <small>(February 2016)</small></li>
|
||||
<li><a href="/doc/go1.5">Go 1.5</a> <small>(August 2015)</small></li>
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
<!--{
|
||||
"Title": "Contribution Guidelines"
|
||||
"Title": "Contribution Guide"
|
||||
}-->
|
||||
|
||||
<h2 id="Introduction">Introduction</h2>
|
||||
|
||||
<p>
|
||||
This document explains how to contribute changes to the Go project.
|
||||
It assumes you have followed the
|
||||
<a href="/doc/install/source">installation instructions</a> and
|
||||
have <a href="code.html">written and tested your code</a>.
|
||||
The Go project welcomes all contributors. The process of contributing
|
||||
to the Go project may be different than many projects you are used to.
|
||||
This document is intended as a guide to help you through the contribution
|
||||
process. This guide assumes you have a basic understanding of Git and Go.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -20,103 +18,54 @@ see <a href="gccgo_contribute.html">Contributing to gccgo</a>.)
|
||||
Sensitive security-related issues should be reported to <a href="mailto:security@golang.org">security@golang.org</a>.
|
||||
</p>
|
||||
|
||||
<h2 id="Design">Discuss your design</h2>
|
||||
<h1 id="contributor">Becoming a contributor</h1>
|
||||
|
||||
<p>
|
||||
The project welcomes submissions but please let everyone know what
|
||||
you're working on if you want to change or add to the Go repositories.
|
||||
Before you can contribute to the Go project you need to setup a few prerequisites.
|
||||
The Go project uses <a href="https://www.gerritcodereview.com/">Gerrit</a>, an open
|
||||
source online tool, to perform all code reviews.
|
||||
Gerrit uses your email address as a unique identifier.
|
||||
The Go project contributing flow is currently configured to work only with Google Accounts.
|
||||
You must go through the following process <em>prior to contributing</em>.
|
||||
You only need to do this once per Google Account.
|
||||
</p>
|
||||
|
||||
<h2 id="auth">Configure Git to use Gerrit</h2>
|
||||
<p>
|
||||
You'll need a web browser and a command line terminal.
|
||||
You should already have Git installed.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Before undertaking to write something new for the Go project,
|
||||
please <a href="https://golang.org/issue/new">file an issue</a>
|
||||
(or claim an <a href="https://golang.org/issues">existing issue</a>).
|
||||
Significant changes must go through the
|
||||
<a href="https://golang.org/s/proposal-process">change proposal process</a>
|
||||
before they can be accepted.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This process gives everyone a chance to validate the design,
|
||||
helps prevent duplication of effort,
|
||||
and ensures that the idea fits inside the goals for the language and tools.
|
||||
It also checks that the design is sound before code is written;
|
||||
the code review tool is not the place for high-level discussions.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
When planning work, please note that the Go project follows a
|
||||
<a href="https://golang.org/wiki/Go-Release-Cycle">six-month
|
||||
development cycle</a>. The latter half of each cycle is a three-month
|
||||
feature freeze during which only bug fixes and doc updates are accepted.
|
||||
New work cannot be submitted during a feature freeze.
|
||||
</p>
|
||||
|
||||
<h2 id="Testing">Testing redux</h2>
|
||||
|
||||
<p>
|
||||
You've <a href="code.html">written and tested your code</a>, but
|
||||
before sending code out for review, run all the tests for the whole
|
||||
tree to make sure the changes don't break other packages or programs:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ cd go/src
|
||||
$ ./all.bash
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
(To build under Windows use <code>all.bat</code>.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
After running for a while, the command should print
|
||||
"<code>ALL</code> <code>TESTS</code> <code>PASSED</code>".
|
||||
</p>
|
||||
|
||||
<h2 id="Code_review">Code review</h2>
|
||||
|
||||
<p>
|
||||
Changes to Go must be reviewed before they are accepted,
|
||||
no matter who makes the change.
|
||||
A custom git command called <code>git-codereview</code>,
|
||||
discussed below, helps manage the code review process through a Google-hosted
|
||||
<a href="https://go-review.googlesource.com/">instance</a> of the code review
|
||||
system called <a href="https://www.gerritcodereview.com/">Gerrit</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="auth">Set up authentication for code review</h3>
|
||||
|
||||
<p>
|
||||
Gerrit uses Google Accounts for authentication. If you don't have
|
||||
a Google Account, you can create an account which
|
||||
Gerrit uses Google Accounts for authentication.
|
||||
If you don't have a Google Account, you can create an account which
|
||||
<a href="https://www.google.com/accounts/NewAccount">includes
|
||||
a new Gmail email account</a> or create an account associated
|
||||
<a href="https://accounts.google.com/SignUpWithoutGmail">with your existing
|
||||
email address</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The email address associated with the Google Account you use will be recorded in
|
||||
the <a href="https://go.googlesource.com/go/+log/">change log</a>
|
||||
and in the <a href="/CONTRIBUTORS">contributors file</a>.
|
||||
</p>
|
||||
<h3>Step 1: Sign in to googlesource and generate a password</h3>
|
||||
|
||||
<p>
|
||||
To set up your account in Gerrit, visit
|
||||
<a href="https://go.googlesource.com">go.googlesource.com</a>
|
||||
Visit <a href="https://go.googlesource.com">go.googlesource.com</a>
|
||||
and click on "Generate Password" in the page's top right menu bar.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You will be redirected to accounts.google.com to sign in.
|
||||
</p>
|
||||
|
||||
<h3>Step 2: Run the provided script</h3>
|
||||
<p>
|
||||
Once signed in, you are returned back to go.googlesource.com to "Configure Git".
|
||||
Follow the instructions on the page.
|
||||
(If you are on a Windows computer, you should instead follow the instructions
|
||||
in the yellow box to run the command.)
|
||||
After signing in, you are taken to a page on go.googlesource.com with the title "Configure Git".
|
||||
This page contains a personalized script which when run locally will configure git
|
||||
to have your unique authentication key.
|
||||
This key is paired with one generated server side similar to how ssh keys work.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Copy and run this script locally in your command line terminal.
|
||||
(On a Windows computer using cmd you should instead follow the instructions
|
||||
in the yellow box to run the command. If you are using git-bash use the same
|
||||
script as *nix.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -124,23 +73,25 @@ Your secret authentication token is now in a <code>.gitcookie</code> file
|
||||
and Git is configured to use this file.
|
||||
</p>
|
||||
|
||||
<h3 id="gerrit">Register with Gerrit</h3>
|
||||
<h3 id="gerrit">Step 3: Register with Gerrit</h3>
|
||||
|
||||
<p>
|
||||
Now that you have your authentication token,
|
||||
you need to register your account with Gerrit.
|
||||
To do this, visit
|
||||
<a href="https://go-review.googlesource.com/login/">
|
||||
go-review.googlesource.com/login/</a>. You will immediately be redirected
|
||||
to Google Accounts. Sign in using the same Google Account you used above.
|
||||
That is all that is required.
|
||||
Now that you have your authentication token, you need to register your
|
||||
account with Gerrit.
|
||||
To do this, visit <a href="https://go-review.googlesource.com/login/">
|
||||
go-review.googlesource.com/login/</a>.
|
||||
Sign in using the same Google Account you used above.
|
||||
</p>
|
||||
|
||||
<h3 id="cla">Contributor License Agreement</h3>
|
||||
<h2 id="cla">Contributor License Agreement</h2>
|
||||
|
||||
<h3 id="which_cla">Which CLA</h3>
|
||||
<p>
|
||||
Before sending your first change to the Go project
|
||||
you must have completed one of the following two CLAs.
|
||||
Which CLA you should sign depends on who owns the copyright to your work.
|
||||
</p>
|
||||
|
||||
<p>Gerrit serves as the gatekeeper and uses your e-mail address as the key.
|
||||
To send your first change to the Go project from a given address,
|
||||
you must have completed one of the contributor license agreements:
|
||||
<ul>
|
||||
<li>
|
||||
If you are the copyright holder, you will need to agree to the
|
||||
@@ -151,37 +102,49 @@ contributor license agreement</a>, which can be completed online.
|
||||
If your organization is the copyright holder, the organization
|
||||
will need to agree to the
|
||||
<a href="https://developers.google.com/open-source/cla/corporate">corporate
|
||||
contributor license agreement</a>.
|
||||
(If the copyright holder for your code has already completed the
|
||||
agreement in connection with another Google open source project,
|
||||
it does not need to be completed again.)
|
||||
contributor license agreement</a>.<br>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
You can use the links above to create and sign the contributor license agreement
|
||||
or you can show your current agreements and create new ones through the Gerrit
|
||||
interface. <a href="https://go-review.googlesource.com/login/">Log into Gerrit</a>,
|
||||
<i>If the copyright holder for your contribution has already completed the
|
||||
agreement in connection with another Google open source project,
|
||||
it does not need to be completed again.</i>
|
||||
</p>
|
||||
|
||||
<h3 id="signing_cla">Completing the CLA</h3>
|
||||
|
||||
<p>
|
||||
You can see your currently signed agreements and sign new ones through the Gerrit
|
||||
interface.
|
||||
To do this, <a href="https://go-review.googlesource.com/login/">Log into Gerrit</a>,
|
||||
click your name in the upper-right, choose "Settings", then select "Agreements"
|
||||
from the topics on the left. If you do not have a signed agreement listed here,
|
||||
from the topics on the left.
|
||||
If you do not have a signed agreement listed here,
|
||||
you can create one by clicking "New Contributor Agreement" and following the steps.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This rigmarole only needs to be done for your first submission for each email address.
|
||||
If the copyright holder for the code you are submitting changes — for example,
|
||||
if you start contributing code on behalf of a new company — please send email
|
||||
to golang-dev and let us know, so that we can make sure an appropriate agreement is
|
||||
completed and update the <code>AUTHORS</code> file.
|
||||
</p>
|
||||
|
||||
<span id="Code_review"></span>
|
||||
<h1 id="prepare_dev_env">Preparing a Development Environment for Contributing</h1>
|
||||
|
||||
<h2 id="git-codereview">Setting up Git for submission to Gerrit</h2>
|
||||
<p>
|
||||
If the copyright holder for the code you are submitting changes—for example,
|
||||
if you start contributing code on behalf of a new company—please send email
|
||||
to let us know, so that we can make sure an appropriate agreement is completed
|
||||
and update the <code>AUTHORS</code> file.
|
||||
Changes to Go must be reviewed before they are accepted, no matter who makes the change.
|
||||
A custom git command called <code>git-codereview</code>, discussed below,
|
||||
helps manage the code review process through a Google-hosted
|
||||
<a href="https://go-review.googlesource.com/">instance</a> Gerrit.
|
||||
</p>
|
||||
|
||||
<h3 id="git-codereview">Install the git-codereview command</h3>
|
||||
|
||||
<h3 id="git-codereview_install">Install the git-codereview command</h3>
|
||||
<p>
|
||||
Now install the <code>git-codereview</code> command by running,
|
||||
Install the <code>git-codereview</code> command by running,
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
@@ -202,18 +165,28 @@ prints help text, not an error.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Note to Git aficionados:</b>
|
||||
The <code>git-codereview</code> command is not required to
|
||||
upload and manage Gerrit code reviews. For those who prefer plain Git, the text
|
||||
below gives the Git equivalent of each git-codereview command.
|
||||
On Windows, when using git-bash you must make sure that
|
||||
<code>git-codereview.exe</code> is in your git exec-path.
|
||||
Run <code>git --exec-path</code> to discover the right location then create a
|
||||
symbolic link or simply copy the executible from $GOPATH/bin to this directory.
|
||||
</p>
|
||||
|
||||
<p>If you do use plain
|
||||
Git, note that you still need the commit hooks that the git-codereview command
|
||||
configures; those hooks add a Gerrit <code>Change-Id</code> line to the commit
|
||||
message and check that all Go source files have been formatted with gofmt. Even
|
||||
if you intend to use plain Git for daily work, install the hooks in a new Git
|
||||
checkout by running <code>git-codereview</code> <code>hooks</code>.
|
||||
<p>
|
||||
<b>Note to Git aficionados:</b>
|
||||
The <code>git-codereview</code> command is not required to
|
||||
upload and manage Gerrit code reviews.
|
||||
For those who prefer plain Git, the text below gives the Git equivalent of
|
||||
each git-codereview command.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you do use plain Git, note that you still need the commit hooks that the
|
||||
git-codereview command configures; those hooks add a Gerrit
|
||||
<code>Change-Id</code> line to the commit message and check that all Go source
|
||||
files have been formatted with gofmt.
|
||||
Even if you intend to use plain Git for
|
||||
daily work, install the hooks in a new Git checkout by running
|
||||
<code>git-codereview</code> <code>hooks</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -264,7 +237,8 @@ To install them, copy this text into your Git configuration file
|
||||
sync = codereview sync
|
||||
</pre>
|
||||
|
||||
<h3 id="help">Understanding the git-codereview command</h3>
|
||||
<span id="help"></span>
|
||||
<h3 id="understanding_git-codereview">Understanding the git-codereview command</h3>
|
||||
|
||||
<p>After installing the <code>git-codereview</code> command, you can run</p>
|
||||
|
||||
@@ -277,11 +251,70 @@ to learn more about its commands.
|
||||
You can also read the <a href="https://godoc.org/golang.org/x/review/git-codereview">command documentation</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="master">Switch to the master branch</h3>
|
||||
|
||||
<h1 id="making_a_contribution">Making a Contribution</h1>
|
||||
|
||||
<h2 id="Design">Discuss your design</h2>
|
||||
|
||||
<p>
|
||||
The project welcomes submissions but please let everyone know what
|
||||
you're working on if you want to change or add to the Go repositories.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Before undertaking to write something new for the Go project,
|
||||
please <a href="https://golang.org/issue/new">file an issue</a>
|
||||
(or claim an <a href="https://golang.org/issues">existing issue</a>).
|
||||
Significant changes must go through the
|
||||
<a href="https://golang.org/s/proposal-process">change proposal process</a>
|
||||
before they can be accepted.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This process gives everyone a chance to validate the design,
|
||||
helps prevent duplication of effort,
|
||||
and ensures that the idea fits inside the goals for the language and tools.
|
||||
It also checks that the design is sound before code is written;
|
||||
the code review tool is not the place for high-level discussions.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
When planning work, please note that the Go project follows a <a
|
||||
href="https://golang.org/wiki/Go-Release-Cycle">six-month development cycle</a>.
|
||||
The latter half of each cycle is a three-month feature freeze during
|
||||
which only bug fixes and doc updates are accepted. New contributions can be
|
||||
sent during a feature freeze but will not be accepted until the freeze thaws.
|
||||
</p>
|
||||
|
||||
<h2 id="making_a_change">Making a change</h2>
|
||||
|
||||
<h3 id="checkout_go">Getting Go Source</h3>
|
||||
<p>
|
||||
First you need to have a local copy of the source checked out from the correct
|
||||
repository.
|
||||
As Go builds Go you will also likely need to have a working version
|
||||
of Go installed (some documentation changes may not need this).
|
||||
This should be a recent version of Go and can be obtained via any package or
|
||||
binary distribution or you can build it from source.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You should checkout the Go source repo anywhere you want as long as it's
|
||||
outside of your $GOPATH.
|
||||
Go to a directory where you want the source to appear and run the following
|
||||
command in a terminal.
|
||||
</p>
|
||||
|
||||
<pre><code>
|
||||
$ git clone https://go.googlesource.com/go
|
||||
$ cd go
|
||||
</code></pre>
|
||||
|
||||
<h3 id="master">Contributing to the main Go tree</h3>
|
||||
|
||||
<p>
|
||||
Most Go installations use a release branch, but new changes should
|
||||
only be made based on the master branch.
|
||||
only be made based on the master branch. <br>
|
||||
(They may be applied later to a release branch as part of the release process,
|
||||
but most contributors won't do this themselves.)
|
||||
Before making a change, make sure you start on the master branch:
|
||||
@@ -297,10 +330,61 @@ $ git sync
|
||||
<code>git</code> <code>pull</code> <code>-r</code>.)
|
||||
</p>
|
||||
|
||||
<h3 id="change">Make a change</h3>
|
||||
<h3 id="subrepos">Contributing to subrepositories (golang.org/x/...)</h3>
|
||||
|
||||
<p>
|
||||
If you are contributing a change to a subrepository, obtain the
|
||||
Go package using <code>go get</code>. For example, to contribute
|
||||
to <code>golang.org/x/oauth2</code>, check out the code by running:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ go get -d golang.org/x/oauth2/...
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Then, change your directory to the package's source directory
|
||||
(<code>$GOPATH/src/golang.org/x/oauth2</code>).
|
||||
</p>
|
||||
|
||||
<h3 id="change">Make your changes</h3>
|
||||
|
||||
<p>
|
||||
The entire checked-out tree is editable.
|
||||
Make your changes as you see fit ensuring that you create appropriate
|
||||
tests along with your changes. Test your changes as you go.
|
||||
</p>
|
||||
|
||||
<h3 id="copyright">Copyright</h3>
|
||||
|
||||
<p>
|
||||
Files in the Go repository don't list author names, both to avoid clutter
|
||||
and to avoid having to keep the lists up to date.
|
||||
Instead, your name will appear in the
|
||||
<a href="https://golang.org/change">change log</a> and in the <a
|
||||
href="/CONTRIBUTORS"><code>CONTRIBUTORS</code></a> file and perhaps the <a
|
||||
href="/AUTHORS"><code>AUTHORS</code></a> file.
|
||||
These files are automatically generated from the commit logs perodically.
|
||||
The <a href="/AUTHORS"><code>AUTHORS</code></a> file defines who “The Go
|
||||
Authors”—the copyright holders—are.
|
||||
</p>
|
||||
|
||||
<p>New files that you contribute should use the standard copyright header:</p>
|
||||
|
||||
<pre>
|
||||
// Copyright 2017 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.
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Files in the repository are copyright the year they are added.
|
||||
Do not update the copyright year on files that you change.
|
||||
</p>
|
||||
|
||||
<h3 id="commit_changes">Commit your changes</h3>
|
||||
|
||||
<p>
|
||||
The entire checked-out tree is writable.
|
||||
Once you have edited files, you must tell Git that they have been modified.
|
||||
You must also tell Git about any files that are added, removed, or renamed files.
|
||||
These operations are done with the usual Git commands,
|
||||
@@ -311,16 +395,19 @@ and
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you wish to checkpoint your work, or are ready to send the code out for review, run</p>
|
||||
Once you have the changes queued up, you will want to commit them.
|
||||
In the Go contribution workflow this is done with a `git change` command,
|
||||
which creates a local branch and commits the changes directly to that local branch.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ git change <i><branch></i>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
from any directory in your Go repository to commit the changes so far.
|
||||
The name <i><branch></i> is an arbitrary one you choose to identify the
|
||||
local branch containing your changes.
|
||||
local branch containing your changes and will not be used elsewhere.
|
||||
This is an offline operation and nothing will be sent to the server yet.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -331,9 +418,11 @@ then <code>git</code> <code>commit</code>.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Git will open a change description file in your editor.
|
||||
As the `git commit` is the final step, Git will open an editor to ask for a
|
||||
commit message.
|
||||
(It uses the editor named by the <code>$EDITOR</code> environment variable,
|
||||
<code>vi</code> by default.)
|
||||
|
||||
The file will look like:
|
||||
</p>
|
||||
|
||||
@@ -352,7 +441,7 @@ At the beginning of this file is a blank line; replace it
|
||||
with a thorough description of your change.
|
||||
The first line of the change description is conventionally a one-line
|
||||
summary of the change, prefixed by the primary affected package,
|
||||
and is used as the subject for code review mail.
|
||||
and is used as the subject for code review email.
|
||||
It should complete the sentence "This change modifies Go to _____."
|
||||
The rest of the description elaborates and should provide context for the
|
||||
change and explain what it does.
|
||||
@@ -395,7 +484,7 @@ the command and move that file to a different branch.
|
||||
<p>
|
||||
The special notation "Fixes #159" associates the change with issue 159 in the
|
||||
<a href="https://golang.org/issue/159">Go issue tracker</a>.
|
||||
When this change is eventually submitted, the issue
|
||||
When this change is eventually applied, the issue
|
||||
tracker will automatically mark the issue as fixed.
|
||||
(There are several such conventions, described in detail in the
|
||||
<a href="https://help.github.com/articles/closing-issues-via-commit-messages/">GitHub Issue Tracker documentation</a>.)
|
||||
@@ -406,6 +495,13 @@ Once you have finished writing the commit message,
|
||||
save the file and exit the editor.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You must have the $EDITOR environment variable set properly and working properly (exiting cleanly)
|
||||
for this operation to succeed.
|
||||
If you run into any issues at this step, it's likely your editor isn't exiting cleanly.
|
||||
Try setting a different editor in your $EDITOR environment variable.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you wish to do more editing, re-stage your changes using
|
||||
<code>git</code> <code>add</code>, and then run
|
||||
@@ -416,8 +512,8 @@ $ git change
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
to update the change description and incorporate the staged changes. The
|
||||
change description contains a <code>Change-Id</code> line near the bottom,
|
||||
to update the change description and incorporate the staged changes.
|
||||
The change description contains a <code>Change-Id</code> line near the bottom,
|
||||
added by a Git commit hook during the initial
|
||||
<code>git</code> <code>change</code>.
|
||||
That line is used by Gerrit to match successive uploads of the same change.
|
||||
@@ -429,35 +525,44 @@ Do not edit or delete it.
|
||||
runs <code>git</code> <code>commit</code> <code>--amend</code>.)
|
||||
</p>
|
||||
|
||||
<h3 id="mail">Mail the change for review</h3>
|
||||
<h3 id="Testing">Testing</h3>
|
||||
|
||||
<p>
|
||||
Once the change is ready, mail it out for review:
|
||||
You've <a href="code.html">written and tested your code</a>, but
|
||||
before sending code out for review, run all the tests for the whole
|
||||
tree to make sure the changes don't break other packages or programs:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ cd go/src
|
||||
$ ./all.bash
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
(To build under Windows use <code>all.bat</code>.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
After running for a while, the command should print
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
"ALL TESTS PASSED".
|
||||
</pre>
|
||||
|
||||
<h3 id="mail">Send the change for review</h3>
|
||||
|
||||
<p>
|
||||
Once the change is ready, send it for review.
|
||||
This is similar to a <code>git push</code> in a GitHub style workflow.
|
||||
This is done via the mail alias setup earlier which despite its name, doesn't
|
||||
directly mail anything, it simply sends the change to Gerrit via git push.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ git mail
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
You can specify a reviewer or CC interested parties
|
||||
using the <code>-r</code> or <code>-cc</code> options.
|
||||
Both accept a comma-separated list of email addresses:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ git mail -r joe@golang.org -cc mabel@example.com,math-nuts@swtch.com
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Unless explicitly told otherwise, such as in the discussion leading
|
||||
up to sending in the change list, it's better not to specify a reviewer.
|
||||
All changes are automatically CC'ed to the
|
||||
<a href="https://groups.google.com/group/golang-codereviews">golang-codereviews@googlegroups.com</a>
|
||||
mailing list. If this is your first ever change, there may be a moderation
|
||||
delay before it appears on the mailing list, to prevent spam.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
(In Git terms, <code>git</code> <code>mail</code> pushes the local committed
|
||||
changes to Gerrit using <code>git</code> <code>push</code> <code>origin</code>
|
||||
@@ -479,7 +584,76 @@ remote: New Changes:
|
||||
remote: https://go-review.googlesource.com/99999 math: improved Sin, Cos and Tan precision for very large arguments
|
||||
</pre>
|
||||
|
||||
<h3 id="review">Reviewing code</h3>
|
||||
<h3>Troubleshooting</h3>
|
||||
|
||||
<p>
|
||||
The most common way that the <code>git mail</code> command fails is because the
|
||||
email address used has not gone through the setup above.
|
||||
<br>
|
||||
If you see something like...
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
remote: Processing changes: refs: 1, done
|
||||
remote:
|
||||
remote: ERROR: In commit ab13517fa29487dcf8b0d48916c51639426c5ee9
|
||||
remote: ERROR: author email address XXXXXXXXXXXXXXXXXXX
|
||||
remote: ERROR: does not match your user account.
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
You need to either add the email address listed to the CLA or set this repo to use
|
||||
another email address already approved.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
First let's change the email address for this repo so this doesn't happen again.
|
||||
You can change your email address for this repo with the following command:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ git config user.email email@address.com
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Then change the previous commit to use this alternative email address.
|
||||
You can do that with:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ git commit --amend --author="Author Name <email@address.com>"
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Finally try to resend with:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ git mail
|
||||
</pre>
|
||||
|
||||
<h3 id="cc">Specifying a reviewer / CCing others</h3>
|
||||
|
||||
<p>
|
||||
Unless explicitly told otherwise, such as in the discussion leading
|
||||
up to sending in the change list, it's better not to specify a reviewer.
|
||||
All changes are automatically CC'ed to the
|
||||
<a href="https://groups.google.com/group/golang-codereviews">golang-codereviews@googlegroups.com</a>
|
||||
mailing list. If this is your first ever change, there may be a moderation
|
||||
delay before it appears on the mailing list, to prevent spam.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can specify a reviewer or CC interested parties
|
||||
using the <code>-r</code> or <code>-cc</code> options.
|
||||
Both accept a comma-separated list of email addresses:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ git mail -r joe@golang.org -cc mabel@example.com,math-nuts@swtch.com
|
||||
</pre>
|
||||
|
||||
<h2 id="review">Going through the review process</h2>
|
||||
|
||||
<p>
|
||||
Running <code>git</code> <code>mail</code> will send an email to you and the
|
||||
@@ -491,7 +665,15 @@ You must reply through the web interface.
|
||||
(Unlike with the old Rietveld review system, replying by mail has no effect.)
|
||||
</p>
|
||||
|
||||
<h3 id="revise">Revise and upload</h3>
|
||||
<h3 id="revise">Revise and resend</h3>
|
||||
|
||||
<p>
|
||||
The Go contribution workflow is optimized for iterative revisions based on
|
||||
feedback.
|
||||
It is rare that an initial contribution will be ready to be applied as is.
|
||||
As you revise your contribution and resend Gerrit will retain a history of
|
||||
all the changes and comments made in the single URL.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You must respond to review comments through the web interface.
|
||||
@@ -534,6 +716,8 @@ $ git sync
|
||||
<code>git</code> <code>pull</code> <code>-r</code>.)
|
||||
</p>
|
||||
|
||||
<h3 id="resolving_conflicts">Resolving Conflicts</h3>
|
||||
|
||||
<p>
|
||||
If files you were editing have changed, Git does its best to merge the
|
||||
remote changes into your local changes.
|
||||
@@ -609,8 +793,8 @@ might turn up:
|
||||
<p>
|
||||
Git doesn't show it, but suppose the original text that both edits
|
||||
started with was 1e8; you changed it to 1e10 and the other change to 1e9,
|
||||
so the correct answer might now be 1e10. First, edit the section
|
||||
to remove the markers and leave the correct code:
|
||||
so the correct answer might now be 1e10.
|
||||
First, edit the section to remove the markers and leave the correct code:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
@@ -639,10 +823,13 @@ restore the change commit.
|
||||
<h3 id="download">Reviewing code by others</h3>
|
||||
|
||||
<p>
|
||||
You can import a change proposed by someone else into your local Git repository.
|
||||
As part of the review process reviewers can propose changes directly (in the
|
||||
GitHub workflow this would be someone else attaching commits to a pull request).
|
||||
|
||||
You can import these changes proposed by someone else into your local Git repository.
|
||||
On the Gerrit review page, click the "Download ▼" link in the upper right
|
||||
corner, copy the "Checkout" command and run it from your local Git repo.
|
||||
It should look something like this:
|
||||
corner, copy the "Checkout" command and run it from your local Git repo. It
|
||||
should look something like this:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
@@ -653,11 +840,11 @@ $ git fetch https://go.googlesource.com/review refs/changes/21/1221/1 &&
|
||||
To revert, change back to the branch you were working in.
|
||||
</p>
|
||||
|
||||
<h3 id="submit">Submit the change after the review</h3>
|
||||
<h2 id="submit">Apply the change to the master branch</h2>
|
||||
|
||||
<p>
|
||||
After the code has been <code>LGTM</code>'ed, an approver may
|
||||
submit it to the master branch using the Gerrit UI.
|
||||
apply it to the master branch using the Gerrit UI.
|
||||
There is a "Submit" button on the web page for the change
|
||||
that appears once the change is approved (marked +2).
|
||||
</p>
|
||||
@@ -669,41 +856,13 @@ and the code review will be updated with a link to the change
|
||||
in the repository.
|
||||
Since the method used to integrate the changes is "Cherry Pick",
|
||||
the commit hashes in the repository will be changed by
|
||||
the submit operation.
|
||||
the "Submit" operation.
|
||||
</p>
|
||||
|
||||
<h3 id="more">More information</h3>
|
||||
<h2 id="more">More information</h2>
|
||||
|
||||
<p>
|
||||
In addition to the information here, the Go community maintains a <a href="https://golang.org/wiki/CodeReview">CodeReview</a> wiki page.
|
||||
In addition to the information here, the Go community maintains a <a
|
||||
href="https://golang.org/wiki/CodeReview">CodeReview</a> wiki page.
|
||||
Feel free to contribute to this page as you learn the review process.
|
||||
</p>
|
||||
|
||||
<h2 id="copyright">Copyright</h2>
|
||||
|
||||
<p>Files in the Go repository don't list author names,
|
||||
both to avoid clutter and to avoid having to keep the lists up to date.
|
||||
Instead, your name will appear in the
|
||||
<a href="https://golang.org/change">change log</a>
|
||||
and in the <a href="/CONTRIBUTORS"><code>CONTRIBUTORS</code></a> file
|
||||
and perhaps the <a href="/AUTHORS"><code>AUTHORS</code></a> file.
|
||||
</p>
|
||||
|
||||
<p>The <a href="/CONTRIBUTORS"><code>CONTRIBUTORS</code></a> file
|
||||
defines who the Go contributors—the people—are;
|
||||
the <a href="/AUTHORS"><code>AUTHORS</code></a> file defines
|
||||
who “The Go Authors”—the copyright holders—are.
|
||||
These files will be periodically updated based on the commit logs.
|
||||
|
||||
<p>Code that you contribute should use the standard copyright header:</p>
|
||||
|
||||
<pre>
|
||||
// Copyright 2016 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.
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Files in the repository are copyright the year they are added. It is not
|
||||
necessary to update the copyright year on files that you change.
|
||||
</p>
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
}-->
|
||||
|
||||
<p><i>
|
||||
This applies to the <code>gc</code> toolchain. Gccgo has native gdb support.
|
||||
This applies to the standard toolchain (the <code>gc</code> Go
|
||||
compiler and tools). Gccgo has native gdb support.
|
||||
Besides this overview you might want to consult the
|
||||
<a href="http://sourceware.org/gdb/current/onlinedocs/gdb/">GDB manual</a>.
|
||||
</i></p>
|
||||
@@ -49,6 +50,14 @@ when debugging, pass the flags <code>-gcflags "-N -l"</code> to the
|
||||
debugged.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you want to use gdb to inspect a core dump, you can trigger a dump
|
||||
on a program crash, on systems that permit it, by setting
|
||||
<code>GOTRACEBACK=crash</code> in the environment (see the
|
||||
<a href="/pkg/runtime/#hdr-Environment_Variables"> runtime package
|
||||
documentation</a> for more info).
|
||||
</p>
|
||||
|
||||
<h3 id="Common_Operations">Common Operations</h3>
|
||||
|
||||
<ul>
|
||||
@@ -130,7 +139,7 @@ the DWARF code.
|
||||
|
||||
<p>
|
||||
If you're interested in what the debugging information looks like, run
|
||||
'<code>objdump -W 6.out</code>' and browse through the <code>.debug_*</code>
|
||||
'<code>objdump -W a.out</code>' and browse through the <code>.debug_*</code>
|
||||
sections.
|
||||
</p>
|
||||
|
||||
@@ -377,7 +386,9 @@ $3 = struct hchan<*testing.T>
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
That <code>struct hchan<*testing.T></code> is the runtime-internal representation of a channel. It is currently empty, or gdb would have pretty-printed it's contents.
|
||||
That <code>struct hchan<*testing.T></code> is the
|
||||
runtime-internal representation of a channel. It is currently empty,
|
||||
or gdb would have pretty-printed its contents.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -30,6 +30,69 @@ to fix critical security problems in both Go 1.4 and Go 1.5 as they arise.
|
||||
See the <a href="/security">security policy</a> for more details.
|
||||
</p>
|
||||
|
||||
<h2 id="go1.8">go1.8 (released 2017/02/16)</h2>
|
||||
|
||||
<p>
|
||||
Go 1.8 is a major release of Go.
|
||||
Read the <a href="/doc/go1.8">Go 1.8 Release Notes</a> for more information.
|
||||
</p>
|
||||
|
||||
<h3 id="go1.8.minor">Minor revisions</h3>
|
||||
|
||||
<p>
|
||||
go1.8.1 (released 2017/04/07) includes fixes to the compiler, linker, runtime,
|
||||
documentation, <code>go</code> command and the <code>crypto/tls</code>,
|
||||
<code>encoding/xml</code>, <code>image/png</code>, <code>net</code>,
|
||||
<code>net/http</code>, <code>reflect</code>, <code>text/template</code>,
|
||||
and <code>time</code> packages.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.8.1">Go
|
||||
1.8.1 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.8.2 (released 2017/05/23) includes a security fix to the
|
||||
<code>crypto/elliptic</code> package.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.8.2">Go
|
||||
1.8.2 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.8.3 (released 2017/05/24) includes fixes to the compiler, runtime,
|
||||
documentation, and the <code>database/sql</code> package.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.8.3">Go
|
||||
1.8.3 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.8.4 (released 2017/10/04) includes two security fixes.
|
||||
It contains the same fixes as Go 1.9.1 and was released at the same time.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.8.4">Go
|
||||
1.8.4 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.8.5 (released 2017/10/25) includes fixes to the compiler, linker, runtime,
|
||||
documentation, <code>go</code> command,
|
||||
and the <code>crypto/x509</code> and <code>net/smtp</code> packages.
|
||||
It includes a fix to a bug introduced in Go 1.8.4 that broke <code>go</code> <code>get</code>
|
||||
of non-Git repositories under certain conditions.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.8.5">Go
|
||||
1.8.5 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.8.6 (released 2018/01/22) includes the the same fix in <code>math/big</code>
|
||||
as Go 1.9.3 and was released at the same time.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.8.6">Go
|
||||
1.8.6 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.8.7 (released 2018/02/07) includes a security fix to “go get”.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.8.7">Go
|
||||
1.8.7</a> milestone on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<h2 id="go1.7">go1.7 (released 2016/08/15)</h2>
|
||||
|
||||
<p>
|
||||
@@ -69,6 +132,20 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.7.4">Go
|
||||
1.7.4 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.7.5 (released 2017/01/26) includes fixes to the compiler, runtime,
|
||||
and the <code>crypto/x509</code> and <code>time</code> packages.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.7.5">Go
|
||||
1.7.5 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.7.6 (released 2017/05/23) includes the same security fix as Go 1.8.2 and
|
||||
was released at the same time.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.8.2">Go
|
||||
1.8.2 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<h2 id="go1.6">go1.6 (released 2016/02/17)</h2>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -52,6 +52,19 @@ user libraries. The Go 1.4 runtime is not fully merged, but that
|
||||
should not be visible to Go programs.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The GCC 6 releases include a complete implementation of the Go 1.6.1
|
||||
user libraries. The Go 1.6 runtime is not fully merged, but that
|
||||
should not be visible to Go programs.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The GCC 7 releases are expected to include a complete implementation
|
||||
of the Go 1.8 user libraries. As with earlier releases, the Go 1.8
|
||||
runtime is not fully merged, but that should not be visible to Go
|
||||
programs.
|
||||
</p>
|
||||
|
||||
<h2 id="Source_code">Source code</h2>
|
||||
|
||||
<p>
|
||||
@@ -160,23 +173,6 @@ make
|
||||
make install
|
||||
</pre>
|
||||
|
||||
<h3 id="Ubuntu">A note on Ubuntu</h3>
|
||||
|
||||
<p>
|
||||
Current versions of Ubuntu and versions of GCC before 4.8 disagree on
|
||||
where system libraries and header files are found. This is not a
|
||||
gccgo issue. When building older versions of GCC, setting these
|
||||
environment variables while configuring and building gccgo may fix the
|
||||
problem.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
LIBRARY_PATH=/usr/lib/x86_64-linux-gnu
|
||||
C_INCLUDE_PATH=/usr/include/x86_64-linux-gnu
|
||||
CPLUS_INCLUDE_PATH=/usr/include/x86_64-linux-gnu
|
||||
export LIBRARY_PATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH
|
||||
</pre>
|
||||
|
||||
<h2 id="Using_gccgo">Using gccgo</h2>
|
||||
|
||||
<p>
|
||||
@@ -364,12 +360,15 @@ or with C++ code compiled using <code>extern "C"</code>.
|
||||
<h3 id="Types">Types</h3>
|
||||
|
||||
<p>
|
||||
Basic types map directly: an <code>int</code> in Go is an <code>int</code>
|
||||
in C, an <code>int32</code> is an <code>int32_t</code>,
|
||||
etc. Go <code>byte</code> is equivalent to C <code>unsigned
|
||||
char</code>.
|
||||
Pointers in Go are pointers in C. A Go <code>struct</code> is the same as C
|
||||
<code>struct</code> with the same fields and types.
|
||||
Basic types map directly: an <code>int32</code> in Go is
|
||||
an <code>int32_t</code> in C, an <code>int64</code> is
|
||||
an <code>int64_t</code>, etc.
|
||||
The Go type <code>int</code> is an integer that is the same size as a
|
||||
pointer, and as such corresponds to the C type <code>intptr_t</code>.
|
||||
Go <code>byte</code> is equivalent to C <code>unsigned char</code>.
|
||||
Pointers in Go are pointers in C.
|
||||
A Go <code>struct</code> is the same as C <code>struct</code> with the
|
||||
same fields and types.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -380,7 +379,7 @@ structure (this is <b style="color: red;">subject to change</b>):
|
||||
<pre>
|
||||
struct __go_string {
|
||||
const unsigned char *__data;
|
||||
int __length;
|
||||
intptr_t __length;
|
||||
};
|
||||
</pre>
|
||||
|
||||
@@ -400,8 +399,8 @@ A slice in Go is a structure. The current definition is
|
||||
<pre>
|
||||
struct __go_slice {
|
||||
void *__values;
|
||||
int __count;
|
||||
int __capacity;
|
||||
intptr_t __count;
|
||||
intptr_t __capacity;
|
||||
};
|
||||
</pre>
|
||||
|
||||
@@ -526,15 +525,3 @@ This procedure is full of unstated caveats and restrictions and we make no
|
||||
guarantee that it will not change in the future. It is more useful as a
|
||||
starting point for real Go code than as a regular procedure.
|
||||
</p>
|
||||
|
||||
<h2 id="RTEMS_Port">RTEMS Port</h2>
|
||||
<p>
|
||||
The gccgo compiler has been ported to <a href="http://www.rtems.com/">
|
||||
<code>RTEMS</code></a>. <code>RTEMS</code> is a real-time executive
|
||||
that provides a high performance environment for embedded applications
|
||||
on a range of processors and embedded hardware. The current gccgo
|
||||
port is for x86. The goal is to extend the port to most of the
|
||||
<a href="http://www.rtems.org/wiki/index.php/SupportedCPUs">
|
||||
architectures supported by <code>RTEMS</code></a>. For more information on the port,
|
||||
as well as instructions on how to install it, please see this
|
||||
<a href="http://www.rtems.org/wiki/index.php/GCCGoRTEMS"><code>RTEMS</code> Wiki page</a>.
|
||||
|
||||
@@ -15,12 +15,7 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
ul li { margin: 0.5em 0; }
|
||||
</style>
|
||||
|
||||
<h2 id="introduction">DRAFT RELEASE NOTES - Introduction to Go 1.8</h2>
|
||||
|
||||
<p><strong>
|
||||
Go 1.8 is not yet released. These are work-in-progress
|
||||
release notes. Go 1.8 is expected to be released in February 2017.
|
||||
</strong></p>
|
||||
<h2 id="introduction">Introduction to Go 1.8</h2>
|
||||
|
||||
<p>
|
||||
The latest Go release, version 1.8, arrives six months after <a href="go1.7">Go 1.7</a>.
|
||||
@@ -93,7 +88,8 @@ On OpenBSD, Go now requires OpenBSD 5.9 or later. <!-- CL 34093 -->
|
||||
<p>
|
||||
The Plan 9 port's networking support is now much more complete
|
||||
and matches the behavior of Unix and Windows with respect to deadlines
|
||||
and cancelation.
|
||||
and cancelation. For Plan 9 kernel requirements, see the
|
||||
<a href="https://golang.org/wiki/Plan9">Plan 9 wiki page</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -434,11 +430,11 @@ version of gccgo.
|
||||
<h3 id="plugin">Plugins</h3>
|
||||
|
||||
<p>
|
||||
Go now supports a “<code>plugin</code>” build mode for generating
|
||||
plugins written in Go, and a
|
||||
Go now provides early support for plugins with a “<code>plugin</code>”
|
||||
build mode for generating plugins written in Go, and a
|
||||
new <a href="/pkg/plugin/"><code>plugin</code></a> package for
|
||||
loading such plugins at run time. Plugin support is only currently
|
||||
available on Linux.
|
||||
loading such plugins at run time. Plugin support is currently only
|
||||
available on Linux. Please report any issues.
|
||||
</p>
|
||||
|
||||
<h2 id="runtime">Runtime</h2>
|
||||
@@ -798,9 +794,9 @@ Optimizations and minor bug fixes are not listed.
|
||||
hardware support for AES-GCM is present.
|
||||
</p>
|
||||
|
||||
<p> <!-- CL 27315 -->
|
||||
<p> <!-- CL 27315, CL 35290 -->
|
||||
AES-128-CBC cipher suites with SHA-256 are also
|
||||
now supported.
|
||||
now supported, but disabled by default.
|
||||
</p>
|
||||
|
||||
</dd>
|
||||
@@ -808,11 +804,6 @@ Optimizations and minor bug fixes are not listed.
|
||||
|
||||
<dl id="crypto_x509"><dt><a href="/pkg/crypto/x509/">crypto/x509</a></dt>
|
||||
<dd>
|
||||
<p> <!-- CL 30578 -->
|
||||
<a href="/pkg/crypto/x509/#SystemCertPool"><code>SystemCertPool</code></a>
|
||||
is now implemented on Windows.
|
||||
</p>
|
||||
|
||||
<p> <!-- CL 24743 -->
|
||||
PSS signatures are now supported.
|
||||
</p>
|
||||
@@ -863,11 +854,12 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
|
||||
<p>
|
||||
The <a href="/pkg/database/sql#IsolationLevel"><code>IsolationLevel</code></a>
|
||||
can now be set when starting a transaction by setting the isolation level
|
||||
on the <code>Context</code> then passing that <code>Context</code> to
|
||||
<a href="/pkg/database/sql#DB.BeginContext"><code>DB.BeginContext</code></a>.
|
||||
on <a href="/pkg/database/sql#TxOptions.Isolation"><code>TxOptions.Isolation</code></a> and passing
|
||||
it to <a href="/pkg/database/sql#DB.BeginTx"><code>DB.BeginTx</code></a>.
|
||||
An error will be returned if an isolation level is selected that the driver
|
||||
does not support. A read-only attribute may also be set on the transaction
|
||||
with <a href="/pkg/database/sql/#ReadOnlyContext"><code>ReadOnlyContext</code></a>.
|
||||
by setting <a href="/pkg/database/sql/#TxOptions.ReadOnly"><code>TxOptions.ReadOnly</code></a>
|
||||
to true.
|
||||
</p>
|
||||
<p>
|
||||
Queries now expose the SQL column type information for drivers that support it.
|
||||
@@ -1312,7 +1304,7 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
|
||||
request must have the new
|
||||
<a href="/pkg/net/http/#Request"><code>Request.GetBody</code></a>
|
||||
field defined.
|
||||
<a href="pkg/net/http/#NewRequest"><code>NewRequest</code></a>
|
||||
<a href="/pkg/net/http/#NewRequest"><code>NewRequest</code></a>
|
||||
sets <code>Request.GetBody</code> automatically for common
|
||||
body types.
|
||||
</li>
|
||||
@@ -1617,9 +1609,9 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
|
||||
June 31 and July 32.
|
||||
</p>
|
||||
|
||||
<p> <!-- CL 33029 -->
|
||||
<p> <!-- CL 33029 --> <!-- CL 34816 -->
|
||||
The <code>tzdata</code> database has been updated to version
|
||||
2016i for systems that don't already have a local time zone
|
||||
2016j for systems that don't already have a local time zone
|
||||
database.
|
||||
</p>
|
||||
|
||||
@@ -1649,6 +1641,17 @@ crypto/x509: return error for missing SerialNumber (CL 27238)
|
||||
and only the overall execution of the test binary would fail.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 32455 -->
|
||||
The signature of the
|
||||
<a href="/pkg/testing/#MainStart"><code>MainStart</code></a>
|
||||
function has changed, as allowed by the documentation. It is an
|
||||
internal detail and not part of the Go 1 compatibility promise.
|
||||
If you're not calling <code>MainStart</code> directly but see
|
||||
errors, that likely means you set the
|
||||
normally-empty <code>GOROOT</code> environment variable and it
|
||||
doesn't match the version of your <code>go</code> command's binary.
|
||||
</p>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
This file lists things yet to be moved into go1.8.html or deemed too
|
||||
minor to mention. Either way, delete from here when done.
|
||||
|
||||
Tools:
|
||||
|
||||
go: -buildmode=c-archive now builds PIC on ELF (CL 24180)
|
||||
go: mobile pkg dir change, recommend using go list in scripts (CL 24930, CL 27929)
|
||||
go, dist: can set default pkg-config tool using PKG_CONFIG env var (CL 29991)
|
||||
go: can set secure/insecure GIT schemes using GIT_ALLOW_PROTOCOL env var (CL 30135)
|
||||
|
||||
API additions and behavior changes:
|
||||
|
||||
cmd/compile, runtime, etc: get rid of constant FP registers (CL 28095)
|
||||
cmd/compile, runtime: add go:yeswritebarrierrec pragma (CL 30938)
|
||||
cmd/compile/internal/gc: enable new parser by default (CL 27203)
|
||||
cmd/compile/internal/syntax: fast Go syntax trees, initial commit (CL 27195)
|
||||
cmd/compile: add compiler phase timing (CL 24462)
|
||||
cmd/compile: add inline explainer (CL 22782)
|
||||
cmd/compile: enable flag-specified dump of specific phase+function (CL 23044)
|
||||
|
||||
cmd/internal/obj, cmd/link: darwin dynlink support (CL 29393)
|
||||
cmd/internal/objfile: add ppc64/ppc64le disassembler support (CL 9682)
|
||||
cmd/link, cmd/go: delay linking of mingwex and mingw32 until very end (CL 26670)
|
||||
cmd/link: R_ADDR dynamic relocs for internal PIE (CL 29118)
|
||||
cmd/link: add trampolines for too far calls in ppc64x (CL 30850)
|
||||
cmd/link: allow internal PIE linking (CL 28543)
|
||||
cmd/link: fix -X importpath.name=value when import path needs escaping (CL 31970)
|
||||
cmd/link: fix -buildmode=pie / -linkshared combination (CL 28996)
|
||||
cmd/link: for -buildmode=exe pass -no-pie to external linker (CL 33106)
|
||||
cmd/link: insert trampolines for too-far jumps on ARM (CL 29397)
|
||||
cmd/link: non-executable stack support for Solaris (CL 24142)
|
||||
cmd/link: put text at address 0x1000000 on darwin/amd64 (CL 32185)
|
||||
cmd/link: remove the -shared flag (CL 28852)
|
||||
cmd/link: split large elf text sections on ppc64x (CL 27790)
|
||||
cmd/link: trampoline support for external linking on ARM (CL 31143)
|
||||
cmd/objdump: implement objdump of .o files (CL 24818)
|
||||
|
||||
go/build: allow % in ${SRCDIR} expansion for Jenkins (CL 31611)
|
||||
go/build: do not record go:binary-only-package if build tags not satisfied (CL 31577)
|
||||
go/build: implement default GOPATH (CL 32019)
|
||||
|
||||
runtime/race: update race runtime (CL 32160)
|
||||
runtime: assume 64kB physical pages on ARM (CL 25021)
|
||||
runtime: disable stack rescanning by default (CL 31766)
|
||||
runtime: don't call cgocallback from signal handler (CL 30218)
|
||||
runtime: fix check for vacuous page boundary rounding (CL 27230)
|
||||
runtime: fix map iterator concurrent map check (CL 24749)
|
||||
runtime: fix newextram PC passed to race detector (CL 29712)
|
||||
runtime: implement unconditional hybrid barrier (CL 31765)
|
||||
runtime: include pre-panic/throw logs in core dumps (CL 32013)
|
||||
runtime: limit the number of map overflow buckets (CL 25049)
|
||||
runtime: pass windows float syscall args via XMM (CL 32173)
|
||||
runtime: print sigcode on signal crash (CL 32183)
|
||||
runtime: record current PC for SIGPROF on non-Go thread (CL 30252)
|
||||
runtime: sleep on CLOCK_MONOTONIC in futexsleep1 on freebsd (CL 30154)
|
||||
@@ -143,10 +143,13 @@ packaged Go distribution.
|
||||
<p>
|
||||
To build a bootstrap tool chain from source, use
|
||||
either the git branch <code>release-branch.go1.4</code> or
|
||||
<a href="https://storage.googleapis.com/golang/go1.4-bootstrap-20161024.tar.gz">go1.4-bootstrap-20161024.tar.gz</a>,
|
||||
<a href="https://storage.googleapis.com/golang/go1.4-bootstrap-20170531.tar.gz">go1.4-bootstrap-20170531.tar.gz</a>,
|
||||
which contains the Go 1.4 source code plus accumulated fixes
|
||||
to keep the tools running on newer operating systems.
|
||||
(Go 1.4 was the last distribution in which the tool chain was written in C.)
|
||||
After unpacking the Go 1.4 source, <code>cd</code> to
|
||||
the <code>src</code> subdirectory and run <code>make.bash</code> (or,
|
||||
on Windows, <code>make.bat</code>).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@@ -218,7 +221,7 @@ To build without <code>cgo</code>, set the environment variable
|
||||
Change to the directory that will be its parent
|
||||
and make sure the <code>go</code> directory does not exist.
|
||||
Then clone the repository and check out the latest release tag
|
||||
(<code class="versionTag">go1.7.4</code>, for example):</p>
|
||||
(<code class="versionTag">go1.8.1</code>, for example):</p>
|
||||
|
||||
<pre>
|
||||
$ git clone https://go.googlesource.com/go
|
||||
@@ -406,7 +409,7 @@ New releases are announced on the
|
||||
<a href="//groups.google.com/group/golang-announce">golang-announce</a>
|
||||
mailing list.
|
||||
Each announcement mentions the latest release tag, for instance,
|
||||
<code class="versionTag">go1.7.4</code>.
|
||||
<code class="versionTag">go1.8.1</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -250,7 +250,7 @@ $ <b>cd $HOME/go/src/hello</b>
|
||||
$ <b>go build</b>
|
||||
</pre>
|
||||
|
||||
<pre class="testWindows" style="display: none">
|
||||
<pre class="testWindows">
|
||||
C:\> <b>cd %USERPROFILE%\go\src\hello</b>
|
||||
C:\Users\Gopher\go\src\hello> <b>go build</b>
|
||||
</pre>
|
||||
@@ -267,7 +267,7 @@ $ <b>./hello</b>
|
||||
hello, world
|
||||
</pre>
|
||||
|
||||
<pre class="testWindows" style="display: none">
|
||||
<pre class="testWindows">
|
||||
C:\Users\Gopher\go\src\hello> <b>hello</b>
|
||||
hello, world
|
||||
</pre>
|
||||
|
||||
144
doc/root.html
144
doc/root.html
@@ -6,7 +6,9 @@
|
||||
<div class="left">
|
||||
|
||||
<div id="learn">
|
||||
{{if not $.GoogleCN}}
|
||||
<a class="popout share">Pop-out</a>
|
||||
{{end}}
|
||||
<div class="rootHeading">Try Go</div>
|
||||
<div class="input">
|
||||
<textarea spellcheck="false" class="code">// You can edit this code!
|
||||
@@ -26,10 +28,10 @@ Hello, 世界
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<a class="run" href="#" title="Run this code [shift-enter]">Run</a>
|
||||
{{if $.Share}}
|
||||
{{if not $.GoogleCN}}
|
||||
<a class="share" href="#" title="Share this code">Share</a>
|
||||
{{end}}
|
||||
<a class="tour" href="//tour.golang.org/" title="Learn Go from your browser">Tour</a>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="toys">
|
||||
<select>
|
||||
@@ -68,85 +70,91 @@ Linux, Mac OS X, Windows, and more.
|
||||
|
||||
<div style="clear: both"></div>
|
||||
|
||||
{{if not $.GoogleCN}}
|
||||
<div class="left">
|
||||
|
||||
<div id="video">
|
||||
<div class="rootHeading">Featured video</div>
|
||||
<iframe width="415" height="241" src="//www.youtube.com/embed/ytEkHepK08c" frameborder="0" allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
<div id="video">
|
||||
<div class="rootHeading">Featured video</div>
|
||||
<iframe width="415" height="241" src="//www.youtube.com/embed/ytEkHepK08c" frameborder="0" allowfullscreen></iframe>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="right">
|
||||
|
||||
<div id="blog">
|
||||
<div class="rootHeading">Featured articles</div>
|
||||
<div class="read"><a href="//blog.golang.org/">Read more</a></div>
|
||||
</div>
|
||||
|
||||
<div id="blog">
|
||||
<div class="rootHeading">Featured articles</div>
|
||||
<div class="read"><a href="//blog.golang.org/">Read more</a></div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<div style="clear: both;"></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
<script>
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
function readableTime(t) {
|
||||
var m = ["January", "February", "March", "April", "May", "June", "July",
|
||||
"August", "September", "October", "November", "December"];
|
||||
var p = t.substring(0, t.indexOf("T")).split("-");
|
||||
var d = new Date(p[0], p[1]-1, p[2]);
|
||||
return d.getDate() + " " + m[d.getMonth()] + " " + d.getFullYear();
|
||||
}
|
||||
window.initFuncs.push(function() {
|
||||
// Set up playground if enabled.
|
||||
if (window.playground) {
|
||||
window.playground({
|
||||
"codeEl": "#learn .code",
|
||||
"outputEl": "#learn .output",
|
||||
"runEl": "#learn .run",
|
||||
"shareEl": "#learn .share",
|
||||
"shareRedirect": "//play.golang.org/p/",
|
||||
"toysEl": "#learn .toys select"
|
||||
});
|
||||
} else {
|
||||
$('#learn').hide()
|
||||
}
|
||||
});
|
||||
|
||||
function feedLoaded(result) {
|
||||
var blog = document.getElementById("blog");
|
||||
var read = blog.getElementsByClassName("read")[0];
|
||||
for (var i = 0; i < result.length && i < 2; i++) {
|
||||
var entry = result[i];
|
||||
var title = document.createElement("a");
|
||||
title.className = "title";
|
||||
title.href = entry.Link;
|
||||
title.innerHTML = entry.Title;
|
||||
blog.insertBefore(title, read);
|
||||
var extract = document.createElement("div");
|
||||
extract.className = "extract";
|
||||
extract.innerHTML = entry.Summary;
|
||||
blog.insertBefore(extract, read);
|
||||
var when = document.createElement("div");
|
||||
when.className = "when";
|
||||
when.innerHTML = "Published " + readableTime(entry.Time);
|
||||
blog.insertBefore(when, read);
|
||||
}
|
||||
}
|
||||
{{if not $.GoogleCN}}
|
||||
|
||||
window.initFuncs.push(function() {
|
||||
// Set up playground if enabled.
|
||||
if (window.playground) {
|
||||
window.playground({
|
||||
"codeEl": "#learn .code",
|
||||
"outputEl": "#learn .output",
|
||||
"runEl": "#learn .run",
|
||||
"shareEl": "#learn .share",
|
||||
"shareRedirect": "//play.golang.org/p/",
|
||||
"toysEl": "#learn .toys select"
|
||||
});
|
||||
} else {
|
||||
$('#learn').hide()
|
||||
function readableTime(t) {
|
||||
var m = ["January", "February", "March", "April", "May", "June", "July",
|
||||
"August", "September", "October", "November", "December"];
|
||||
var p = t.substring(0, t.indexOf("T")).split("-");
|
||||
var d = new Date(p[0], p[1]-1, p[2]);
|
||||
return d.getDate() + " " + m[d.getMonth()] + " " + d.getFullYear();
|
||||
}
|
||||
|
||||
// Load blog feed.
|
||||
$('<script/>').attr('text', 'text/javascript')
|
||||
.attr('src', '//blog.golang.org/.json?jsonp=feedLoaded')
|
||||
.appendTo('body');
|
||||
window.feedLoaded = function(result) {
|
||||
var blog = document.getElementById("blog");
|
||||
var read = blog.getElementsByClassName("read")[0];
|
||||
for (var i = 0; i < result.length && i < 2; i++) {
|
||||
var entry = result[i];
|
||||
var title = document.createElement("a");
|
||||
title.className = "title";
|
||||
title.href = entry.Link;
|
||||
title.innerHTML = entry.Title;
|
||||
blog.insertBefore(title, read);
|
||||
var extract = document.createElement("div");
|
||||
extract.className = "extract";
|
||||
extract.innerHTML = entry.Summary;
|
||||
blog.insertBefore(extract, read);
|
||||
var when = document.createElement("div");
|
||||
when.className = "when";
|
||||
when.innerHTML = "Published " + readableTime(entry.Time);
|
||||
blog.insertBefore(when, read);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the video at random.
|
||||
var videos = [
|
||||
{h: 241, s: "//www.youtube.com/embed/ytEkHepK08c"}, // Tour of Go
|
||||
{h: 241, s: "//www.youtube.com/embed/f6kdp27TYZs"}, // Concurrency Patterns
|
||||
{h: 233, s: "//player.vimeo.com/video/69237265"} // Simple environment
|
||||
];
|
||||
var v = videos[Math.floor(Math.random()*videos.length)];
|
||||
$('#video iframe').attr('height', v.h).attr('src', v.s);
|
||||
});
|
||||
window.initFuncs.push(function() {
|
||||
// Load blog feed.
|
||||
$('<script/>').attr('text', 'text/javascript')
|
||||
.attr('src', '//blog.golang.org/.json?jsonp=feedLoaded')
|
||||
.appendTo('body');
|
||||
|
||||
// Set the video at random.
|
||||
var videos = [
|
||||
{h: 241, s: "//www.youtube.com/embed/ytEkHepK08c"}, // Tour of Go
|
||||
{h: 241, s: "//www.youtube.com/embed/f6kdp27TYZs"}, // Concurrency Patterns
|
||||
{h: 233, s: "//player.vimeo.com/video/69237265"} // Simple environment
|
||||
];
|
||||
var v = videos[Math.floor(Math.random()*videos.length)];
|
||||
$('#video iframe').attr('height', v.h).attr('src', v.s);
|
||||
});
|
||||
|
||||
{{end}}
|
||||
})();
|
||||
</script>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
package main
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -c
|
||||
#cgo LDFLAGS: -L/nonexist
|
||||
|
||||
void test() {
|
||||
xxx; // ERROR HERE
|
||||
|
||||
@@ -73,7 +73,7 @@ func test18146(t *testing.T) {
|
||||
}
|
||||
runtime.GOMAXPROCS(threads)
|
||||
argv := append(os.Args, "-test.run=NoSuchTestExists")
|
||||
if err := syscall.Exec(os.Args[0], argv, nil); err != nil {
|
||||
if err := syscall.Exec(os.Args[0], argv, os.Environ()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ package cgotest
|
||||
static stack_t oss;
|
||||
static char signalStack[SIGSTKSZ];
|
||||
|
||||
static void changeSignalStack() {
|
||||
static void changeSignalStack(void) {
|
||||
stack_t ss;
|
||||
memset(&ss, 0, sizeof ss);
|
||||
ss.ss_sp = signalStack;
|
||||
@@ -29,7 +29,7 @@ static void changeSignalStack() {
|
||||
}
|
||||
}
|
||||
|
||||
static void restoreSignalStack() {
|
||||
static void restoreSignalStack(void) {
|
||||
#if (defined(__x86_64__) || defined(__i386__)) && defined(__APPLE__)
|
||||
// The Darwin C library enforces a minimum that the kernel does not.
|
||||
// This is OK since we allocated this much space in mpreinit,
|
||||
@@ -42,7 +42,7 @@ static void restoreSignalStack() {
|
||||
}
|
||||
}
|
||||
|
||||
static int zero() {
|
||||
static int zero(void) {
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -179,6 +179,13 @@ if test "$output" != "PASS"; then
|
||||
status=1
|
||||
fi
|
||||
|
||||
if test "$libext" = "dylib"; then
|
||||
# make sure dylibs are well-formed
|
||||
if ! otool -l libgo*.dylib >/dev/null; then
|
||||
status=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if test $status = 0; then
|
||||
echo "ok"
|
||||
fi
|
||||
|
||||
46
misc/cgo/testplugin/src/iface/main.go
Normal file
46
misc/cgo/testplugin/src/iface/main.go
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"iface_i"
|
||||
"log"
|
||||
"plugin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
a, err := plugin.Open("iface_a.so")
|
||||
if err != nil {
|
||||
log.Fatalf(`plugin.Open("iface_a.so"): %v`, err)
|
||||
}
|
||||
b, err := plugin.Open("iface_b.so")
|
||||
if err != nil {
|
||||
log.Fatalf(`plugin.Open("iface_b.so"): %v`, err)
|
||||
}
|
||||
|
||||
af, err := a.Lookup("F")
|
||||
if err != nil {
|
||||
log.Fatalf(`a.Lookup("F") failed: %v`, err)
|
||||
}
|
||||
bf, err := b.Lookup("F")
|
||||
if err != nil {
|
||||
log.Fatalf(`b.Lookup("F") failed: %v`, err)
|
||||
}
|
||||
if af.(func() interface{})() != bf.(func() interface{})() {
|
||||
panic("empty interfaces not equal")
|
||||
}
|
||||
|
||||
ag, err := a.Lookup("G")
|
||||
if err != nil {
|
||||
log.Fatalf(`a.Lookup("G") failed: %v`, err)
|
||||
}
|
||||
bg, err := b.Lookup("G")
|
||||
if err != nil {
|
||||
log.Fatalf(`b.Lookup("G") failed: %v`, err)
|
||||
}
|
||||
if ag.(func() iface_i.I)() != bg.(func() iface_i.I)() {
|
||||
panic("nonempty interfaces not equal")
|
||||
}
|
||||
}
|
||||
17
misc/cgo/testplugin/src/iface_a/a.go
Normal file
17
misc/cgo/testplugin/src/iface_a/a.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import "iface_i"
|
||||
|
||||
//go:noinline
|
||||
func F() interface{} {
|
||||
return (*iface_i.T)(nil)
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func G() iface_i.I {
|
||||
return (*iface_i.T)(nil)
|
||||
}
|
||||
17
misc/cgo/testplugin/src/iface_b/b.go
Normal file
17
misc/cgo/testplugin/src/iface_b/b.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import "iface_i"
|
||||
|
||||
//go:noinline
|
||||
func F() interface{} {
|
||||
return (*iface_i.T)(nil)
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func G() iface_i.I {
|
||||
return (*iface_i.T)(nil)
|
||||
}
|
||||
17
misc/cgo/testplugin/src/iface_i/i.go
Normal file
17
misc/cgo/testplugin/src/iface_i/i.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2017 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 iface_i
|
||||
|
||||
type I interface {
|
||||
M()
|
||||
}
|
||||
|
||||
type T struct {
|
||||
}
|
||||
|
||||
func (t *T) M() {
|
||||
}
|
||||
|
||||
// *T implements I
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright 2017 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 dynamodbstreamsevt
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
var foo json.RawMessage
|
||||
|
||||
type Event struct{}
|
||||
|
||||
func (e *Event) Dummy() {}
|
||||
31
misc/cgo/testplugin/src/issue18676/main.go
Normal file
31
misc/cgo/testplugin/src/issue18676/main.go
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
// The bug happened like this:
|
||||
// 1) The main binary adds an itab for *json.UnsupportedValueError / error
|
||||
// (concrete type / interface type). This itab goes in hash bucket 0x111.
|
||||
// 2) The plugin adds that same itab again. That makes a cycle in the itab
|
||||
// chain rooted at hash bucket 0x111.
|
||||
// 3) The main binary then asks for the itab for *dynamodbstreamsevt.Event /
|
||||
// json.Unmarshaler. This itab happens to also live in bucket 0x111.
|
||||
// The lookup code goes into an infinite loop searching for this itab.
|
||||
// The code is carefully crafted so that the two itabs are both from the
|
||||
// same bucket, and so that the second itab doesn't exist in
|
||||
// the itab hashmap yet (so the entire linked list must be searched).
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"issue18676/dynamodbstreamsevt"
|
||||
"plugin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
plugin.Open("plugin.so")
|
||||
|
||||
var x interface{} = (*dynamodbstreamsevt.Event)(nil)
|
||||
if _, ok := x.(json.Unmarshaler); !ok {
|
||||
println("something")
|
||||
}
|
||||
}
|
||||
11
misc/cgo/testplugin/src/issue18676/plugin.go
Normal file
11
misc/cgo/testplugin/src/issue18676/plugin.go
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import "C"
|
||||
|
||||
import "issue18676/dynamodbstreamsevt"
|
||||
|
||||
func F(evt *dynamodbstreamsevt.Event) {}
|
||||
@@ -15,8 +15,8 @@ goos=$(go env GOOS)
|
||||
goarch=$(go env GOARCH)
|
||||
|
||||
function cleanup() {
|
||||
rm -f plugin*.so unnamed*.so
|
||||
rm -rf host pkg sub
|
||||
rm -f plugin*.so unnamed*.so iface*.so
|
||||
rm -rf host pkg sub iface issue18676
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
@@ -32,3 +32,15 @@ GOPATH=$(pwd) go build -buildmode=plugin unnamed2.go
|
||||
GOPATH=$(pwd) go build host
|
||||
|
||||
LD_LIBRARY_PATH=$(pwd) ./host
|
||||
|
||||
# Test that types and itabs get properly uniqified.
|
||||
GOPATH=$(pwd) go build -buildmode=plugin iface_a
|
||||
GOPATH=$(pwd) go build -buildmode=plugin iface_b
|
||||
GOPATH=$(pwd) go build iface
|
||||
LD_LIBRARY_PATH=$(pwd) ./iface
|
||||
|
||||
# Test for issue 18676 - make sure we don't add the same itab twice.
|
||||
# The buggy code hangs forever, so use a timeout to check for that.
|
||||
GOPATH=$(pwd) go build -buildmode=plugin -o plugin.so src/issue18676/plugin.go
|
||||
GOPATH=$(pwd) go build -o issue18676 src/issue18676/main.go
|
||||
timeout 10s ./issue18676
|
||||
|
||||
12
misc/cgo/testsanitizers/msan_shared.go
Normal file
12
misc/cgo/testsanitizers/msan_shared.go
Normal file
@@ -0,0 +1,12 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
// This program segfaulted during libpreinit when built with -msan:
|
||||
// http://golang.org/issue/18707
|
||||
|
||||
package main
|
||||
|
||||
import "C"
|
||||
|
||||
func main() {}
|
||||
@@ -68,6 +68,25 @@ fi
|
||||
|
||||
status=0
|
||||
|
||||
testmsanshared() {
|
||||
goos=$(go env GOOS)
|
||||
suffix="-installsuffix testsanitizers"
|
||||
libext="so"
|
||||
if [ "$goos" == "darwin" ]; then
|
||||
libext="dylib"
|
||||
fi
|
||||
go build -msan -buildmode=c-shared $suffix -o ${TMPDIR}/libmsanshared.$libext msan_shared.go
|
||||
|
||||
echo 'int main() { return 0; }' > ${TMPDIR}/testmsanshared.c
|
||||
$CC $(go env GOGCCFLAGS) -fsanitize=memory -o ${TMPDIR}/testmsanshared ${TMPDIR}/testmsanshared.c ${TMPDIR}/libmsanshared.$libext
|
||||
|
||||
if ! LD_LIBRARY_PATH=. ${TMPDIR}/testmsanshared; then
|
||||
echo "FAIL: msan_shared"
|
||||
status=1
|
||||
fi
|
||||
rm -f ${TMPDIR}/{testmsanshared,testmsanshared.c,libmsanshared.$libext}
|
||||
}
|
||||
|
||||
if test "$msan" = "yes"; then
|
||||
if ! go build -msan std; then
|
||||
echo "FAIL: build -msan std"
|
||||
@@ -108,6 +127,8 @@ if test "$msan" = "yes"; then
|
||||
echo "FAIL: msan_fail"
|
||||
status=1
|
||||
fi
|
||||
|
||||
testmsanshared
|
||||
fi
|
||||
|
||||
if test "$tsan" = "yes"; then
|
||||
|
||||
@@ -815,3 +815,14 @@ func TestImplicitInclusion(t *testing.T) {
|
||||
goCmd(t, "install", "-linkshared", "implicitcmd")
|
||||
run(t, "running executable linked against library that contains same package as it", "./bin/implicitcmd")
|
||||
}
|
||||
|
||||
// Tests to make sure that the type fields of empty interfaces and itab
|
||||
// fields of nonempty interfaces are unique even across modules,
|
||||
// so that interface equality works correctly.
|
||||
func TestInterface(t *testing.T) {
|
||||
goCmd(t, "install", "-buildmode=shared", "-linkshared", "iface_a")
|
||||
// Note: iface_i gets installed implicitly as a dependency of iface_a.
|
||||
goCmd(t, "install", "-buildmode=shared", "-linkshared", "iface_b")
|
||||
goCmd(t, "install", "-linkshared", "iface")
|
||||
run(t, "running type/itab uniqueness tester", "./bin/iface")
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var SlicePtr interface{} = &[]int{}
|
||||
|
||||
var V int = 1
|
||||
|
||||
var HasMask []string = []string{"hi"}
|
||||
|
||||
@@ -19,6 +19,8 @@ func F() *C {
|
||||
return nil
|
||||
}
|
||||
|
||||
var slicePtr interface{} = &[]int{}
|
||||
|
||||
func main() {
|
||||
defer depBase.ImplementedInAsm()
|
||||
// This code below causes various go.itab.* symbols to be generated in
|
||||
@@ -32,4 +34,11 @@ func main() {
|
||||
if reflect.TypeOf(F).Out(0) != reflect.TypeOf(c) {
|
||||
panic("bad reflection results, see golang.org/issue/18252")
|
||||
}
|
||||
|
||||
sp := reflect.New(reflect.TypeOf(slicePtr).Elem())
|
||||
s := sp.Interface()
|
||||
|
||||
if reflect.TypeOf(s) != reflect.TypeOf(slicePtr) {
|
||||
panic("bad reflection results, see golang.org/issue/18729")
|
||||
}
|
||||
}
|
||||
|
||||
17
misc/cgo/testshared/src/iface/main.go
Normal file
17
misc/cgo/testshared/src/iface/main.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import "iface_a"
|
||||
import "iface_b"
|
||||
|
||||
func main() {
|
||||
if iface_a.F() != iface_b.F() {
|
||||
panic("empty interfaces not equal")
|
||||
}
|
||||
if iface_a.G() != iface_b.G() {
|
||||
panic("non-empty interfaces not equal")
|
||||
}
|
||||
}
|
||||
17
misc/cgo/testshared/src/iface_a/a.go
Normal file
17
misc/cgo/testshared/src/iface_a/a.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2017 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 iface_a
|
||||
|
||||
import "iface_i"
|
||||
|
||||
//go:noinline
|
||||
func F() interface{} {
|
||||
return (*iface_i.T)(nil)
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func G() iface_i.I {
|
||||
return (*iface_i.T)(nil)
|
||||
}
|
||||
17
misc/cgo/testshared/src/iface_b/b.go
Normal file
17
misc/cgo/testshared/src/iface_b/b.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2017 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 iface_b
|
||||
|
||||
import "iface_i"
|
||||
|
||||
//go:noinline
|
||||
func F() interface{} {
|
||||
return (*iface_i.T)(nil)
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func G() iface_i.I {
|
||||
return (*iface_i.T)(nil)
|
||||
}
|
||||
17
misc/cgo/testshared/src/iface_i/i.go
Normal file
17
misc/cgo/testshared/src/iface_i/i.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2017 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 iface_i
|
||||
|
||||
type I interface {
|
||||
M()
|
||||
}
|
||||
|
||||
type T struct {
|
||||
}
|
||||
|
||||
func (t *T) M() {
|
||||
}
|
||||
|
||||
// *T implements I
|
||||
@@ -99,7 +99,7 @@ func main() {
|
||||
// Approximately 1 in a 100 binaries fail to start. If it happens,
|
||||
// try again. These failures happen for several reasons beyond
|
||||
// our control, but all of them are safe to retry as they happen
|
||||
// before lldb encounters the initial getwd breakpoint. As we
|
||||
// before lldb encounters the initial SIGUSR2 stop. As we
|
||||
// know the tests haven't started, we are not hiding flaky tests
|
||||
// with this retry.
|
||||
for i := 0; i < 5; i++ {
|
||||
@@ -204,6 +204,11 @@ func run(bin string, args []string) (err error) {
|
||||
var opts options
|
||||
opts, args = parseArgs(args)
|
||||
|
||||
// Pass the suffix for the current working directory as the
|
||||
// first argument to the test. For iOS, cmd/go generates
|
||||
// special handling of this argument.
|
||||
args = append([]string{"cwdSuffix=" + pkgpath}, args...)
|
||||
|
||||
// ios-deploy invokes lldb to give us a shell session with the app.
|
||||
s, err := newSession(appdir, args, opts)
|
||||
if err != nil {
|
||||
@@ -224,6 +229,7 @@ func run(bin string, args []string) (err error) {
|
||||
s.do(`process handle SIGHUP --stop false --pass true --notify false`)
|
||||
s.do(`process handle SIGPIPE --stop false --pass true --notify false`)
|
||||
s.do(`process handle SIGUSR1 --stop false --pass true --notify false`)
|
||||
s.do(`process handle SIGUSR2 --stop true --pass false --notify true`) // sent by test harness
|
||||
s.do(`process handle SIGCONT --stop false --pass true --notify false`)
|
||||
s.do(`process handle SIGSEGV --stop false --pass true --notify false`) // does not work
|
||||
s.do(`process handle SIGBUS --stop false --pass true --notify false`) // does not work
|
||||
@@ -236,20 +242,9 @@ func run(bin string, args []string) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
s.do(`breakpoint set -n getwd`) // in runtime/cgo/gcc_darwin_arm.go
|
||||
|
||||
started = true
|
||||
|
||||
s.doCmd("run", "stop reason = breakpoint", 20*time.Second)
|
||||
|
||||
// Move the current working directory into the faux gopath.
|
||||
if pkgpath != "src" {
|
||||
s.do(`breakpoint delete 1`)
|
||||
s.do(`expr char* $mem = (char*)malloc(512)`)
|
||||
s.do(`expr $mem = (char*)getwd($mem, 512)`)
|
||||
s.do(`expr $mem = (char*)strcat($mem, "/` + pkgpath + `")`)
|
||||
s.do(`call (void)chdir($mem)`)
|
||||
}
|
||||
s.doCmd("run", "stop reason = signal SIGUSR2", 20*time.Second)
|
||||
|
||||
startTestsLen := s.out.Len()
|
||||
fmt.Fprintln(s.in, `process continue`)
|
||||
@@ -520,13 +515,11 @@ func copyLocalData(dstbase string) (pkgpath string, err error) {
|
||||
|
||||
// Copy timezone file.
|
||||
//
|
||||
// Typical apps have the zoneinfo.zip in the root of their app bundle,
|
||||
// Apps have the zoneinfo.zip in the root of their app bundle,
|
||||
// read by the time package as the working directory at initialization.
|
||||
// As we move the working directory to the GOROOT pkg directory, we
|
||||
// install the zoneinfo.zip file in the pkgpath.
|
||||
if underGoRoot {
|
||||
err := cp(
|
||||
filepath.Join(dstbase, pkgpath),
|
||||
dstbase,
|
||||
filepath.Join(cwd, "lib", "time", "zoneinfo.zip"),
|
||||
)
|
||||
if err != nil {
|
||||
|
||||
@@ -55,11 +55,21 @@ For example:
|
||||
|
||||
The default pkg-config tool may be changed by setting the PKG_CONFIG environment variable.
|
||||
|
||||
For security reasons, only a limited set of flags are allowed, notably -D, -I, and -l.
|
||||
To allow additional flags, set CGO_CFLAGS_ALLOW to a regular expression
|
||||
matching the new flags. To disallow flags that would otherwise be allowed,
|
||||
set CGO_CFLAGS_DISALLOW to a regular expression matching arguments
|
||||
that must be disallowed. In both cases the regular expression must match
|
||||
a full argument: to allow -mfoo=bar, use CGO_CFLAGS_ALLOW='-mfoo.*',
|
||||
not just CGO_CFLAGS_ALLOW='-mfoo'. Similarly named variables control
|
||||
the allowed CPPFLAGS, CXXFLAGS, FFLAGS, and LDFLAGS.
|
||||
|
||||
When building, the CGO_CFLAGS, CGO_CPPFLAGS, CGO_CXXFLAGS, CGO_FFLAGS and
|
||||
CGO_LDFLAGS environment variables are added to the flags derived from
|
||||
these directives. Package-specific flags should be set using the
|
||||
directives, not the environment variables, so that builds work in
|
||||
unmodified environments.
|
||||
unmodified environments. Flags obtained from environment variables
|
||||
are not subject to the security limitations described above.
|
||||
|
||||
All the cgo CPPFLAGS and CFLAGS directives in a package are concatenated and
|
||||
used to compile C files in that package. All the CPPFLAGS and CXXFLAGS
|
||||
|
||||
@@ -27,4 +27,5 @@ func Init() {
|
||||
gc.Thearch.SSAMarkMoves = ssaMarkMoves
|
||||
gc.Thearch.SSAGenValue = ssaGenValue
|
||||
gc.Thearch.SSAGenBlock = ssaGenBlock
|
||||
gc.Thearch.ZeroAuto = zeroAuto
|
||||
}
|
||||
|
||||
@@ -166,6 +166,27 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, ax *uint32, x0 *uin
|
||||
return p
|
||||
}
|
||||
|
||||
func zeroAuto(n *gc.Node, pp *obj.Prog) {
|
||||
// Note: this code must not clobber any registers.
|
||||
op := x86.AMOVQ
|
||||
if gc.Widthptr == 4 {
|
||||
op = x86.AMOVL
|
||||
}
|
||||
sym := gc.Linksym(n.Sym)
|
||||
size := n.Type.Size()
|
||||
for i := int64(0); i < size; i += int64(gc.Widthptr) {
|
||||
p := gc.AddAsmAfter(op, pp)
|
||||
pp = p
|
||||
p.From.Type = obj.TYPE_CONST
|
||||
p.From.Offset = 0
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Name = obj.NAME_AUTO
|
||||
p.To.Reg = x86.REG_SP
|
||||
p.To.Offset = n.Xoffset + i
|
||||
p.To.Sym = sym
|
||||
}
|
||||
}
|
||||
|
||||
func ginsnop() {
|
||||
// This is actually not the x86 NOP anymore,
|
||||
// but at the point where it gets used, AX is dead
|
||||
|
||||
@@ -21,4 +21,5 @@ func Init() {
|
||||
gc.Thearch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
|
||||
gc.Thearch.SSAGenValue = ssaGenValue
|
||||
gc.Thearch.SSAGenBlock = ssaGenBlock
|
||||
gc.Thearch.ZeroAuto = zeroAuto
|
||||
}
|
||||
|
||||
@@ -92,6 +92,27 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, r0 *uint32) *obj.Pr
|
||||
|
||||
return p
|
||||
}
|
||||
func zeroAuto(n *gc.Node, pp *obj.Prog) {
|
||||
// Note: this code must not clobber any registers.
|
||||
sym := gc.Linksym(n.Sym)
|
||||
size := n.Type.Size()
|
||||
p := gc.Prog(arm.AMOVW)
|
||||
p.From.Type = obj.TYPE_CONST
|
||||
p.From.Offset = 0
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = arm.REGTMP
|
||||
for i := int64(0); i < size; i += 4 {
|
||||
p := gc.AddAsmAfter(arm.AMOVW, pp)
|
||||
pp = p
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = arm.REGTMP
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Name = obj.NAME_AUTO
|
||||
p.To.Reg = arm.REGSP
|
||||
p.To.Offset = n.Xoffset + i
|
||||
p.To.Sym = sym
|
||||
}
|
||||
}
|
||||
|
||||
func ginsnop() {
|
||||
p := gc.Prog(arm.AAND)
|
||||
|
||||
@@ -21,4 +21,5 @@ func Init() {
|
||||
gc.Thearch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
|
||||
gc.Thearch.SSAGenValue = ssaGenValue
|
||||
gc.Thearch.SSAGenBlock = ssaGenBlock
|
||||
gc.Thearch.ZeroAuto = zeroAuto
|
||||
}
|
||||
|
||||
@@ -103,6 +103,23 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
|
||||
return p
|
||||
}
|
||||
|
||||
func zeroAuto(n *gc.Node, pp *obj.Prog) {
|
||||
// Note: this code must not clobber any registers.
|
||||
sym := gc.Linksym(n.Sym)
|
||||
size := n.Type.Size()
|
||||
for i := int64(0); i < size; i += 8 {
|
||||
p := gc.AddAsmAfter(arm64.AMOVD, pp)
|
||||
pp = p
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = arm64.REGZERO
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Name = obj.NAME_AUTO
|
||||
p.To.Reg = arm64.REGSP
|
||||
p.To.Offset = n.Xoffset + i
|
||||
p.To.Sym = sym
|
||||
}
|
||||
}
|
||||
|
||||
func ginsnop() {
|
||||
p := gc.Prog(arm64.AHINT)
|
||||
p.From.Type = obj.TYPE_CONST
|
||||
|
||||
@@ -303,7 +303,9 @@ func genhash(sym *Sym, t *Type) {
|
||||
typecheckslice(fn.Nbody.Slice(), Etop)
|
||||
Curfn = nil
|
||||
popdcl()
|
||||
testdclstack()
|
||||
if debug_dclstack != 0 {
|
||||
testdclstack()
|
||||
}
|
||||
|
||||
// Disable safemode while compiling this code: the code we
|
||||
// generate internally can refer to unsafe.Pointer.
|
||||
@@ -493,7 +495,9 @@ func geneq(sym *Sym, t *Type) {
|
||||
typecheckslice(fn.Nbody.Slice(), Etop)
|
||||
Curfn = nil
|
||||
popdcl()
|
||||
testdclstack()
|
||||
if debug_dclstack != 0 {
|
||||
testdclstack()
|
||||
}
|
||||
|
||||
// Disable safemode while compiling this code: the code we
|
||||
// generate internally can refer to unsafe.Pointer.
|
||||
|
||||
@@ -217,7 +217,9 @@ func Import(in *bufio.Reader) {
|
||||
typecheckok = tcok
|
||||
resumecheckwidth()
|
||||
|
||||
testdclstack() // debugging only
|
||||
if debug_dclstack != 0 {
|
||||
testdclstack()
|
||||
}
|
||||
}
|
||||
|
||||
func formatErrorf(format string, args ...interface{}) {
|
||||
|
||||
@@ -477,6 +477,10 @@ func escAnalyze(all []*Node, recursive bool) {
|
||||
for _, n := range all {
|
||||
if n.Op == ODCLFUNC {
|
||||
n.Esc = EscFuncPlanned
|
||||
if Debug['m'] > 3 {
|
||||
Dump("escAnalyze", n)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1675,7 +1679,10 @@ func (e *EscState) escflows(dst, src *Node, why *EscStep) {
|
||||
}
|
||||
|
||||
// Don't bother building a graph for scalars.
|
||||
if src.Type != nil && !haspointers(src.Type) {
|
||||
if src.Type != nil && !haspointers(src.Type) && !isReflectHeaderDataField(src) {
|
||||
if Debug['m'] > 3 {
|
||||
fmt.Printf("%v::NOT flows:: %S <- %S\n", linestr(lineno), dst, src)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -248,6 +248,7 @@ var nblank *Node
|
||||
var typecheckok bool
|
||||
|
||||
var compiling_runtime bool
|
||||
var compiling_std bool
|
||||
|
||||
var compiling_wrappers int
|
||||
|
||||
@@ -361,6 +362,12 @@ type Arch struct {
|
||||
// SSAGenBlock emits end-of-block Progs. SSAGenValue should be called
|
||||
// for all values in the block before SSAGenBlock.
|
||||
SSAGenBlock func(s *SSAGenState, b, next *ssa.Block)
|
||||
|
||||
// ZeroAuto emits code to zero the given auto stack variable.
|
||||
// Code is added immediately after pp.
|
||||
// ZeroAuto must not use any non-temporary registers.
|
||||
// ZeroAuto will only be called for variables which contain a pointer.
|
||||
ZeroAuto func(n *Node, pp *obj.Prog)
|
||||
}
|
||||
|
||||
var pcloc int32
|
||||
|
||||
@@ -72,6 +72,15 @@ func Appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int16, foffset in
|
||||
return q
|
||||
}
|
||||
|
||||
func AddAsmAfter(as obj.As, p *obj.Prog) *obj.Prog {
|
||||
q := Ctxt.NewProg()
|
||||
Clearp(q)
|
||||
q.As = as
|
||||
q.Link = p.Link
|
||||
p.Link = q
|
||||
return q
|
||||
}
|
||||
|
||||
func ggloblnod(nam *Node) {
|
||||
s := Linksym(nam.Sym)
|
||||
s.Gotype = Linksym(ngotype(nam))
|
||||
|
||||
@@ -30,11 +30,12 @@ var (
|
||||
)
|
||||
|
||||
var (
|
||||
Debug_append int
|
||||
Debug_closure int
|
||||
Debug_panic int
|
||||
Debug_slice int
|
||||
Debug_wb int
|
||||
Debug_append int
|
||||
Debug_closure int
|
||||
debug_dclstack int
|
||||
Debug_panic int
|
||||
Debug_slice int
|
||||
Debug_wb int
|
||||
)
|
||||
|
||||
// Debug arguments.
|
||||
@@ -48,6 +49,7 @@ var debugtab = []struct {
|
||||
{"append", &Debug_append}, // print information about append compilation
|
||||
{"closure", &Debug_closure}, // print information about closure compilation
|
||||
{"disablenil", &disable_checknil}, // disable nil checks
|
||||
{"dclstack", &debug_dclstack}, // run internal dclstack checks
|
||||
{"gcprog", &Debug_gcprog}, // print dump of GC programs
|
||||
{"nil", &Debug_checknil}, // print information about nil checks
|
||||
{"panic", &Debug_panic}, // do not hide any compiler panic
|
||||
@@ -152,6 +154,7 @@ func Main() {
|
||||
}
|
||||
|
||||
flag.BoolVar(&compiling_runtime, "+", false, "compiling runtime")
|
||||
flag.BoolVar(&compiling_std, "std", false, "compiling standard library")
|
||||
obj.Flagcount("%", "debug non-static initializers", &Debug['%'])
|
||||
obj.Flagcount("B", "disable bounds checking", &Debug['B'])
|
||||
flag.StringVar(&localimport, "D", "", "set relative `path` for local imports")
|
||||
@@ -325,7 +328,6 @@ func Main() {
|
||||
timings.Stop()
|
||||
timings.AddEvent(int64(lexlineno-lexlineno0), "lines")
|
||||
|
||||
testdclstack()
|
||||
mkpackage(localpkg.Name) // final import not used checks
|
||||
finishUniverse()
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ package gc
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
@@ -34,6 +35,7 @@ func parseFile(filename string) {
|
||||
}
|
||||
|
||||
if nsyntaxerrors == 0 {
|
||||
// Always run testdclstack here, even when debug_dclstack is not set, as a sanity measure.
|
||||
testdclstack()
|
||||
}
|
||||
}
|
||||
@@ -1056,6 +1058,11 @@ func (p *noder) pragma(pos, line int, text string) syntax.Pragma {
|
||||
|
||||
case strings.HasPrefix(text, "go:cgo_"):
|
||||
lineno = p.baseline + int32(line) - 1 // pragcgo may call yyerror
|
||||
// For security, we disallow //go:cgo_* directives outside cgo-generated files.
|
||||
// Exception: they are allowed in the standard library, for runtime and syscall.
|
||||
if !isCgoGeneratedFile() && !compiling_std {
|
||||
p.error(syntax.Error{Pos: pos, Line: line, Msg: fmt.Sprintf("//%s only allowed in cgo-generated code", text)})
|
||||
}
|
||||
pragcgobuf += pragcgo(text)
|
||||
fallthrough // because of //go:cgo_unsafe_args
|
||||
default:
|
||||
@@ -1070,6 +1077,20 @@ func (p *noder) pragma(pos, line int, text string) syntax.Pragma {
|
||||
return 0
|
||||
}
|
||||
|
||||
// isCgoGeneratedFile reports whether lineno is in a file
|
||||
// generated by cgo, which is to say a file with name
|
||||
// beginning with "_cgo_". Such files are allowed to
|
||||
// contain cgo directives, and for security reasons
|
||||
// (primarily misuse of linker flags), other files are not.
|
||||
// See golang.org/issue/23672.
|
||||
func isCgoGeneratedFile() bool {
|
||||
stk := Ctxt.LineHist.At(int(lineno))
|
||||
if stk == nil {
|
||||
return false
|
||||
}
|
||||
return strings.HasPrefix(filepath.Base(filepath.Clean(stk.File)), "_cgo_")
|
||||
}
|
||||
|
||||
func mkname(sym *Sym) *Node {
|
||||
n := oldname(sym)
|
||||
if n.Name != nil && n.Name.Pack != nil {
|
||||
|
||||
@@ -120,7 +120,30 @@ func Gvarlive(n *Node) {
|
||||
}
|
||||
|
||||
func removevardef(firstp *obj.Prog) {
|
||||
// At VARKILLs, zero variable if it is ambiguously live.
|
||||
// After the VARKILL anything this variable references
|
||||
// might be collected. If it were to become live again later,
|
||||
// the GC will see references to already-collected objects.
|
||||
// See issue 20029.
|
||||
for p := firstp; p != nil; p = p.Link {
|
||||
if p.As != obj.AVARKILL {
|
||||
continue
|
||||
}
|
||||
n := p.To.Node.(*Node)
|
||||
if !n.Name.Needzero {
|
||||
continue
|
||||
}
|
||||
if n.Class != PAUTO {
|
||||
Fatalf("zero of variable which isn't PAUTO %v", n)
|
||||
}
|
||||
if n.Type.Size()%int64(Widthptr) != 0 {
|
||||
Fatalf("zero of variable not a multiple of ptr size %v", n)
|
||||
}
|
||||
Thearch.ZeroAuto(n, p)
|
||||
}
|
||||
|
||||
for p := firstp; p != nil; p = p.Link {
|
||||
|
||||
for p.Link != nil && (p.Link.As == obj.AVARDEF || p.Link.As == obj.AVARKILL || p.Link.As == obj.AVARLIVE) {
|
||||
p.Link = p.Link.Link
|
||||
}
|
||||
|
||||
@@ -585,7 +585,7 @@ func isliteral(n *Node) bool {
|
||||
}
|
||||
|
||||
func (n *Node) isSimpleName() bool {
|
||||
return n.Op == ONAME && n.Addable && n.Class != PAUTOHEAP
|
||||
return n.Op == ONAME && n.Addable && n.Class != PAUTOHEAP && n.Class != PEXTERN
|
||||
}
|
||||
|
||||
func litas(l *Node, r *Node, init *Nodes) {
|
||||
|
||||
@@ -3470,8 +3470,13 @@ func (s *state) insertWBstore(t *Type, left, right *ssa.Value, line int32, skip
|
||||
if s.WBLineno == 0 {
|
||||
s.WBLineno = left.Line
|
||||
}
|
||||
s.storeTypeScalars(t, left, right, skip)
|
||||
s.storeTypePtrsWB(t, left, right)
|
||||
if t == Types[TUINTPTR] {
|
||||
// Stores to reflect.{Slice,String}Header.Data.
|
||||
s.vars[&memVar] = s.newValue3I(ssa.OpStoreWB, ssa.TypeMem, s.config.PtrSize, left, right, s.mem())
|
||||
} else {
|
||||
s.storeTypeScalars(t, left, right, skip)
|
||||
s.storeTypePtrsWB(t, left, right)
|
||||
}
|
||||
|
||||
// WB ops will be expanded to branches at writebarrier phase.
|
||||
// To make it easy, we put WB ops at the end of a block, so
|
||||
|
||||
@@ -63,6 +63,9 @@ func TestArithmeticConst(t *testing.T) { runTest(t, "arithConst.go") }
|
||||
|
||||
func TestChan(t *testing.T) { runTest(t, "chan.go") }
|
||||
|
||||
// TestComparisonsConst tests results for comparison operations against constants.
|
||||
func TestComparisonsConst(t *testing.T) { runTest(t, "cmpConst.go") }
|
||||
|
||||
func TestCompound(t *testing.T) { runTest(t, "compound.go") }
|
||||
|
||||
func TestCtl(t *testing.T) { runTest(t, "ctl.go") }
|
||||
|
||||
@@ -1833,7 +1833,9 @@ func genwrapper(rcvr *Type, method *Field, newnam *Sym, iface int) {
|
||||
funcbody(fn)
|
||||
Curfn = fn
|
||||
popdcl()
|
||||
testdclstack()
|
||||
if debug_dclstack != 0 {
|
||||
testdclstack()
|
||||
}
|
||||
|
||||
// wrappers where T is anonymous (struct or interface) can be duplicated.
|
||||
if rcvr.IsStruct() || rcvr.IsInterface() || rcvr.IsPtr() && rcvr.Elem().IsStruct() {
|
||||
|
||||
11
src/cmd/compile/internal/gc/testdata/arith.go
vendored
11
src/cmd/compile/internal/gc/testdata/arith.go
vendored
@@ -488,6 +488,17 @@ func testLrot() {
|
||||
wantA, wantB, wantC, wantD, ", got", a, b, c, d)
|
||||
failed = true
|
||||
}
|
||||
// Also test inputs with the top bit set, and make sure
|
||||
// sub-word right shift has high bits cleared first.
|
||||
// See issue #19270.
|
||||
wantA, wantB, wantC, wantD = uint8(0xdf), uint16(0xdfff),
|
||||
uint32(0xdfffffff), uint64(0xdfffffffffffffff)
|
||||
a, b, c, d = lrot1_ssa(0xfe, 0xfffe, 0xfffffffe, 0xfffffffffffffffe)
|
||||
if a != wantA || b != wantB || c != wantC || d != wantD {
|
||||
println("lrot1_ssa(0xfe, 0xfffe, 0xfffffffe, 0xfffffffffffffffe)=",
|
||||
wantA, wantB, wantC, wantD, ", got", a, b, c, d)
|
||||
failed = true
|
||||
}
|
||||
x := lrot2_ssa(0xb0000001, 32)
|
||||
wantX := uint32(0xb0000001)
|
||||
if x != wantX {
|
||||
|
||||
2217
src/cmd/compile/internal/gc/testdata/cmpConst.go
vendored
Normal file
2217
src/cmd/compile/internal/gc/testdata/cmpConst.go
vendored
Normal file
File diff suppressed because it is too large
Load Diff
248
src/cmd/compile/internal/gc/testdata/gen/cmpConstGen.go
vendored
Normal file
248
src/cmd/compile/internal/gc/testdata/gen/cmpConstGen.go
vendored
Normal file
@@ -0,0 +1,248 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
// This program generates a test to verify that the standard comparison
|
||||
// operators properly handle one const operand. The test file should be
|
||||
// generated with a known working version of go.
|
||||
// launch with `go run cmpConstGen.go` a file called cmpConst.go
|
||||
// will be written into the parent directory containing the tests
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/big"
|
||||
"sort"
|
||||
)
|
||||
|
||||
const (
|
||||
maxU64 = (1 << 64) - 1
|
||||
maxU32 = (1 << 32) - 1
|
||||
maxU16 = (1 << 16) - 1
|
||||
maxU8 = (1 << 8) - 1
|
||||
|
||||
maxI64 = (1 << 63) - 1
|
||||
maxI32 = (1 << 31) - 1
|
||||
maxI16 = (1 << 15) - 1
|
||||
maxI8 = (1 << 7) - 1
|
||||
|
||||
minI64 = -(1 << 63)
|
||||
minI32 = -(1 << 31)
|
||||
minI16 = -(1 << 15)
|
||||
minI8 = -(1 << 7)
|
||||
)
|
||||
|
||||
func cmp(left *big.Int, op string, right *big.Int) bool {
|
||||
switch left.Cmp(right) {
|
||||
case -1: // less than
|
||||
return op == "<" || op == "<=" || op == "!="
|
||||
case 0: // equal
|
||||
return op == "==" || op == "<=" || op == ">="
|
||||
case 1: // greater than
|
||||
return op == ">" || op == ">=" || op == "!="
|
||||
}
|
||||
panic("unexpected comparison value")
|
||||
}
|
||||
|
||||
func inRange(typ string, val *big.Int) bool {
|
||||
min, max := &big.Int{}, &big.Int{}
|
||||
switch typ {
|
||||
case "uint64":
|
||||
max = max.SetUint64(maxU64)
|
||||
case "uint32":
|
||||
max = max.SetUint64(maxU32)
|
||||
case "uint16":
|
||||
max = max.SetUint64(maxU16)
|
||||
case "uint8":
|
||||
max = max.SetUint64(maxU8)
|
||||
case "int64":
|
||||
min = min.SetInt64(minI64)
|
||||
max = max.SetInt64(maxI64)
|
||||
case "int32":
|
||||
min = min.SetInt64(minI32)
|
||||
max = max.SetInt64(maxI32)
|
||||
case "int16":
|
||||
min = min.SetInt64(minI16)
|
||||
max = max.SetInt64(maxI16)
|
||||
case "int8":
|
||||
min = min.SetInt64(minI8)
|
||||
max = max.SetInt64(maxI8)
|
||||
default:
|
||||
panic("unexpected type")
|
||||
}
|
||||
return cmp(min, "<=", val) && cmp(val, "<=", max)
|
||||
}
|
||||
|
||||
func getValues(typ string) []*big.Int {
|
||||
Uint := func(v uint64) *big.Int { return big.NewInt(0).SetUint64(v) }
|
||||
Int := func(v int64) *big.Int { return big.NewInt(0).SetInt64(v) }
|
||||
values := []*big.Int{
|
||||
// limits
|
||||
Uint(maxU64),
|
||||
Uint(maxU64 - 1),
|
||||
Uint(maxI64 + 1),
|
||||
Uint(maxI64),
|
||||
Uint(maxI64 - 1),
|
||||
Uint(maxU32 + 1),
|
||||
Uint(maxU32),
|
||||
Uint(maxU32 - 1),
|
||||
Uint(maxI32 + 1),
|
||||
Uint(maxI32),
|
||||
Uint(maxI32 - 1),
|
||||
Uint(maxU16 + 1),
|
||||
Uint(maxU16),
|
||||
Uint(maxU16 - 1),
|
||||
Uint(maxI16 + 1),
|
||||
Uint(maxI16),
|
||||
Uint(maxI16 - 1),
|
||||
Uint(maxU8 + 1),
|
||||
Uint(maxU8),
|
||||
Uint(maxU8 - 1),
|
||||
Uint(maxI8 + 1),
|
||||
Uint(maxI8),
|
||||
Uint(maxI8 - 1),
|
||||
Uint(0),
|
||||
Int(minI8 + 1),
|
||||
Int(minI8),
|
||||
Int(minI8 - 1),
|
||||
Int(minI16 + 1),
|
||||
Int(minI16),
|
||||
Int(minI16 - 1),
|
||||
Int(minI32 + 1),
|
||||
Int(minI32),
|
||||
Int(minI32 - 1),
|
||||
Int(minI64 + 1),
|
||||
Int(minI64),
|
||||
|
||||
// other possibly interesting values
|
||||
Uint(1),
|
||||
Int(-1),
|
||||
Uint(0xff << 56),
|
||||
Uint(0xff << 32),
|
||||
Uint(0xff << 24),
|
||||
}
|
||||
sort.Slice(values, func(i, j int) bool { return values[i].Cmp(values[j]) == -1 })
|
||||
var ret []*big.Int
|
||||
for _, val := range values {
|
||||
if !inRange(typ, val) {
|
||||
continue
|
||||
}
|
||||
ret = append(ret, val)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func sigString(v *big.Int) string {
|
||||
var t big.Int
|
||||
t.Abs(v)
|
||||
if v.Sign() == -1 {
|
||||
return "neg" + t.String()
|
||||
}
|
||||
return t.String()
|
||||
}
|
||||
|
||||
func main() {
|
||||
types := []string{
|
||||
"uint64", "uint32", "uint16", "uint8",
|
||||
"int64", "int32", "int16", "int8",
|
||||
}
|
||||
|
||||
w := new(bytes.Buffer)
|
||||
fmt.Fprintf(w, "// run\n")
|
||||
fmt.Fprintf(w, "// Code generated by gen/cmpConstGen.go. DO NOT EDIT.\n\n")
|
||||
fmt.Fprintf(w, "package main;\n")
|
||||
fmt.Fprintf(w, "import (\"fmt\"; \"reflect\"; \"runtime\";)\n")
|
||||
fmt.Fprintf(w, "// results show the expected result for the elements left of, equal to and right of the index.\n")
|
||||
fmt.Fprintf(w, "type result struct{l, e, r bool}\n")
|
||||
fmt.Fprintf(w, "var (\n")
|
||||
fmt.Fprintf(w, " eq = result{l: false, e: true, r: false}\n")
|
||||
fmt.Fprintf(w, " ne = result{l: true, e: false, r: true}\n")
|
||||
fmt.Fprintf(w, " lt = result{l: true, e: false, r: false}\n")
|
||||
fmt.Fprintf(w, " le = result{l: true, e: true, r: false}\n")
|
||||
fmt.Fprintf(w, " gt = result{l: false, e: false, r: true}\n")
|
||||
fmt.Fprintf(w, " ge = result{l: false, e: true, r: true}\n")
|
||||
fmt.Fprintf(w, ")\n")
|
||||
|
||||
operators := []struct{ op, name string }{
|
||||
{"<", "lt"},
|
||||
{"<=", "le"},
|
||||
{">", "gt"},
|
||||
{">=", "ge"},
|
||||
{"==", "eq"},
|
||||
{"!=", "ne"},
|
||||
}
|
||||
|
||||
for _, typ := range types {
|
||||
// generate a slice containing valid values for this type
|
||||
fmt.Fprintf(w, "\n// %v tests\n", typ)
|
||||
values := getValues(typ)
|
||||
fmt.Fprintf(w, "var %v_vals = []%v{\n", typ, typ)
|
||||
for _, val := range values {
|
||||
fmt.Fprintf(w, "%v,\n", val.String())
|
||||
}
|
||||
fmt.Fprintf(w, "}\n")
|
||||
|
||||
// generate test functions
|
||||
for _, r := range values {
|
||||
// TODO: could also test constant on lhs.
|
||||
sig := sigString(r)
|
||||
for _, op := range operators {
|
||||
// no need for go:noinline because the function is called indirectly
|
||||
fmt.Fprintf(w, "func %v_%v_%v(x %v) bool { return x %v %v; }\n", op.name, sig, typ, typ, op.op, r.String())
|
||||
}
|
||||
}
|
||||
|
||||
// generate a table of test cases
|
||||
fmt.Fprintf(w, "var %v_tests = []struct{\n", typ)
|
||||
fmt.Fprintf(w, " idx int // index of the constant used\n")
|
||||
fmt.Fprintf(w, " exp result // expected results\n")
|
||||
fmt.Fprintf(w, " fn func(%v) bool\n", typ)
|
||||
fmt.Fprintf(w, "}{\n")
|
||||
for i, r := range values {
|
||||
sig := sigString(r)
|
||||
for _, op := range operators {
|
||||
fmt.Fprintf(w, "{idx: %v,", i)
|
||||
fmt.Fprintf(w, "exp: %v,", op.name)
|
||||
fmt.Fprintf(w, "fn: %v_%v_%v},\n", op.name, sig, typ)
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(w, "}\n")
|
||||
}
|
||||
|
||||
// emit the main function, looping over all test cases
|
||||
fmt.Fprintf(w, "func main() {\n")
|
||||
for _, typ := range types {
|
||||
fmt.Fprintf(w, "for i, test := range %v_tests {\n", typ)
|
||||
fmt.Fprintf(w, " for j, x := range %v_vals {\n", typ)
|
||||
fmt.Fprintf(w, " want := test.exp.l\n")
|
||||
fmt.Fprintf(w, " if j == test.idx {\nwant = test.exp.e\n}")
|
||||
fmt.Fprintf(w, " else if j > test.idx {\nwant = test.exp.r\n}\n")
|
||||
fmt.Fprintf(w, " if test.fn(x) != want {\n")
|
||||
fmt.Fprintf(w, " fn := runtime.FuncForPC(reflect.ValueOf(test.fn).Pointer()).Name()\n")
|
||||
fmt.Fprintf(w, " msg := fmt.Sprintf(\"test failed: %%v(%%v) != %%v [type=%v i=%%v j=%%v idx=%%v]\", fn, x, want, i, j, test.idx)\n", typ)
|
||||
fmt.Fprintf(w, " panic(msg)\n")
|
||||
fmt.Fprintf(w, " }\n")
|
||||
fmt.Fprintf(w, " }\n")
|
||||
fmt.Fprintf(w, "}\n")
|
||||
}
|
||||
fmt.Fprintf(w, "}\n")
|
||||
|
||||
// gofmt result
|
||||
b := w.Bytes()
|
||||
src, err := format.Source(b)
|
||||
if err != nil {
|
||||
fmt.Printf("%s\n", b)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// write to file
|
||||
err = ioutil.WriteFile("../cmpConst.go", src, 0666)
|
||||
if err != nil {
|
||||
log.Fatalf("can't write output: %v\n", err)
|
||||
}
|
||||
}
|
||||
108
src/cmd/compile/internal/gc/testdata/loadstore.go
vendored
108
src/cmd/compile/internal/gc/testdata/loadstore.go
vendored
@@ -102,12 +102,120 @@ func testDeadStorePanic() {
|
||||
}
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func loadHitStore8(x int8, p *int8) int32 {
|
||||
x *= x // try to trash high bits (arch-dependent)
|
||||
*p = x // store
|
||||
return int32(*p) // load and cast
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func loadHitStoreU8(x uint8, p *uint8) uint32 {
|
||||
x *= x // try to trash high bits (arch-dependent)
|
||||
*p = x // store
|
||||
return uint32(*p) // load and cast
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func loadHitStore16(x int16, p *int16) int32 {
|
||||
x *= x // try to trash high bits (arch-dependent)
|
||||
*p = x // store
|
||||
return int32(*p) // load and cast
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func loadHitStoreU16(x uint16, p *uint16) uint32 {
|
||||
x *= x // try to trash high bits (arch-dependent)
|
||||
*p = x // store
|
||||
return uint32(*p) // load and cast
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func loadHitStore32(x int32, p *int32) int64 {
|
||||
x *= x // try to trash high bits (arch-dependent)
|
||||
*p = x // store
|
||||
return int64(*p) // load and cast
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func loadHitStoreU32(x uint32, p *uint32) uint64 {
|
||||
x *= x // try to trash high bits (arch-dependent)
|
||||
*p = x // store
|
||||
return uint64(*p) // load and cast
|
||||
}
|
||||
|
||||
func testLoadHitStore() {
|
||||
// Test that sign/zero extensions are kept when a load-hit-store
|
||||
// is replaced by a register-register move.
|
||||
{
|
||||
var in int8 = (1 << 6) + 1
|
||||
var p int8
|
||||
got := loadHitStore8(in, &p)
|
||||
want := int32(in * in)
|
||||
if got != want {
|
||||
fmt.Println("testLoadHitStore (int8) failed. want =", want, ", got =", got)
|
||||
failed = true
|
||||
}
|
||||
}
|
||||
{
|
||||
var in uint8 = (1 << 6) + 1
|
||||
var p uint8
|
||||
got := loadHitStoreU8(in, &p)
|
||||
want := uint32(in * in)
|
||||
if got != want {
|
||||
fmt.Println("testLoadHitStore (uint8) failed. want =", want, ", got =", got)
|
||||
failed = true
|
||||
}
|
||||
}
|
||||
{
|
||||
var in int16 = (1 << 10) + 1
|
||||
var p int16
|
||||
got := loadHitStore16(in, &p)
|
||||
want := int32(in * in)
|
||||
if got != want {
|
||||
fmt.Println("testLoadHitStore (int16) failed. want =", want, ", got =", got)
|
||||
failed = true
|
||||
}
|
||||
}
|
||||
{
|
||||
var in uint16 = (1 << 10) + 1
|
||||
var p uint16
|
||||
got := loadHitStoreU16(in, &p)
|
||||
want := uint32(in * in)
|
||||
if got != want {
|
||||
fmt.Println("testLoadHitStore (uint16) failed. want =", want, ", got =", got)
|
||||
failed = true
|
||||
}
|
||||
}
|
||||
{
|
||||
var in int32 = (1 << 30) + 1
|
||||
var p int32
|
||||
got := loadHitStore32(in, &p)
|
||||
want := int64(in * in)
|
||||
if got != want {
|
||||
fmt.Println("testLoadHitStore (int32) failed. want =", want, ", got =", got)
|
||||
failed = true
|
||||
}
|
||||
}
|
||||
{
|
||||
var in uint32 = (1 << 30) + 1
|
||||
var p uint32
|
||||
got := loadHitStoreU32(in, &p)
|
||||
want := uint64(in * in)
|
||||
if got != want {
|
||||
fmt.Println("testLoadHitStore (uint32) failed. want =", want, ", got =", got)
|
||||
failed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
testLoadStoreOrder()
|
||||
testStoreSize()
|
||||
testExtStore()
|
||||
testDeadStorePanic()
|
||||
testLoadHitStore()
|
||||
|
||||
if failed {
|
||||
panic("failed")
|
||||
|
||||
@@ -1107,7 +1107,7 @@ OpSwitch:
|
||||
|
||||
case OSLICE, OSLICE3:
|
||||
ok |= Erv
|
||||
n.Left = typecheck(n.Left, top)
|
||||
n.Left = typecheck(n.Left, Erv)
|
||||
low, high, max := n.SliceBounds()
|
||||
hasmax := n.Op.IsSlice3()
|
||||
low = typecheck(low, Erv)
|
||||
@@ -1119,6 +1119,10 @@ OpSwitch:
|
||||
max = indexlit(max)
|
||||
n.SetSliceBounds(low, high, max)
|
||||
l := n.Left
|
||||
if l.Type == nil {
|
||||
n.Type = nil
|
||||
return n
|
||||
}
|
||||
if l.Type.IsArray() {
|
||||
if !islvalue(n.Left) {
|
||||
yyerror("invalid operation %v (slice of unaddressable value)", n)
|
||||
@@ -1131,12 +1135,7 @@ OpSwitch:
|
||||
n.Left = typecheck(n.Left, Erv)
|
||||
l = n.Left
|
||||
}
|
||||
|
||||
t := l.Type
|
||||
if t == nil {
|
||||
n.Type = nil
|
||||
return n
|
||||
}
|
||||
var tp *Type
|
||||
if t.IsString() {
|
||||
if hasmax {
|
||||
|
||||
@@ -57,8 +57,13 @@ func startProfile() {
|
||||
Fatalf("%v", err)
|
||||
}
|
||||
atExit(func() {
|
||||
runtime.GC() // profile all outstanding allocations
|
||||
if err := pprof.WriteHeapProfile(f); err != nil {
|
||||
// Profile all outstanding allocations.
|
||||
runtime.GC()
|
||||
// compilebench parses the memory profile to extract memstats,
|
||||
// which are only written in the legacy pprof format.
|
||||
// See golang.org/issue/18641 and runtime/pprof/pprof.go:writeHeap.
|
||||
const writeLegacyFormat = 1
|
||||
if err := pprof.Lookup("heap").WriteTo(f, writeLegacyFormat); err != nil {
|
||||
Fatalf("%v", err)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -2071,6 +2071,29 @@ func isstack(n *Node) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// isReflectHeaderDataField reports whether l is an expression p.Data
|
||||
// where p has type reflect.SliceHeader or reflect.StringHeader.
|
||||
func isReflectHeaderDataField(l *Node) bool {
|
||||
if l.Type != Types[TUINTPTR] {
|
||||
return false
|
||||
}
|
||||
|
||||
var tsym *Sym
|
||||
switch l.Op {
|
||||
case ODOT:
|
||||
tsym = l.Left.Type.Sym
|
||||
case ODOTPTR:
|
||||
tsym = l.Left.Type.Elem().Sym
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
if tsym == nil || l.Sym.Name != "Data" || tsym.Pkg.Path != "reflect" {
|
||||
return false
|
||||
}
|
||||
return tsym.Name == "SliceHeader" || tsym.Name == "StringHeader"
|
||||
}
|
||||
|
||||
// Do we need a write barrier for the assignment l = r?
|
||||
func needwritebarrier(l *Node, r *Node) bool {
|
||||
if !use_writebarrier {
|
||||
@@ -2081,15 +2104,21 @@ func needwritebarrier(l *Node, r *Node) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// No write barrier for write of non-pointers.
|
||||
dowidth(l.Type)
|
||||
|
||||
if !haspointers(l.Type) {
|
||||
// No write barrier for write to stack.
|
||||
if isstack(l) {
|
||||
return false
|
||||
}
|
||||
|
||||
// No write barrier for write to stack.
|
||||
if isstack(l) {
|
||||
// Package unsafe's documentation says storing pointers into
|
||||
// reflect.SliceHeader and reflect.StringHeader's Data fields
|
||||
// is valid, even though they have type uintptr (#19168).
|
||||
if isReflectHeaderDataField(l) {
|
||||
return true
|
||||
}
|
||||
|
||||
// No write barrier for write of non-pointers.
|
||||
dowidth(l.Type)
|
||||
if !haspointers(l.Type) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -3117,12 +3146,12 @@ func walkcompare(n *Node, init *Nodes) *Node {
|
||||
cmpr = cmpr.Left
|
||||
}
|
||||
|
||||
if !islvalue(cmpl) || !islvalue(cmpr) {
|
||||
Fatalf("arguments of comparison must be lvalues - %v %v", cmpl, cmpr)
|
||||
}
|
||||
|
||||
// Chose not to inline. Call equality function directly.
|
||||
if !inline {
|
||||
if !islvalue(cmpl) || !islvalue(cmpr) {
|
||||
Fatalf("arguments of comparison must be lvalues - %v %v", cmpl, cmpr)
|
||||
}
|
||||
|
||||
// eq algs take pointers
|
||||
pl := temp(ptrto(t))
|
||||
al := nod(OAS, pl, nod(OADDR, cmpl, nil))
|
||||
|
||||
@@ -23,4 +23,5 @@ func Init() {
|
||||
gc.Thearch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
|
||||
gc.Thearch.SSAGenValue = ssaGenValue
|
||||
gc.Thearch.SSAGenBlock = ssaGenBlock
|
||||
gc.Thearch.ZeroAuto = zeroAuto
|
||||
}
|
||||
|
||||
@@ -92,6 +92,23 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
|
||||
return p
|
||||
}
|
||||
|
||||
func zeroAuto(n *gc.Node, pp *obj.Prog) {
|
||||
// Note: this code must not clobber any registers.
|
||||
sym := gc.Linksym(n.Sym)
|
||||
size := n.Type.Size()
|
||||
for i := int64(0); i < size; i += 4 {
|
||||
p := gc.AddAsmAfter(mips.AMOVW, pp)
|
||||
pp = p
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = mips.REGZERO
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Name = obj.NAME_AUTO
|
||||
p.To.Reg = mips.REGSP
|
||||
p.To.Offset = n.Xoffset + i
|
||||
p.To.Sym = sym
|
||||
}
|
||||
}
|
||||
|
||||
func ginsnop() {
|
||||
p := gc.Prog(mips.ANOR)
|
||||
p.From.Type = obj.TYPE_REG
|
||||
|
||||
@@ -25,4 +25,5 @@ func Init() {
|
||||
gc.Thearch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
|
||||
gc.Thearch.SSAGenValue = ssaGenValue
|
||||
gc.Thearch.SSAGenBlock = ssaGenBlock
|
||||
gc.Thearch.ZeroAuto = zeroAuto
|
||||
}
|
||||
|
||||
@@ -95,6 +95,23 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
|
||||
return p
|
||||
}
|
||||
|
||||
func zeroAuto(n *gc.Node, pp *obj.Prog) {
|
||||
// Note: this code must not clobber any registers.
|
||||
sym := gc.Linksym(n.Sym)
|
||||
size := n.Type.Size()
|
||||
for i := int64(0); i < size; i += 8 {
|
||||
p := gc.AddAsmAfter(mips.AMOVV, pp)
|
||||
pp = p
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = mips.REGZERO
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Name = obj.NAME_AUTO
|
||||
p.To.Reg = mips.REGSP
|
||||
p.To.Offset = n.Xoffset + i
|
||||
p.To.Sym = sym
|
||||
}
|
||||
}
|
||||
|
||||
func ginsnop() {
|
||||
p := gc.Prog(mips.ANOR)
|
||||
p.From.Type = obj.TYPE_REG
|
||||
|
||||
@@ -24,6 +24,7 @@ func Init() {
|
||||
gc.Thearch.SSAMarkMoves = ssaMarkMoves
|
||||
gc.Thearch.SSAGenValue = ssaGenValue
|
||||
gc.Thearch.SSAGenBlock = ssaGenBlock
|
||||
gc.Thearch.ZeroAuto = zeroAuto
|
||||
|
||||
initvariants()
|
||||
initproginfo()
|
||||
|
||||
@@ -90,6 +90,23 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
|
||||
return p
|
||||
}
|
||||
|
||||
func zeroAuto(n *gc.Node, pp *obj.Prog) {
|
||||
// Note: this code must not clobber any registers.
|
||||
sym := gc.Linksym(n.Sym)
|
||||
size := n.Type.Size()
|
||||
for i := int64(0); i < size; i += 8 {
|
||||
p := gc.AddAsmAfter(ppc64.AMOVD, pp)
|
||||
pp = p
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = ppc64.REGZERO
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Name = obj.NAME_AUTO
|
||||
p.To.Reg = ppc64.REGSP
|
||||
p.To.Offset = n.Xoffset + i
|
||||
p.To.Sym = sym
|
||||
}
|
||||
}
|
||||
|
||||
func ginsnop() {
|
||||
p := gc.Prog(ppc64.AOR)
|
||||
p.From.Type = obj.TYPE_REG
|
||||
|
||||
@@ -20,4 +20,5 @@ func Init() {
|
||||
gc.Thearch.SSAMarkMoves = ssaMarkMoves
|
||||
gc.Thearch.SSAGenValue = ssaGenValue
|
||||
gc.Thearch.SSAGenBlock = ssaGenBlock
|
||||
gc.Thearch.ZeroAuto = zeroAuto
|
||||
}
|
||||
|
||||
@@ -143,6 +143,19 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
|
||||
return p
|
||||
}
|
||||
|
||||
func zeroAuto(n *gc.Node, pp *obj.Prog) {
|
||||
// Note: this code must not clobber any registers.
|
||||
p := gc.AddAsmAfter(s390x.ACLEAR, pp)
|
||||
pp = p
|
||||
p.From.Type = obj.TYPE_CONST
|
||||
p.From.Offset = n.Type.Size()
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Name = obj.NAME_AUTO
|
||||
p.To.Reg = s390x.REGSP
|
||||
p.To.Offset = n.Xoffset
|
||||
p.To.Sym = gc.Linksym(n.Sym)
|
||||
}
|
||||
|
||||
func ginsnop() {
|
||||
p := gc.Prog(s390x.AOR)
|
||||
p.From.Type = obj.TYPE_REG
|
||||
|
||||
@@ -424,7 +424,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Reg = v.Args[0].Reg()
|
||||
gc.AddAux2(&p.To, v, sc.Off())
|
||||
case ssa.OpCopy, ssa.OpS390XMOVDconvert:
|
||||
case ssa.OpCopy, ssa.OpS390XMOVDconvert, ssa.OpS390XMOVDreg:
|
||||
if v.Type.IsMemory() {
|
||||
return
|
||||
}
|
||||
@@ -433,6 +433,11 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
if x != y {
|
||||
opregreg(moveByType(v.Type), y, x)
|
||||
}
|
||||
case ssa.OpS390XMOVDnop:
|
||||
if v.Reg() != v.Args[0].Reg() {
|
||||
v.Fatalf("input[0] and output not in same register %s", v.LongString())
|
||||
}
|
||||
// nothing to do
|
||||
case ssa.OpLoadReg:
|
||||
if v.Type.IsFlags() {
|
||||
v.Fatalf("load flags not implemented: %v", v.LongString())
|
||||
|
||||
@@ -294,6 +294,39 @@ func checkFunc(f *Func) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that if a tuple has a memory type, it is second.
|
||||
for _, b := range f.Blocks {
|
||||
for _, v := range b.Values {
|
||||
if v.Type.IsTuple() && v.Type.FieldType(0).IsMemory() {
|
||||
f.Fatalf("memory is first in a tuple: %s\n", v.LongString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that only one memory is live at any point.
|
||||
// TODO: make this check examine interblock.
|
||||
if f.scheduled {
|
||||
for _, b := range f.Blocks {
|
||||
var mem *Value // the live memory
|
||||
for _, v := range b.Values {
|
||||
if v.Op != OpPhi {
|
||||
for _, a := range v.Args {
|
||||
if a.Type.IsMemory() || a.Type.IsTuple() && a.Type.FieldType(1).IsMemory() {
|
||||
if mem == nil {
|
||||
mem = a
|
||||
} else if mem != a {
|
||||
f.Fatalf("two live mems @ %s: %s and %s", v, mem, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if v.Type.IsMemory() || v.Type.IsTuple() && v.Type.FieldType(1).IsMemory() {
|
||||
mem = v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// domCheck reports whether x dominates y (including x==y).
|
||||
|
||||
@@ -313,9 +313,13 @@ func cmpVal(v, w *Value, auxIDs auxmap) Cmp {
|
||||
// that generate memory.
|
||||
return lt2Cmp(v.ID < w.ID)
|
||||
}
|
||||
|
||||
if tc := v.Type.Compare(w.Type); tc != CMPeq {
|
||||
return tc
|
||||
// OpSelect is a pseudo-op. We need to be more agressive
|
||||
// regarding CSE to keep multiple OpSelect's of the same
|
||||
// argument from existing.
|
||||
if v.Op != OpSelect0 && v.Op != OpSelect1 {
|
||||
if tc := v.Type.Compare(w.Type); tc != CMPeq {
|
||||
return tc
|
||||
}
|
||||
}
|
||||
|
||||
if v.Aux != w.Aux {
|
||||
|
||||
@@ -64,7 +64,7 @@ func liveValues(f *Func, reachable []bool) []bool {
|
||||
q = append(q, v)
|
||||
}
|
||||
for _, v := range b.Values {
|
||||
if opcodeTable[v.Op].call && !live[v.ID] {
|
||||
if (opcodeTable[v.Op].call || opcodeTable[v.Op].hasSideEffects) && !live[v.ID] {
|
||||
live[v.ID] = true
|
||||
q = append(q, v)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ package ssa
|
||||
|
||||
import (
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/s390x"
|
||||
"cmd/internal/obj/x86"
|
||||
"testing"
|
||||
)
|
||||
@@ -21,6 +22,10 @@ func testConfig(t testing.TB) *Config {
|
||||
return NewConfig("amd64", DummyFrontend{t}, testCtxt, true)
|
||||
}
|
||||
|
||||
func testConfigS390X(t testing.TB) *Config {
|
||||
return NewConfig("s390x", DummyFrontend{t}, obj.Linknew(&s390x.Links390x), true)
|
||||
}
|
||||
|
||||
// DummyFrontend is a test-only frontend.
|
||||
// It assumes 64 bit integers and pointers.
|
||||
type DummyFrontend struct {
|
||||
@@ -30,8 +35,20 @@ type DummyFrontend struct {
|
||||
func (DummyFrontend) StringData(s string) interface{} {
|
||||
return nil
|
||||
}
|
||||
func (DummyFrontend) Auto(t Type) GCNode {
|
||||
return nil
|
||||
|
||||
type dummyGCNode struct {
|
||||
typ Type
|
||||
name string
|
||||
}
|
||||
|
||||
func (d *dummyGCNode) Typ() Type {
|
||||
return d.typ
|
||||
}
|
||||
func (d *dummyGCNode) String() string {
|
||||
return d.name
|
||||
}
|
||||
func (d DummyFrontend) Auto(t Type) GCNode {
|
||||
return &dummyGCNode{typ: t, name: "dummy"}
|
||||
}
|
||||
func (d DummyFrontend) SplitString(s LocalSlot) (LocalSlot, LocalSlot) {
|
||||
return LocalSlot{s.N, d.TypeBytePtr(), s.Off}, LocalSlot{s.N, d.TypeInt(), s.Off + 8}
|
||||
|
||||
@@ -620,10 +620,12 @@
|
||||
(MOVWLZX x:(MOVWloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWloadidx1 <v.Type> [off] {sym} ptr idx mem)
|
||||
(MOVWLZX x:(MOVWloadidx2 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWloadidx2 <v.Type> [off] {sym} ptr idx mem)
|
||||
|
||||
// replace load from same location as preceding store with copy
|
||||
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
|
||||
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBLZX x)
|
||||
(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWLZX x)
|
||||
(MOVLload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
(MOVBLSXload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBLSX x)
|
||||
(MOVWLSXload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWLSX x)
|
||||
|
||||
// Fold extensions and ANDs together.
|
||||
(MOVBLZX (ANDLconst [c] x)) -> (ANDLconst [c & 0xff] x)
|
||||
|
||||
@@ -762,11 +762,14 @@
|
||||
(MOVLQZX x:(MOVLloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVLloadidx1 <v.Type> [off] {sym} ptr idx mem)
|
||||
(MOVLQZX x:(MOVLloadidx4 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVLloadidx4 <v.Type> [off] {sym} ptr idx mem)
|
||||
|
||||
// replace load from same location as preceding store with copy
|
||||
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
(MOVLload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
|
||||
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBQZX x)
|
||||
(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWQZX x)
|
||||
(MOVLload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVLQZX x)
|
||||
(MOVQload [off] {sym} ptr (MOVQstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
(MOVBQSXload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBQSX x)
|
||||
(MOVWQSXload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWQSX x)
|
||||
(MOVLQSXload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVLQSX x)
|
||||
|
||||
// Fold extensions and ANDs together.
|
||||
(MOVBQZX (ANDLconst [c] x)) -> (ANDLconst [c & 0xff] x)
|
||||
|
||||
@@ -522,15 +522,15 @@ func init() {
|
||||
// store arg0 to arg1+auxint+aux, arg2=mem.
|
||||
// These ops return a tuple of <old contents of *(arg1+auxint+aux), memory>.
|
||||
// Note: arg0 and arg1 are backwards compared to MOVLstore (to facilitate resultInArg0)!
|
||||
{name: "XCHGL", argLength: 3, reg: gpstorexchg, asm: "XCHGL", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true},
|
||||
{name: "XCHGQ", argLength: 3, reg: gpstorexchg, asm: "XCHGQ", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true},
|
||||
{name: "XCHGL", argLength: 3, reg: gpstorexchg, asm: "XCHGL", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, hasSideEffects: true},
|
||||
{name: "XCHGQ", argLength: 3, reg: gpstorexchg, asm: "XCHGQ", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, hasSideEffects: true},
|
||||
|
||||
// Atomic adds.
|
||||
// *(arg1+auxint+aux) += arg0. arg2=mem.
|
||||
// Returns a tuple of <old contents of *(arg1+auxint+aux), memory>.
|
||||
// Note: arg0 and arg1 are backwards compared to MOVLstore (to facilitate resultInArg0)!
|
||||
{name: "XADDLlock", argLength: 3, reg: gpstorexchg, asm: "XADDL", typ: "(UInt32,Mem)", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true},
|
||||
{name: "XADDQlock", argLength: 3, reg: gpstorexchg, asm: "XADDQ", typ: "(UInt64,Mem)", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true},
|
||||
{name: "XADDLlock", argLength: 3, reg: gpstorexchg, asm: "XADDL", typ: "(UInt32,Mem)", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, hasSideEffects: true},
|
||||
{name: "XADDQlock", argLength: 3, reg: gpstorexchg, asm: "XADDQ", typ: "(UInt64,Mem)", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, hasSideEffects: true},
|
||||
{name: "AddTupleFirst32", argLength: 2}, // arg0=tuple <x,y>. Returns <x+arg1,y>.
|
||||
{name: "AddTupleFirst64", argLength: 2}, // arg0=tuple <x,y>. Returns <x+arg1,y>.
|
||||
|
||||
@@ -553,12 +553,12 @@ func init() {
|
||||
// JEQ ...
|
||||
// but we can't do that because memory-using ops can't generate flags yet
|
||||
// (flagalloc wants to move flag-generating instructions around).
|
||||
{name: "CMPXCHGLlock", argLength: 4, reg: cmpxchg, asm: "CMPXCHGL", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true},
|
||||
{name: "CMPXCHGQlock", argLength: 4, reg: cmpxchg, asm: "CMPXCHGQ", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true},
|
||||
{name: "CMPXCHGLlock", argLength: 4, reg: cmpxchg, asm: "CMPXCHGL", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
|
||||
{name: "CMPXCHGQlock", argLength: 4, reg: cmpxchg, asm: "CMPXCHGQ", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
|
||||
|
||||
// Atomic memory updates.
|
||||
{name: "ANDBlock", argLength: 3, reg: gpstore, asm: "ANDB", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true}, // *(arg0+auxint+aux) &= arg1
|
||||
{name: "ORBlock", argLength: 3, reg: gpstore, asm: "ORB", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true}, // *(arg0+auxint+aux) |= arg1
|
||||
{name: "ANDBlock", argLength: 3, reg: gpstore, asm: "ANDB", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true}, // *(arg0+auxint+aux) &= arg1
|
||||
{name: "ORBlock", argLength: 3, reg: gpstore, asm: "ORB", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true}, // *(arg0+auxint+aux) |= arg1
|
||||
}
|
||||
|
||||
var AMD64blocks = []blockData{
|
||||
|
||||
@@ -178,8 +178,8 @@
|
||||
(Rsh8x64 x (Const64 [c])) && uint64(c) >= 8 -> (SRAconst (SLLconst <config.fe.TypeUInt32()> x [24]) [31])
|
||||
|
||||
(Lrot32 x [c]) -> (SRRconst x [32-c&31])
|
||||
(Lrot16 <t> x [c]) -> (OR (SLLconst <t> x [c&15]) (SRLconst <t> x [16-c&15]))
|
||||
(Lrot8 <t> x [c]) -> (OR (SLLconst <t> x [c&7]) (SRLconst <t> x [8-c&7]))
|
||||
(Lrot16 <t> x [c]) -> (OR (SLLconst <t> x [c&15]) (SRLconst <t> (ZeroExt16to32 x) [16-c&15]))
|
||||
(Lrot8 <t> x [c]) -> (OR (SLLconst <t> x [c&7]) (SRLconst <t> (ZeroExt8to32 x) [8-c&7]))
|
||||
|
||||
// constants
|
||||
(Const8 [val]) -> (MOVWconst [val])
|
||||
@@ -467,12 +467,13 @@
|
||||
(MOVDstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
|
||||
(MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
|
||||
// replace load from same location as preceding store with copy
|
||||
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type) -> x
|
||||
(MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type) -> x
|
||||
(MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type) -> x
|
||||
(MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type) -> x
|
||||
// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
|
||||
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBreg x)
|
||||
(MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBUreg x)
|
||||
(MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHreg x)
|
||||
(MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHUreg x)
|
||||
(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
|
||||
(MOVFload [off] {sym} ptr (MOVFstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
(MOVDload [off] {sym} ptr (MOVDstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
|
||||
|
||||
@@ -529,110 +529,148 @@
|
||||
// can be encoded in the instructions
|
||||
// since this rewriting takes place before stack allocation, the offset to SP is unknown,
|
||||
// so don't do it for args and locals with unaligned offset
|
||||
(MOVBload [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVBload [off1+off2] {sym} ptr mem)
|
||||
(MOVBUload [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVBUload [off1+off2] {sym} ptr mem)
|
||||
(MOVBload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(off1+off2) ->
|
||||
(MOVBload [off1+off2] {sym} ptr mem)
|
||||
(MOVBUload [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(off1+off2) ->
|
||||
(MOVBUload [off1+off2] {sym} ptr mem)
|
||||
(MOVHload [off1] {sym} (ADDconst [off2] ptr) mem)
|
||||
&& (off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
|
||||
&& is32Bit(off1+off2) && !isArg(sym)
|
||||
&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
|
||||
(MOVHload [off1+off2] {sym} ptr mem)
|
||||
(MOVHUload [off1] {sym} (ADDconst [off2] ptr) mem)
|
||||
&& (off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
|
||||
&& is32Bit(off1+off2) && !isArg(sym)
|
||||
&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
|
||||
(MOVHUload [off1+off2] {sym} ptr mem)
|
||||
(MOVWload [off1] {sym} (ADDconst [off2] ptr) mem)
|
||||
&& (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
|
||||
&& is32Bit(off1+off2) && !isArg(sym)
|
||||
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
|
||||
(MOVWload [off1+off2] {sym} ptr mem)
|
||||
(MOVWUload [off1] {sym} (ADDconst [off2] ptr) mem)
|
||||
&& (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
|
||||
&& is32Bit(off1+off2) && !isArg(sym)
|
||||
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
|
||||
(MOVWUload [off1+off2] {sym} ptr mem)
|
||||
(MOVDload [off1] {sym} (ADDconst [off2] ptr) mem)
|
||||
&& (off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
|
||||
&& is32Bit(off1+off2) && !isArg(sym)
|
||||
&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
|
||||
(MOVDload [off1+off2] {sym} ptr mem)
|
||||
(FMOVSload [off1] {sym} (ADDconst [off2] ptr) mem)
|
||||
&& (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
|
||||
&& is32Bit(off1+off2) && !isArg(sym)
|
||||
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
|
||||
(FMOVSload [off1+off2] {sym} ptr mem)
|
||||
(FMOVDload [off1] {sym} (ADDconst [off2] ptr) mem)
|
||||
&& (off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
|
||||
&& is32Bit(off1+off2) && !isArg(sym)
|
||||
&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
|
||||
(FMOVDload [off1+off2] {sym} ptr mem)
|
||||
|
||||
(MOVBstore [off1] {sym} (ADDconst [off2] ptr) val mem) -> (MOVBstore [off1+off2] {sym} ptr val mem)
|
||||
(MOVBstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is32Bit(off1+off2) ->
|
||||
(MOVBstore [off1+off2] {sym} ptr val mem)
|
||||
(MOVHstore [off1] {sym} (ADDconst [off2] ptr) val mem)
|
||||
&& (off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
|
||||
&& is32Bit(off1+off2) && !isArg(sym)
|
||||
&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
|
||||
(MOVHstore [off1+off2] {sym} ptr val mem)
|
||||
(MOVWstore [off1] {sym} (ADDconst [off2] ptr) val mem)
|
||||
&& (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
|
||||
&& is32Bit(off1+off2) && !isArg(sym)
|
||||
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
|
||||
(MOVWstore [off1+off2] {sym} ptr val mem)
|
||||
(MOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem)
|
||||
&& (off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
|
||||
&& is32Bit(off1+off2) && !isArg(sym)
|
||||
&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
|
||||
(MOVDstore [off1+off2] {sym} ptr val mem)
|
||||
(FMOVSstore [off1] {sym} (ADDconst [off2] ptr) val mem)
|
||||
&& (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
|
||||
&& is32Bit(off1+off2) && !isArg(sym)
|
||||
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
|
||||
(FMOVSstore [off1+off2] {sym} ptr val mem)
|
||||
(FMOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem)
|
||||
&& (off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
|
||||
&& is32Bit(off1+off2) && !isArg(sym)
|
||||
&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
|
||||
(FMOVDstore [off1+off2] {sym} ptr val mem)
|
||||
(MOVBstorezero [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVBstorezero [off1+off2] {sym} ptr mem)
|
||||
(MOVBstorezero [off1] {sym} (ADDconst [off2] ptr) mem) && is32Bit(off1+off2) ->
|
||||
(MOVBstorezero [off1+off2] {sym} ptr mem)
|
||||
(MOVHstorezero [off1] {sym} (ADDconst [off2] ptr) mem)
|
||||
&& (off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
|
||||
&& is32Bit(off1+off2) && !isArg(sym)
|
||||
&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
|
||||
(MOVHstorezero [off1+off2] {sym} ptr mem)
|
||||
(MOVWstorezero [off1] {sym} (ADDconst [off2] ptr) mem)
|
||||
&& (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
|
||||
&& is32Bit(off1+off2) && !isArg(sym)
|
||||
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
|
||||
(MOVWstorezero [off1+off2] {sym} ptr mem)
|
||||
(MOVDstorezero [off1] {sym} (ADDconst [off2] ptr) mem)
|
||||
&& (off1+off2)%2==8 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
|
||||
&& is32Bit(off1+off2) && !isArg(sym)
|
||||
&& ((off1+off2)%2==8 || off1+off2<256 && off1+off2>-256 && !isAuto(sym)) ->
|
||||
(MOVDstorezero [off1+off2] {sym} ptr mem)
|
||||
|
||||
(MOVBload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
|
||||
(MOVBload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
|
||||
&& is32Bit(off1+off2) ->
|
||||
(MOVBload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVBUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
|
||||
(MOVBUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
|
||||
&& is32Bit(off1+off2) ->
|
||||
(MOVBUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVHload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
|
||||
&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
|
||||
&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
|
||||
&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
|
||||
(MOVHload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVHUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
|
||||
&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
|
||||
&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
|
||||
&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
|
||||
(MOVHUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVWload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
|
||||
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
|
||||
&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
|
||||
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
|
||||
(MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVWUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
|
||||
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
|
||||
&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
|
||||
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
|
||||
(MOVWUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
|
||||
&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
|
||||
&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
|
||||
&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
|
||||
(MOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(FMOVSload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
|
||||
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
|
||||
&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
|
||||
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
|
||||
(FMOVSload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(FMOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
|
||||
&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
|
||||
&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
|
||||
&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
|
||||
(FMOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
|
||||
(MOVBstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
|
||||
(MOVBstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2)
|
||||
&& is32Bit(off1+off2) ->
|
||||
(MOVBstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
(MOVHstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2)
|
||||
&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
|
||||
&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
|
||||
&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
|
||||
(MOVHstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
(MOVWstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2)
|
||||
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
|
||||
&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
|
||||
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
|
||||
(MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
(MOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2)
|
||||
&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
|
||||
&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
|
||||
&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
|
||||
(MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
(FMOVSstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2)
|
||||
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
|
||||
&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
|
||||
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
|
||||
(FMOVSstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
(FMOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2)
|
||||
&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
|
||||
&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
|
||||
&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
|
||||
(FMOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
(MOVBstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
|
||||
(MOVBstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
|
||||
&& is32Bit(off1+off2) ->
|
||||
(MOVBstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVHstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
|
||||
&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
|
||||
&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
|
||||
&& ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
|
||||
(MOVHstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVWstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
|
||||
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
|
||||
&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
|
||||
&& ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
|
||||
(MOVWstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVDstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
|
||||
&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
|
||||
&& is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2))
|
||||
&& ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2))) ->
|
||||
(MOVDstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
|
||||
// store zero
|
||||
@@ -641,14 +679,14 @@
|
||||
(MOVWstore [off] {sym} ptr (MOVDconst [0]) mem) -> (MOVWstorezero [off] {sym} ptr mem)
|
||||
(MOVDstore [off] {sym} ptr (MOVDconst [0]) mem) -> (MOVDstorezero [off] {sym} ptr mem)
|
||||
|
||||
// replace load from same location as preceding store with copy
|
||||
// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
|
||||
// these seem to have bad interaction with other rules, resulting in slower code
|
||||
//(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
//(MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
//(MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
//(MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
//(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
//(MOVWUload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
//(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBreg x)
|
||||
//(MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBUreg x)
|
||||
//(MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHreg x)
|
||||
//(MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHUreg x)
|
||||
//(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWreg x)
|
||||
//(MOVWUload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWUreg x)
|
||||
//(MOVDload [off] {sym} ptr (MOVDstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
//(FMOVSload [off] {sym} ptr (FMOVSstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
//(FMOVDload [off] {sym} ptr (FMOVDstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
|
||||
@@ -456,16 +456,16 @@ func init() {
|
||||
|
||||
// atomic stores.
|
||||
// store arg1 to arg0. arg2=mem. returns memory. auxint must be zero.
|
||||
{name: "STLR", argLength: 3, reg: gpstore, asm: "STLR", faultOnNilArg0: true},
|
||||
{name: "STLRW", argLength: 3, reg: gpstore, asm: "STLRW", faultOnNilArg0: true},
|
||||
{name: "STLR", argLength: 3, reg: gpstore, asm: "STLR", faultOnNilArg0: true, hasSideEffects: true},
|
||||
{name: "STLRW", argLength: 3, reg: gpstore, asm: "STLRW", faultOnNilArg0: true, hasSideEffects: true},
|
||||
|
||||
// atomic exchange.
|
||||
// store arg1 to arg0. arg2=mem. returns <old content of *arg0, memory>. auxint must be zero.
|
||||
// LDAXR (Rarg0), Rout
|
||||
// STLXR Rarg1, (Rarg0), Rtmp
|
||||
// CBNZ Rtmp, -2(PC)
|
||||
{name: "LoweredAtomicExchange64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true},
|
||||
{name: "LoweredAtomicExchange32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true},
|
||||
{name: "LoweredAtomicExchange64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
|
||||
{name: "LoweredAtomicExchange32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
|
||||
|
||||
// atomic add.
|
||||
// *arg0 += arg1. arg2=mem. returns <new content of *arg0, memory>. auxint must be zero.
|
||||
@@ -473,8 +473,8 @@ func init() {
|
||||
// ADD Rarg1, Rout
|
||||
// STLXR Rout, (Rarg0), Rtmp
|
||||
// CBNZ Rtmp, -3(PC)
|
||||
{name: "LoweredAtomicAdd64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true},
|
||||
{name: "LoweredAtomicAdd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true},
|
||||
{name: "LoweredAtomicAdd64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
|
||||
{name: "LoweredAtomicAdd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
|
||||
|
||||
// atomic compare and swap.
|
||||
// arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory. auxint must be zero.
|
||||
@@ -490,8 +490,8 @@ func init() {
|
||||
// STLXR Rarg2, (Rarg0), Rtmp
|
||||
// CBNZ Rtmp, -4(PC)
|
||||
// CSET EQ, Rout
|
||||
{name: "LoweredAtomicCas64", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true},
|
||||
{name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true},
|
||||
{name: "LoweredAtomicCas64", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
|
||||
{name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
|
||||
|
||||
// atomic and/or.
|
||||
// *arg0 &= (|=) arg1. arg2=mem. returns memory. auxint must be zero.
|
||||
@@ -499,8 +499,8 @@ func init() {
|
||||
// AND/OR Rarg1, Rtmp
|
||||
// STLXRB Rtmp, (Rarg0), Rtmp
|
||||
// CBNZ Rtmp, -3(PC)
|
||||
{name: "LoweredAtomicAnd8", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true},
|
||||
{name: "LoweredAtomicOr8", argLength: 3, reg: gpstore, asm: "ORR", faultOnNilArg0: true},
|
||||
{name: "LoweredAtomicAnd8", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true, hasSideEffects: true},
|
||||
{name: "LoweredAtomicOr8", argLength: 3, reg: gpstore, asm: "ORR", faultOnNilArg0: true, hasSideEffects: true},
|
||||
}
|
||||
|
||||
blocks := []blockData{
|
||||
|
||||
@@ -119,8 +119,8 @@ func init() {
|
||||
fp01 = regInfo{inputs: nil, outputs: []regMask{fp}}
|
||||
fp11 = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}}
|
||||
fp1flags = regInfo{inputs: []regMask{fp}}
|
||||
fpgp = regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}}
|
||||
gpfp = regInfo{inputs: []regMask{gp}, outputs: []regMask{fp}}
|
||||
fpgp = regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}, clobbers: buildReg("F15")} // int-float conversion uses F15 as tmp
|
||||
gpfp = regInfo{inputs: []regMask{gp}, outputs: []regMask{fp}, clobbers: buildReg("F15")}
|
||||
fp21 = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}}
|
||||
fp2flags = regInfo{inputs: []regMask{fp, fp}}
|
||||
fpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{fp}}
|
||||
|
||||
@@ -404,8 +404,7 @@
|
||||
(ANDconst <config.fe.TypeUInt32()> [3] ptr)))
|
||||
(NORconst [0] <config.fe.TypeUInt32()> (SLL <config.fe.TypeUInt32()>
|
||||
(MOVWconst [0xff]) (SLLconst <config.fe.TypeUInt32()> [3]
|
||||
(ANDconst <config.fe.TypeUInt32()> [3]
|
||||
(XORconst <config.fe.TypeUInt32()> [3] ptr)))))) mem)
|
||||
(ANDconst <config.fe.TypeUInt32()> [3] ptr))))) mem)
|
||||
|
||||
// AtomicOr8(ptr,val) -> LoweredAtomicOr(ptr&^3,uint32(val) << (((ptr^3) & 3) * 8))
|
||||
(AtomicOr8 ptr val mem) && config.BigEndian ->
|
||||
@@ -523,11 +522,11 @@
|
||||
(MOVWstorezero [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
|
||||
(MOVWstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
|
||||
// replace load from same location as preceding store with copy
|
||||
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type) -> x
|
||||
(MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type) -> x
|
||||
(MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type) -> x
|
||||
(MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type) -> x
|
||||
// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
|
||||
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBreg x)
|
||||
(MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBUreg x)
|
||||
(MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHreg x)
|
||||
(MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHUreg x)
|
||||
(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
(MOVFload [off] {sym} ptr (MOVFstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
(MOVDload [off] {sym} ptr (MOVDstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
|
||||
@@ -267,8 +267,8 @@ func init() {
|
||||
// SYNC
|
||||
// MOVW Rarg1, (Rarg0)
|
||||
// SYNC
|
||||
{name: "LoweredAtomicStore", argLength: 3, reg: gpstore, faultOnNilArg0: true},
|
||||
{name: "LoweredAtomicStorezero", argLength: 2, reg: gpstore0, faultOnNilArg0: true},
|
||||
{name: "LoweredAtomicStore", argLength: 3, reg: gpstore, faultOnNilArg0: true, hasSideEffects: true},
|
||||
{name: "LoweredAtomicStorezero", argLength: 2, reg: gpstore0, faultOnNilArg0: true, hasSideEffects: true},
|
||||
|
||||
// atomic exchange.
|
||||
// store arg1 to arg0. arg2=mem. returns <old content of *arg0, memory>.
|
||||
@@ -278,7 +278,7 @@ func init() {
|
||||
// SC Rtmp, (Rarg0)
|
||||
// BEQ Rtmp, -3(PC)
|
||||
// SYNC
|
||||
{name: "LoweredAtomicExchange", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true},
|
||||
{name: "LoweredAtomicExchange", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
|
||||
|
||||
// atomic add.
|
||||
// *arg0 += arg1. arg2=mem. returns <new content of *arg0, memory>.
|
||||
@@ -289,8 +289,8 @@ func init() {
|
||||
// BEQ Rtmp, -3(PC)
|
||||
// SYNC
|
||||
// ADDU Rarg1, Rout
|
||||
{name: "LoweredAtomicAdd", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true},
|
||||
{name: "LoweredAtomicAddconst", argLength: 2, reg: regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}, aux: "Int32", resultNotInArgs: true, faultOnNilArg0: true},
|
||||
{name: "LoweredAtomicAdd", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
|
||||
{name: "LoweredAtomicAddconst", argLength: 2, reg: regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}, aux: "Int32", resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
|
||||
|
||||
// atomic compare and swap.
|
||||
// arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory.
|
||||
@@ -308,7 +308,7 @@ func init() {
|
||||
// SC Rout, (Rarg0)
|
||||
// BEQ Rout, -4(PC)
|
||||
// SYNC
|
||||
{name: "LoweredAtomicCas", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true},
|
||||
{name: "LoweredAtomicCas", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
|
||||
|
||||
// atomic and/or.
|
||||
// *arg0 &= (|=) arg1. arg2=mem. returns memory.
|
||||
@@ -318,8 +318,8 @@ func init() {
|
||||
// SC Rtmp, (Rarg0)
|
||||
// BEQ Rtmp, -3(PC)
|
||||
// SYNC
|
||||
{name: "LoweredAtomicAnd", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true},
|
||||
{name: "LoweredAtomicOr", argLength: 3, reg: gpstore, asm: "OR", faultOnNilArg0: true},
|
||||
{name: "LoweredAtomicAnd", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true, hasSideEffects: true},
|
||||
{name: "LoweredAtomicOr", argLength: 3, reg: gpstore, asm: "OR", faultOnNilArg0: true, hasSideEffects: true},
|
||||
|
||||
// large or unaligned zeroing
|
||||
// arg0 = address of memory to zero (in R1, changed as side effect)
|
||||
|
||||
@@ -338,9 +338,9 @@
|
||||
(Geq32F x y) -> (FGreaterEqual (FCMPU x y))
|
||||
(Geq64F x y) -> (FGreaterEqual (FCMPU x y))
|
||||
|
||||
(Geq8U x y) -> (GreaterEqual (CMPU (ZeroExt8to32 x) (ZeroExt8to32 y)))
|
||||
(Geq16U x y) -> (GreaterEqual (CMPU (ZeroExt16to32 x) (ZeroExt16to32 y)))
|
||||
(Geq32U x y) -> (GreaterEqual (CMPU x y))
|
||||
(Geq8U x y) -> (GreaterEqual (CMPWU (ZeroExt8to32 x) (ZeroExt8to32 y)))
|
||||
(Geq16U x y) -> (GreaterEqual (CMPWU (ZeroExt16to32 x) (ZeroExt16to32 y)))
|
||||
(Geq32U x y) -> (GreaterEqual (CMPWU x y))
|
||||
(Geq64U x y) -> (GreaterEqual (CMPU x y))
|
||||
|
||||
// Absorb pseudo-ops into blocks.
|
||||
|
||||
@@ -312,9 +312,12 @@
|
||||
|
||||
// Lowering loads
|
||||
(Load <t> ptr mem) && (is64BitInt(t) || isPtr(t)) -> (MOVDload ptr mem)
|
||||
(Load <t> ptr mem) && is32BitInt(t) -> (MOVWZload ptr mem)
|
||||
(Load <t> ptr mem) && is16BitInt(t) -> (MOVHZload ptr mem)
|
||||
(Load <t> ptr mem) && (t.IsBoolean() || is8BitInt(t)) -> (MOVBZload ptr mem)
|
||||
(Load <t> ptr mem) && is32BitInt(t) && isSigned(t) -> (MOVWload ptr mem)
|
||||
(Load <t> ptr mem) && is32BitInt(t) && !isSigned(t) -> (MOVWZload ptr mem)
|
||||
(Load <t> ptr mem) && is16BitInt(t) && isSigned(t) -> (MOVHload ptr mem)
|
||||
(Load <t> ptr mem) && is16BitInt(t) && !isSigned(t) -> (MOVHZload ptr mem)
|
||||
(Load <t> ptr mem) && is8BitInt(t) && isSigned(t) -> (MOVBload ptr mem)
|
||||
(Load <t> ptr mem) && (t.IsBoolean() || (is8BitInt(t) && !isSigned(t))) -> (MOVBZload ptr mem)
|
||||
(Load <t> ptr mem) && is32BitFloat(t) -> (FMOVSload ptr mem)
|
||||
(Load <t> ptr mem) && is64BitFloat(t) -> (FMOVDload ptr mem)
|
||||
|
||||
@@ -437,7 +440,7 @@
|
||||
(If (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) cmp) yes no) -> (GTF cmp yes no)
|
||||
(If (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) cmp) yes no) -> (GEF cmp yes no)
|
||||
|
||||
(If cond yes no) -> (NE (CMPWconst [0] (MOVBZreg cond)) yes no)
|
||||
(If cond yes no) -> (NE (CMPWconst [0] (MOVBZreg <config.fe.TypeBool()> cond)) yes no)
|
||||
|
||||
// ***************************
|
||||
// Above: lowering rules
|
||||
@@ -445,16 +448,28 @@
|
||||
// ***************************
|
||||
// TODO: Should the optimizations be a separate pass?
|
||||
|
||||
// Fold unnecessary type conversions.
|
||||
(MOVDreg <t> x) && t.Compare(x.Type) == CMPeq -> x
|
||||
(MOVDnop <t> x) && t.Compare(x.Type) == CMPeq -> x
|
||||
|
||||
// Propagate constants through type conversions.
|
||||
(MOVDreg (MOVDconst [c])) -> (MOVDconst [c])
|
||||
(MOVDnop (MOVDconst [c])) -> (MOVDconst [c])
|
||||
|
||||
// If a register move has only 1 use, just use the same register without emitting instruction.
|
||||
// MOVDnop doesn't emit instruction, only for ensuring the type.
|
||||
(MOVDreg x) && x.Uses == 1 -> (MOVDnop x)
|
||||
|
||||
// Fold sign extensions into conditional moves of constants.
|
||||
// Designed to remove the MOVBZreg inserted by the If lowering.
|
||||
(MOVBZreg x:(MOVDLT (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> x
|
||||
(MOVBZreg x:(MOVDLE (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> x
|
||||
(MOVBZreg x:(MOVDGT (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> x
|
||||
(MOVBZreg x:(MOVDGE (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> x
|
||||
(MOVBZreg x:(MOVDEQ (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> x
|
||||
(MOVBZreg x:(MOVDNE (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> x
|
||||
(MOVBZreg x:(MOVDGTnoinv (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> x
|
||||
(MOVBZreg x:(MOVDGEnoinv (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> x
|
||||
(MOVBZreg x:(MOVDLT (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x)
|
||||
(MOVBZreg x:(MOVDLE (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x)
|
||||
(MOVBZreg x:(MOVDGT (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x)
|
||||
(MOVBZreg x:(MOVDGE (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x)
|
||||
(MOVBZreg x:(MOVDEQ (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x)
|
||||
(MOVBZreg x:(MOVDNE (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x)
|
||||
(MOVBZreg x:(MOVDGTnoinv (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x)
|
||||
(MOVBZreg x:(MOVDGEnoinv (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> (MOVDreg x)
|
||||
|
||||
// Fold boolean tests into blocks.
|
||||
(NE (CMPWconst [0] (MOVDLT (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no) -> (LT cmp yes no)
|
||||
@@ -522,8 +537,8 @@
|
||||
(CMP (MOVDconst [c]) x) && is32Bit(c) -> (InvertFlags (CMPconst x [c]))
|
||||
(CMPW x (MOVDconst [c])) -> (CMPWconst x [c])
|
||||
(CMPW (MOVDconst [c]) x) -> (InvertFlags (CMPWconst x [c]))
|
||||
(CMPU x (MOVDconst [c])) && is32Bit(c) -> (CMPUconst x [int64(uint32(c))])
|
||||
(CMPU (MOVDconst [c]) x) && is32Bit(c) -> (InvertFlags (CMPUconst x [int64(uint32(c))]))
|
||||
(CMPU x (MOVDconst [c])) && isU32Bit(c) -> (CMPUconst x [int64(uint32(c))])
|
||||
(CMPU (MOVDconst [c]) x) && isU32Bit(c) -> (InvertFlags (CMPUconst x [int64(uint32(c))]))
|
||||
(CMPWU x (MOVDconst [c])) -> (CMPWUconst x [int64(uint32(c))])
|
||||
(CMPWU (MOVDconst [c]) x) -> (InvertFlags (CMPWUconst x [int64(uint32(c))]))
|
||||
|
||||
@@ -572,46 +587,46 @@
|
||||
(MOVDNE x y (InvertFlags cmp)) -> (MOVDNE x y cmp)
|
||||
|
||||
// don't extend after proper load
|
||||
(MOVBreg x:(MOVBload _ _)) -> x
|
||||
(MOVBZreg x:(MOVBZload _ _)) -> x
|
||||
(MOVHreg x:(MOVBload _ _)) -> x
|
||||
(MOVHreg x:(MOVBZload _ _)) -> x
|
||||
(MOVHreg x:(MOVHload _ _)) -> x
|
||||
(MOVHZreg x:(MOVBZload _ _)) -> x
|
||||
(MOVHZreg x:(MOVHZload _ _)) -> x
|
||||
(MOVWreg x:(MOVBload _ _)) -> x
|
||||
(MOVWreg x:(MOVBZload _ _)) -> x
|
||||
(MOVWreg x:(MOVHload _ _)) -> x
|
||||
(MOVWreg x:(MOVHZload _ _)) -> x
|
||||
(MOVWreg x:(MOVWload _ _)) -> x
|
||||
(MOVWZreg x:(MOVBZload _ _)) -> x
|
||||
(MOVWZreg x:(MOVHZload _ _)) -> x
|
||||
(MOVWZreg x:(MOVWZload _ _)) -> x
|
||||
(MOVBreg x:(MOVBload _ _)) -> (MOVDreg x)
|
||||
(MOVBZreg x:(MOVBZload _ _)) -> (MOVDreg x)
|
||||
(MOVHreg x:(MOVBload _ _)) -> (MOVDreg x)
|
||||
(MOVHreg x:(MOVBZload _ _)) -> (MOVDreg x)
|
||||
(MOVHreg x:(MOVHload _ _)) -> (MOVDreg x)
|
||||
(MOVHZreg x:(MOVBZload _ _)) -> (MOVDreg x)
|
||||
(MOVHZreg x:(MOVHZload _ _)) -> (MOVDreg x)
|
||||
(MOVWreg x:(MOVBload _ _)) -> (MOVDreg x)
|
||||
(MOVWreg x:(MOVBZload _ _)) -> (MOVDreg x)
|
||||
(MOVWreg x:(MOVHload _ _)) -> (MOVDreg x)
|
||||
(MOVWreg x:(MOVHZload _ _)) -> (MOVDreg x)
|
||||
(MOVWreg x:(MOVWload _ _)) -> (MOVDreg x)
|
||||
(MOVWZreg x:(MOVBZload _ _)) -> (MOVDreg x)
|
||||
(MOVWZreg x:(MOVHZload _ _)) -> (MOVDreg x)
|
||||
(MOVWZreg x:(MOVWZload _ _)) -> (MOVDreg x)
|
||||
|
||||
// don't extend if argument is already extended
|
||||
(MOVBreg x:(Arg <t>)) && is8BitInt(t) && isSigned(t) -> x
|
||||
(MOVBZreg x:(Arg <t>)) && is8BitInt(t) && !isSigned(t) -> x
|
||||
(MOVHreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t)) && isSigned(t) -> x
|
||||
(MOVHZreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t)) && !isSigned(t) -> x
|
||||
(MOVWreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && isSigned(t) -> x
|
||||
(MOVWZreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && !isSigned(t) -> x
|
||||
(MOVBreg x:(Arg <t>)) && is8BitInt(t) && isSigned(t) -> (MOVDreg x)
|
||||
(MOVBZreg x:(Arg <t>)) && is8BitInt(t) && !isSigned(t) -> (MOVDreg x)
|
||||
(MOVHreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t)) && isSigned(t) -> (MOVDreg x)
|
||||
(MOVHZreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t)) && !isSigned(t) -> (MOVDreg x)
|
||||
(MOVWreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && isSigned(t) -> (MOVDreg x)
|
||||
(MOVWZreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && !isSigned(t) -> (MOVDreg x)
|
||||
|
||||
// fold double extensions
|
||||
(MOVBreg x:(MOVBreg _)) -> x
|
||||
(MOVBZreg x:(MOVBZreg _)) -> x
|
||||
(MOVHreg x:(MOVBreg _)) -> x
|
||||
(MOVHreg x:(MOVBZreg _)) -> x
|
||||
(MOVHreg x:(MOVHreg _)) -> x
|
||||
(MOVHZreg x:(MOVBZreg _)) -> x
|
||||
(MOVHZreg x:(MOVHZreg _)) -> x
|
||||
(MOVWreg x:(MOVBreg _)) -> x
|
||||
(MOVWreg x:(MOVBZreg _)) -> x
|
||||
(MOVWreg x:(MOVHreg _)) -> x
|
||||
(MOVWreg x:(MOVHreg _)) -> x
|
||||
(MOVWreg x:(MOVWreg _)) -> x
|
||||
(MOVWZreg x:(MOVBZreg _)) -> x
|
||||
(MOVWZreg x:(MOVHZreg _)) -> x
|
||||
(MOVWZreg x:(MOVWZreg _)) -> x
|
||||
(MOVBreg x:(MOVBreg _)) -> (MOVDreg x)
|
||||
(MOVBZreg x:(MOVBZreg _)) -> (MOVDreg x)
|
||||
(MOVHreg x:(MOVBreg _)) -> (MOVDreg x)
|
||||
(MOVHreg x:(MOVBZreg _)) -> (MOVDreg x)
|
||||
(MOVHreg x:(MOVHreg _)) -> (MOVDreg x)
|
||||
(MOVHZreg x:(MOVBZreg _)) -> (MOVDreg x)
|
||||
(MOVHZreg x:(MOVHZreg _)) -> (MOVDreg x)
|
||||
(MOVWreg x:(MOVBreg _)) -> (MOVDreg x)
|
||||
(MOVWreg x:(MOVBZreg _)) -> (MOVDreg x)
|
||||
(MOVWreg x:(MOVHreg _)) -> (MOVDreg x)
|
||||
(MOVWreg x:(MOVHreg _)) -> (MOVDreg x)
|
||||
(MOVWreg x:(MOVWreg _)) -> (MOVDreg x)
|
||||
(MOVWZreg x:(MOVBZreg _)) -> (MOVDreg x)
|
||||
(MOVWZreg x:(MOVHZreg _)) -> (MOVDreg x)
|
||||
(MOVWZreg x:(MOVWZreg _)) -> (MOVDreg x)
|
||||
|
||||
// fold extensions into constants
|
||||
(MOVBreg (MOVDconst [c])) -> (MOVDconst [int64(int8(c))])
|
||||
@@ -641,10 +656,10 @@
|
||||
(MOVWZreg x:(MOVWZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWZloadidx <v.Type> [off] {sym} ptr idx mem)
|
||||
|
||||
// replace load from same location as preceding store with copy
|
||||
(MOVBZload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
(MOVHZload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
(MOVWZload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
(MOVDload [off] {sym} ptr (MOVDstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
(MOVBZload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBZreg x)
|
||||
(MOVHZload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHZreg x)
|
||||
(MOVWZload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWZreg x)
|
||||
(MOVDload [off] {sym} ptr (MOVDstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDreg x)
|
||||
|
||||
// Don't extend before storing
|
||||
(MOVWstore [off] {sym} ptr (MOVWreg x) mem) -> (MOVWstore [off] {sym} ptr x mem)
|
||||
@@ -885,9 +900,9 @@
|
||||
(MOVDEQ y _ (FlagLT)) -> y
|
||||
(MOVDEQ y _ (FlagGT)) -> y
|
||||
|
||||
(MOVDNE _ y (FlagEQ)) -> y
|
||||
(MOVDNE x _ (FlagLT)) -> x
|
||||
(MOVDNE x _ (FlagGT)) -> x
|
||||
(MOVDNE y _ (FlagEQ)) -> y
|
||||
(MOVDNE _ x (FlagLT)) -> x
|
||||
(MOVDNE _ x (FlagGT)) -> x
|
||||
|
||||
(MOVDLT y _ (FlagEQ)) -> y
|
||||
(MOVDLT _ x (FlagLT)) -> x
|
||||
|
||||
@@ -311,6 +311,9 @@ func init() {
|
||||
{name: "MOVHZreg", argLength: 1, reg: gp11sp, asm: "MOVHZ", typ: "UInt64"}, // zero extend arg0 from int16 to int64
|
||||
{name: "MOVWreg", argLength: 1, reg: gp11sp, asm: "MOVW", typ: "Int64"}, // sign extend arg0 from int32 to int64
|
||||
{name: "MOVWZreg", argLength: 1, reg: gp11sp, asm: "MOVWZ", typ: "UInt64"}, // zero extend arg0 from int32 to int64
|
||||
{name: "MOVDreg", argLength: 1, reg: gp11sp, asm: "MOVD"}, // move from arg0
|
||||
|
||||
{name: "MOVDnop", argLength: 1, reg: gp11, resultInArg0: true}, // nop, return arg0 in same register
|
||||
|
||||
{name: "MOVDconst", reg: gp01, asm: "MOVD", typ: "UInt64", aux: "Int64", rematerializeable: true}, // auxint
|
||||
|
||||
@@ -426,14 +429,14 @@ func init() {
|
||||
|
||||
// Atomic stores. These are just normal stores.
|
||||
// store arg1 to arg0+auxint+aux. arg2=mem.
|
||||
{name: "MOVWatomicstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true},
|
||||
{name: "MOVDatomicstore", argLength: 3, reg: gpstore, asm: "MOVD", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true},
|
||||
{name: "MOVWatomicstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
|
||||
{name: "MOVDatomicstore", argLength: 3, reg: gpstore, asm: "MOVD", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
|
||||
|
||||
// Atomic adds.
|
||||
// *(arg0+auxint+aux) += arg1. arg2=mem.
|
||||
// Returns a tuple of <old contents of *(arg0+auxint+aux), memory>.
|
||||
{name: "LAA", argLength: 3, reg: gpstorelaa, asm: "LAA", typ: "(UInt32,Mem)", aux: "SymOff", faultOnNilArg0: true},
|
||||
{name: "LAAG", argLength: 3, reg: gpstorelaa, asm: "LAAG", typ: "(UInt64,Mem)", aux: "SymOff", faultOnNilArg0: true},
|
||||
{name: "LAA", argLength: 3, reg: gpstorelaa, asm: "LAA", typ: "(UInt32,Mem)", aux: "SymOff", faultOnNilArg0: true, hasSideEffects: true},
|
||||
{name: "LAAG", argLength: 3, reg: gpstorelaa, asm: "LAAG", typ: "(UInt64,Mem)", aux: "SymOff", faultOnNilArg0: true, hasSideEffects: true},
|
||||
{name: "AddTupleFirst32", argLength: 2}, // arg0=tuple <x,y>. Returns <x+arg1,y>.
|
||||
{name: "AddTupleFirst64", argLength: 2}, // arg0=tuple <x,y>. Returns <x+arg1,y>.
|
||||
|
||||
@@ -458,13 +461,13 @@ func init() {
|
||||
// BEQ ...
|
||||
// but we can't do that because memory-using ops can't generate flags yet
|
||||
// (flagalloc wants to move flag-generating instructions around).
|
||||
{name: "LoweredAtomicCas32", argLength: 4, reg: cas, asm: "CS", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true},
|
||||
{name: "LoweredAtomicCas64", argLength: 4, reg: cas, asm: "CSG", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true},
|
||||
{name: "LoweredAtomicCas32", argLength: 4, reg: cas, asm: "CS", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
|
||||
{name: "LoweredAtomicCas64", argLength: 4, reg: cas, asm: "CSG", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
|
||||
|
||||
// Lowered atomic swaps, emulated using compare-and-swap.
|
||||
// store arg1 to arg0+auxint+aux, arg2=mem.
|
||||
{name: "LoweredAtomicExchange32", argLength: 3, reg: exchange, asm: "CS", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true},
|
||||
{name: "LoweredAtomicExchange64", argLength: 3, reg: exchange, asm: "CSG", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true},
|
||||
{name: "LoweredAtomicExchange32", argLength: 3, reg: exchange, asm: "CS", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
|
||||
{name: "LoweredAtomicExchange64", argLength: 3, reg: exchange, asm: "CSG", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
|
||||
|
||||
// find leftmost one
|
||||
{
|
||||
|
||||
@@ -460,20 +460,20 @@ var genericOps = []opData{
|
||||
// Atomic loads return a new memory so that the loads are properly ordered
|
||||
// with respect to other loads and stores.
|
||||
// TODO: use for sync/atomic at some point.
|
||||
{name: "AtomicLoad32", argLength: 2, typ: "(UInt32,Mem)"}, // Load from arg0. arg1=memory. Returns loaded value and new memory.
|
||||
{name: "AtomicLoad64", argLength: 2, typ: "(UInt64,Mem)"}, // Load from arg0. arg1=memory. Returns loaded value and new memory.
|
||||
{name: "AtomicLoadPtr", argLength: 2, typ: "(BytePtr,Mem)"}, // Load from arg0. arg1=memory. Returns loaded value and new memory.
|
||||
{name: "AtomicStore32", argLength: 3, typ: "Mem"}, // Store arg1 to *arg0. arg2=memory. Returns memory.
|
||||
{name: "AtomicStore64", argLength: 3, typ: "Mem"}, // Store arg1 to *arg0. arg2=memory. Returns memory.
|
||||
{name: "AtomicStorePtrNoWB", argLength: 3, typ: "Mem"}, // Store arg1 to *arg0. arg2=memory. Returns memory.
|
||||
{name: "AtomicExchange32", argLength: 3, typ: "(UInt32,Mem)"}, // Store arg1 to *arg0. arg2=memory. Returns old contents of *arg0 and new memory.
|
||||
{name: "AtomicExchange64", argLength: 3, typ: "(UInt64,Mem)"}, // Store arg1 to *arg0. arg2=memory. Returns old contents of *arg0 and new memory.
|
||||
{name: "AtomicAdd32", argLength: 3, typ: "(UInt32,Mem)"}, // Do *arg0 += arg1. arg2=memory. Returns sum and new memory.
|
||||
{name: "AtomicAdd64", argLength: 3, typ: "(UInt64,Mem)"}, // Do *arg0 += arg1. arg2=memory. Returns sum and new memory.
|
||||
{name: "AtomicCompareAndSwap32", argLength: 4, typ: "(Bool,Mem)"}, // if *arg0==arg1, then set *arg0=arg2. Returns true iff store happens and new memory.
|
||||
{name: "AtomicCompareAndSwap64", argLength: 4, typ: "(Bool,Mem)"}, // if *arg0==arg1, then set *arg0=arg2. Returns true iff store happens and new memory.
|
||||
{name: "AtomicAnd8", argLength: 3, typ: "Mem"}, // *arg0 &= arg1. arg2=memory. Returns memory.
|
||||
{name: "AtomicOr8", argLength: 3, typ: "Mem"}, // *arg0 |= arg1. arg2=memory. Returns memory.
|
||||
{name: "AtomicLoad32", argLength: 2, typ: "(UInt32,Mem)"}, // Load from arg0. arg1=memory. Returns loaded value and new memory.
|
||||
{name: "AtomicLoad64", argLength: 2, typ: "(UInt64,Mem)"}, // Load from arg0. arg1=memory. Returns loaded value and new memory.
|
||||
{name: "AtomicLoadPtr", argLength: 2, typ: "(BytePtr,Mem)"}, // Load from arg0. arg1=memory. Returns loaded value and new memory.
|
||||
{name: "AtomicStore32", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns memory.
|
||||
{name: "AtomicStore64", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns memory.
|
||||
{name: "AtomicStorePtrNoWB", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns memory.
|
||||
{name: "AtomicExchange32", argLength: 3, typ: "(UInt32,Mem)", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns old contents of *arg0 and new memory.
|
||||
{name: "AtomicExchange64", argLength: 3, typ: "(UInt64,Mem)", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns old contents of *arg0 and new memory.
|
||||
{name: "AtomicAdd32", argLength: 3, typ: "(UInt32,Mem)", hasSideEffects: true}, // Do *arg0 += arg1. arg2=memory. Returns sum and new memory.
|
||||
{name: "AtomicAdd64", argLength: 3, typ: "(UInt64,Mem)", hasSideEffects: true}, // Do *arg0 += arg1. arg2=memory. Returns sum and new memory.
|
||||
{name: "AtomicCompareAndSwap32", argLength: 4, typ: "(Bool,Mem)", hasSideEffects: true}, // if *arg0==arg1, then set *arg0=arg2. Returns true iff store happens and new memory.
|
||||
{name: "AtomicCompareAndSwap64", argLength: 4, typ: "(Bool,Mem)", hasSideEffects: true}, // if *arg0==arg1, then set *arg0=arg2. Returns true iff store happens and new memory.
|
||||
{name: "AtomicAnd8", argLength: 3, typ: "Mem", hasSideEffects: true}, // *arg0 &= arg1. arg2=memory. Returns memory.
|
||||
{name: "AtomicOr8", argLength: 3, typ: "Mem", hasSideEffects: true}, // *arg0 |= arg1. arg2=memory. Returns memory.
|
||||
}
|
||||
|
||||
// kind control successors implicit exit
|
||||
|
||||
@@ -52,6 +52,7 @@ type opData struct {
|
||||
faultOnNilArg0 bool // this op will fault if arg0 is nil (and aux encodes a small offset)
|
||||
faultOnNilArg1 bool // this op will fault if arg1 is nil (and aux encodes a small offset)
|
||||
usesScratch bool // this op requires scratch memory space
|
||||
hasSideEffects bool // for "reasons", not to be eliminated. E.g., atomic store, #19182.
|
||||
}
|
||||
|
||||
type blockData struct {
|
||||
@@ -208,6 +209,9 @@ func genOp() {
|
||||
if v.usesScratch {
|
||||
fmt.Fprintln(w, "usesScratch: true,")
|
||||
}
|
||||
if v.hasSideEffects {
|
||||
fmt.Fprintln(w, "hasSideEffects: true,")
|
||||
}
|
||||
if a.name == "generic" {
|
||||
fmt.Fprintln(w, "generic:true,")
|
||||
fmt.Fprintln(w, "},") // close op
|
||||
|
||||
@@ -33,13 +33,24 @@ type loop struct {
|
||||
|
||||
// outerinner records that outer contains inner
|
||||
func (sdom SparseTree) outerinner(outer, inner *loop) {
|
||||
// There could be other outer loops found in some random order,
|
||||
// locate the new outer loop appropriately among them.
|
||||
oldouter := inner.outer
|
||||
if oldouter == nil || sdom.isAncestorEq(oldouter.header, outer.header) {
|
||||
inner.outer = outer
|
||||
outer.isInner = false
|
||||
if inner.containsCall {
|
||||
outer.setContainsCall()
|
||||
}
|
||||
for oldouter != nil && sdom.isAncestor(outer.header, oldouter.header) {
|
||||
inner = oldouter
|
||||
oldouter = inner.outer
|
||||
}
|
||||
if outer == oldouter {
|
||||
return
|
||||
}
|
||||
if oldouter != nil {
|
||||
outer.outer = oldouter
|
||||
}
|
||||
|
||||
inner.outer = outer
|
||||
outer.isInner = false
|
||||
if inner.containsCall {
|
||||
outer.setContainsCall()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
87
src/cmd/compile/internal/ssa/loop_test.go
Normal file
87
src/cmd/compile/internal/ssa/loop_test.go
Normal file
@@ -0,0 +1,87 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ssa
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLoopConditionS390X(t *testing.T) {
|
||||
// Test that a simple loop condition does not generate a conditional
|
||||
// move (issue #19227).
|
||||
//
|
||||
// MOVDLT is generated when Less64 is lowered but should be
|
||||
// optimized into an LT branch.
|
||||
//
|
||||
// For example, compiling the following loop:
|
||||
//
|
||||
// for i := 0; i < N; i++ {
|
||||
// sum += 3
|
||||
// }
|
||||
//
|
||||
// should generate assembly similar to:
|
||||
// loop:
|
||||
// CMP R0, R1
|
||||
// BGE done
|
||||
// ADD $3, R4
|
||||
// ADD $1, R1
|
||||
// BR loop
|
||||
// done:
|
||||
//
|
||||
// rather than:
|
||||
// loop:
|
||||
// MOVD $0, R2
|
||||
// MOVD $1, R3
|
||||
// CMP R0, R1
|
||||
// MOVDLT R2, R3
|
||||
// CMPW R2, $0
|
||||
// BNE done
|
||||
// ADD $3, R4
|
||||
// ADD $1, R1
|
||||
// BR loop
|
||||
// done:
|
||||
//
|
||||
c := testConfigS390X(t)
|
||||
fun := Fun(c, "entry",
|
||||
Bloc("entry",
|
||||
Valu("mem", OpInitMem, TypeMem, 0, nil),
|
||||
Valu("SP", OpSP, TypeUInt64, 0, nil),
|
||||
Valu("Nptr", OpOffPtr, TypeInt64Ptr, 8, nil, "SP"),
|
||||
Valu("ret", OpOffPtr, TypeInt64Ptr, 16, nil, "SP"),
|
||||
Valu("N", OpLoad, TypeInt64, 0, nil, "Nptr", "mem"),
|
||||
Valu("starti", OpConst64, TypeInt64, 0, nil),
|
||||
Valu("startsum", OpConst64, TypeInt64, 0, nil),
|
||||
Goto("b1")),
|
||||
Bloc("b1",
|
||||
Valu("phii", OpPhi, TypeInt64, 0, nil, "starti", "i"),
|
||||
Valu("phisum", OpPhi, TypeInt64, 0, nil, "startsum", "sum"),
|
||||
Valu("cmp1", OpLess64, TypeBool, 0, nil, "phii", "N"),
|
||||
If("cmp1", "b2", "b3")),
|
||||
Bloc("b2",
|
||||
Valu("c1", OpConst64, TypeInt64, 1, nil),
|
||||
Valu("i", OpAdd64, TypeInt64, 0, nil, "phii", "c1"),
|
||||
Valu("c3", OpConst64, TypeInt64, 3, nil),
|
||||
Valu("sum", OpAdd64, TypeInt64, 0, nil, "phisum", "c3"),
|
||||
Goto("b1")),
|
||||
Bloc("b3",
|
||||
Valu("store", OpStore, TypeMem, 8, nil, "ret", "phisum", "mem"),
|
||||
Exit("store")))
|
||||
CheckFunc(fun.f)
|
||||
Compile(fun.f)
|
||||
CheckFunc(fun.f)
|
||||
|
||||
checkOpcodeCounts(t, fun.f, map[Op]int{
|
||||
OpS390XMOVDLT: 0,
|
||||
OpS390XMOVDGT: 0,
|
||||
OpS390XMOVDLE: 0,
|
||||
OpS390XMOVDGE: 0,
|
||||
OpS390XMOVDEQ: 0,
|
||||
OpS390XMOVDNE: 0,
|
||||
OpS390XCMP: 1,
|
||||
OpS390XCMPWconst: 0,
|
||||
})
|
||||
|
||||
fun.f.Free()
|
||||
}
|
||||
@@ -82,7 +82,7 @@ func nilcheckelim(f *Func) {
|
||||
}
|
||||
}
|
||||
|
||||
// Next, process values in the block.
|
||||
// Next, eliminate any redundant nil checks in this block.
|
||||
i := 0
|
||||
for _, v := range b.Values {
|
||||
b.Values[i] = v
|
||||
@@ -105,13 +105,10 @@ func nilcheckelim(f *Func) {
|
||||
f.Config.Warnl(v.Line, "removed nil check")
|
||||
}
|
||||
v.reset(OpUnknown)
|
||||
// TODO: f.freeValue(v)
|
||||
i--
|
||||
continue
|
||||
}
|
||||
// Record the fact that we know ptr is non nil, and remember to
|
||||
// undo that information when this dominator subtree is done.
|
||||
nonNilValues[ptr.ID] = true
|
||||
work = append(work, bp{op: ClearPtr, ptr: ptr})
|
||||
}
|
||||
}
|
||||
for j := i; j < len(b.Values); j++ {
|
||||
@@ -119,6 +116,21 @@ func nilcheckelim(f *Func) {
|
||||
}
|
||||
b.Values = b.Values[:i]
|
||||
|
||||
// Finally, find redundant nil checks for subsequent blocks.
|
||||
// Note that we can't add these until the loop above is done, as the
|
||||
// values in the block are not ordered in any way when this pass runs.
|
||||
// This was the cause of issue #18725.
|
||||
for _, v := range b.Values {
|
||||
if v.Op != OpNilCheck {
|
||||
continue
|
||||
}
|
||||
ptr := v.Args[0]
|
||||
// Record the fact that we know ptr is non nil, and remember to
|
||||
// undo that information when this dominator subtree is done.
|
||||
nonNilValues[ptr.ID] = true
|
||||
work = append(work, bp{op: ClearPtr, ptr: ptr})
|
||||
}
|
||||
|
||||
// Add all dominated blocks to the work list.
|
||||
for w := sdom[node.block.ID].child; w != nil; w = sdom[w.ID].sibling {
|
||||
work = append(work, bp{op: Work, block: w})
|
||||
|
||||
@@ -34,6 +34,7 @@ type opInfo struct {
|
||||
faultOnNilArg0 bool // this op will fault if arg0 is nil (and aux encodes a small offset)
|
||||
faultOnNilArg1 bool // this op will fault if arg1 is nil (and aux encodes a small offset)
|
||||
usesScratch bool // this op requires scratch memory space
|
||||
hasSideEffects bool // for "reasons", not to be eliminated. E.g., atomic store, #19182.
|
||||
}
|
||||
|
||||
type inputInfo struct {
|
||||
|
||||
@@ -1473,6 +1473,8 @@ const (
|
||||
OpS390XMOVHZreg
|
||||
OpS390XMOVWreg
|
||||
OpS390XMOVWZreg
|
||||
OpS390XMOVDreg
|
||||
OpS390XMOVDnop
|
||||
OpS390XMOVDconst
|
||||
OpS390XCFDBRA
|
||||
OpS390XCGDBRA
|
||||
@@ -7305,6 +7307,7 @@ var opcodeTable = [...]opInfo{
|
||||
argLen: 3,
|
||||
resultInArg0: true,
|
||||
faultOnNilArg1: true,
|
||||
hasSideEffects: true,
|
||||
asm: x86.AXCHGL,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
@@ -7322,6 +7325,7 @@ var opcodeTable = [...]opInfo{
|
||||
argLen: 3,
|
||||
resultInArg0: true,
|
||||
faultOnNilArg1: true,
|
||||
hasSideEffects: true,
|
||||
asm: x86.AXCHGQ,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
@@ -7340,6 +7344,7 @@ var opcodeTable = [...]opInfo{
|
||||
resultInArg0: true,
|
||||
clobberFlags: true,
|
||||
faultOnNilArg1: true,
|
||||
hasSideEffects: true,
|
||||
asm: x86.AXADDL,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
@@ -7358,6 +7363,7 @@ var opcodeTable = [...]opInfo{
|
||||
resultInArg0: true,
|
||||
clobberFlags: true,
|
||||
faultOnNilArg1: true,
|
||||
hasSideEffects: true,
|
||||
asm: x86.AXADDQ,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
@@ -7385,6 +7391,7 @@ var opcodeTable = [...]opInfo{
|
||||
argLen: 4,
|
||||
clobberFlags: true,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
asm: x86.ACMPXCHGL,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
@@ -7405,6 +7412,7 @@ var opcodeTable = [...]opInfo{
|
||||
argLen: 4,
|
||||
clobberFlags: true,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
asm: x86.ACMPXCHGQ,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
@@ -7425,6 +7433,7 @@ var opcodeTable = [...]opInfo{
|
||||
argLen: 3,
|
||||
clobberFlags: true,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
asm: x86.AANDB,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
@@ -7439,6 +7448,7 @@ var opcodeTable = [...]opInfo{
|
||||
argLen: 3,
|
||||
clobberFlags: true,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
asm: x86.AORB,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
@@ -10073,6 +10083,7 @@ var opcodeTable = [...]opInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
|
||||
},
|
||||
clobbers: 2147483648, // F15
|
||||
outputs: []outputInfo{
|
||||
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
|
||||
},
|
||||
@@ -10086,6 +10097,7 @@ var opcodeTable = [...]opInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
|
||||
},
|
||||
clobbers: 2147483648, // F15
|
||||
outputs: []outputInfo{
|
||||
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
|
||||
},
|
||||
@@ -10099,6 +10111,7 @@ var opcodeTable = [...]opInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
|
||||
},
|
||||
clobbers: 2147483648, // F15
|
||||
outputs: []outputInfo{
|
||||
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
|
||||
},
|
||||
@@ -10112,6 +10125,7 @@ var opcodeTable = [...]opInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
|
||||
},
|
||||
clobbers: 2147483648, // F15
|
||||
outputs: []outputInfo{
|
||||
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
|
||||
},
|
||||
@@ -10125,6 +10139,7 @@ var opcodeTable = [...]opInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
|
||||
},
|
||||
clobbers: 2147483648, // F15
|
||||
outputs: []outputInfo{
|
||||
{0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
|
||||
},
|
||||
@@ -10138,6 +10153,7 @@ var opcodeTable = [...]opInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
|
||||
},
|
||||
clobbers: 2147483648, // F15
|
||||
outputs: []outputInfo{
|
||||
{0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
|
||||
},
|
||||
@@ -10151,6 +10167,7 @@ var opcodeTable = [...]opInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
|
||||
},
|
||||
clobbers: 2147483648, // F15
|
||||
outputs: []outputInfo{
|
||||
{0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
|
||||
},
|
||||
@@ -10164,6 +10181,7 @@ var opcodeTable = [...]opInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
|
||||
},
|
||||
clobbers: 2147483648, // F15
|
||||
outputs: []outputInfo{
|
||||
{0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
|
||||
},
|
||||
@@ -12655,6 +12673,7 @@ var opcodeTable = [...]opInfo{
|
||||
name: "STLR",
|
||||
argLen: 3,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
asm: arm64.ASTLR,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
@@ -12667,6 +12686,7 @@ var opcodeTable = [...]opInfo{
|
||||
name: "STLRW",
|
||||
argLen: 3,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
asm: arm64.ASTLRW,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
@@ -12680,6 +12700,7 @@ var opcodeTable = [...]opInfo{
|
||||
argLen: 3,
|
||||
resultNotInArgs: true,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
|
||||
@@ -12695,6 +12716,7 @@ var opcodeTable = [...]opInfo{
|
||||
argLen: 3,
|
||||
resultNotInArgs: true,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
|
||||
@@ -12710,6 +12732,7 @@ var opcodeTable = [...]opInfo{
|
||||
argLen: 3,
|
||||
resultNotInArgs: true,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
|
||||
@@ -12725,6 +12748,7 @@ var opcodeTable = [...]opInfo{
|
||||
argLen: 3,
|
||||
resultNotInArgs: true,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
|
||||
@@ -12741,6 +12765,7 @@ var opcodeTable = [...]opInfo{
|
||||
resultNotInArgs: true,
|
||||
clobberFlags: true,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
|
||||
@@ -12758,6 +12783,7 @@ var opcodeTable = [...]opInfo{
|
||||
resultNotInArgs: true,
|
||||
clobberFlags: true,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
|
||||
@@ -12773,6 +12799,7 @@ var opcodeTable = [...]opInfo{
|
||||
name: "LoweredAtomicAnd8",
|
||||
argLen: 3,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
asm: arm64.AAND,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
@@ -12785,6 +12812,7 @@ var opcodeTable = [...]opInfo{
|
||||
name: "LoweredAtomicOr8",
|
||||
argLen: 3,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
asm: arm64.AORR,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
@@ -13975,6 +14003,7 @@ var opcodeTable = [...]opInfo{
|
||||
name: "LoweredAtomicStore",
|
||||
argLen: 3,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{1, 469762046}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R28 g R31
|
||||
@@ -13986,6 +14015,7 @@ var opcodeTable = [...]opInfo{
|
||||
name: "LoweredAtomicStorezero",
|
||||
argLen: 2,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 140738025226238}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R28 SP g R31 SB
|
||||
@@ -13997,6 +14027,7 @@ var opcodeTable = [...]opInfo{
|
||||
argLen: 3,
|
||||
resultNotInArgs: true,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{1, 469762046}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R28 g R31
|
||||
@@ -14012,6 +14043,7 @@ var opcodeTable = [...]opInfo{
|
||||
argLen: 3,
|
||||
resultNotInArgs: true,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{1, 469762046}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R28 g R31
|
||||
@@ -14028,6 +14060,7 @@ var opcodeTable = [...]opInfo{
|
||||
argLen: 2,
|
||||
resultNotInArgs: true,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 140738025226238}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R28 SP g R31 SB
|
||||
@@ -14042,6 +14075,7 @@ var opcodeTable = [...]opInfo{
|
||||
argLen: 4,
|
||||
resultNotInArgs: true,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{1, 469762046}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R28 g R31
|
||||
@@ -14057,6 +14091,7 @@ var opcodeTable = [...]opInfo{
|
||||
name: "LoweredAtomicAnd",
|
||||
argLen: 3,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
asm: mips.AAND,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
@@ -14069,6 +14104,7 @@ var opcodeTable = [...]opInfo{
|
||||
name: "LoweredAtomicOr",
|
||||
argLen: 3,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
asm: mips.AOR,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
@@ -18570,6 +18606,32 @@ var opcodeTable = [...]opInfo{
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "MOVDreg",
|
||||
argLen: 1,
|
||||
asm: s390x.AMOVD,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
|
||||
},
|
||||
outputs: []outputInfo{
|
||||
{0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "MOVDnop",
|
||||
argLen: 1,
|
||||
resultInArg0: true,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
|
||||
},
|
||||
outputs: []outputInfo{
|
||||
{0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "MOVDconst",
|
||||
auxType: auxInt64,
|
||||
@@ -19472,6 +19534,7 @@ var opcodeTable = [...]opInfo{
|
||||
argLen: 3,
|
||||
clobberFlags: true,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
asm: s390x.AMOVW,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
@@ -19486,6 +19549,7 @@ var opcodeTable = [...]opInfo{
|
||||
argLen: 3,
|
||||
clobberFlags: true,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
asm: s390x.AMOVD,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
@@ -19499,6 +19563,7 @@ var opcodeTable = [...]opInfo{
|
||||
auxType: auxSymOff,
|
||||
argLen: 3,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
asm: s390x.ALAA,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
@@ -19515,6 +19580,7 @@ var opcodeTable = [...]opInfo{
|
||||
auxType: auxSymOff,
|
||||
argLen: 3,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
asm: s390x.ALAAG,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
@@ -19542,6 +19608,7 @@ var opcodeTable = [...]opInfo{
|
||||
argLen: 4,
|
||||
clobberFlags: true,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
asm: s390x.ACS,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
@@ -19562,6 +19629,7 @@ var opcodeTable = [...]opInfo{
|
||||
argLen: 4,
|
||||
clobberFlags: true,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
asm: s390x.ACSG,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
@@ -19582,6 +19650,7 @@ var opcodeTable = [...]opInfo{
|
||||
argLen: 3,
|
||||
clobberFlags: true,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
asm: s390x.ACS,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
@@ -19600,6 +19669,7 @@ var opcodeTable = [...]opInfo{
|
||||
argLen: 3,
|
||||
clobberFlags: true,
|
||||
faultOnNilArg0: true,
|
||||
hasSideEffects: true,
|
||||
asm: s390x.ACSG,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
@@ -21387,59 +21457,70 @@ var opcodeTable = [...]opInfo{
|
||||
generic: true,
|
||||
},
|
||||
{
|
||||
name: "AtomicStore32",
|
||||
argLen: 3,
|
||||
generic: true,
|
||||
name: "AtomicStore32",
|
||||
argLen: 3,
|
||||
hasSideEffects: true,
|
||||
generic: true,
|
||||
},
|
||||
{
|
||||
name: "AtomicStore64",
|
||||
argLen: 3,
|
||||
generic: true,
|
||||
name: "AtomicStore64",
|
||||
argLen: 3,
|
||||
hasSideEffects: true,
|
||||
generic: true,
|
||||
},
|
||||
{
|
||||
name: "AtomicStorePtrNoWB",
|
||||
argLen: 3,
|
||||
generic: true,
|
||||
name: "AtomicStorePtrNoWB",
|
||||
argLen: 3,
|
||||
hasSideEffects: true,
|
||||
generic: true,
|
||||
},
|
||||
{
|
||||
name: "AtomicExchange32",
|
||||
argLen: 3,
|
||||
generic: true,
|
||||
name: "AtomicExchange32",
|
||||
argLen: 3,
|
||||
hasSideEffects: true,
|
||||
generic: true,
|
||||
},
|
||||
{
|
||||
name: "AtomicExchange64",
|
||||
argLen: 3,
|
||||
generic: true,
|
||||
name: "AtomicExchange64",
|
||||
argLen: 3,
|
||||
hasSideEffects: true,
|
||||
generic: true,
|
||||
},
|
||||
{
|
||||
name: "AtomicAdd32",
|
||||
argLen: 3,
|
||||
generic: true,
|
||||
name: "AtomicAdd32",
|
||||
argLen: 3,
|
||||
hasSideEffects: true,
|
||||
generic: true,
|
||||
},
|
||||
{
|
||||
name: "AtomicAdd64",
|
||||
argLen: 3,
|
||||
generic: true,
|
||||
name: "AtomicAdd64",
|
||||
argLen: 3,
|
||||
hasSideEffects: true,
|
||||
generic: true,
|
||||
},
|
||||
{
|
||||
name: "AtomicCompareAndSwap32",
|
||||
argLen: 4,
|
||||
generic: true,
|
||||
name: "AtomicCompareAndSwap32",
|
||||
argLen: 4,
|
||||
hasSideEffects: true,
|
||||
generic: true,
|
||||
},
|
||||
{
|
||||
name: "AtomicCompareAndSwap64",
|
||||
argLen: 4,
|
||||
generic: true,
|
||||
name: "AtomicCompareAndSwap64",
|
||||
argLen: 4,
|
||||
hasSideEffects: true,
|
||||
generic: true,
|
||||
},
|
||||
{
|
||||
name: "AtomicAnd8",
|
||||
argLen: 3,
|
||||
generic: true,
|
||||
name: "AtomicAnd8",
|
||||
argLen: 3,
|
||||
hasSideEffects: true,
|
||||
generic: true,
|
||||
},
|
||||
{
|
||||
name: "AtomicOr8",
|
||||
argLen: 3,
|
||||
generic: true,
|
||||
name: "AtomicOr8",
|
||||
argLen: 3,
|
||||
hasSideEffects: true,
|
||||
generic: true,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -1699,6 +1699,24 @@ sinking:
|
||||
}
|
||||
p := d.Preds[0].b // block in loop exiting to d.
|
||||
|
||||
// Check that the spill value is still live at the start of d.
|
||||
// If it isn't, we can't move the spill here because some other value
|
||||
// may be using the same stack slot. See issue 20472.
|
||||
// The spill value can't be defined in d, so that makes our lives easier.
|
||||
for _, x := range stacklive[d.ID] {
|
||||
if x == vsp.ID {
|
||||
goto stillLive
|
||||
}
|
||||
}
|
||||
for _, v := range d.Values {
|
||||
if v.Op == OpLoadReg && v.Args[0] == vsp {
|
||||
goto stillLive
|
||||
}
|
||||
}
|
||||
// Spill is not live - abort sinking this spill.
|
||||
continue sinking
|
||||
stillLive:
|
||||
|
||||
endregs := s.endRegs[p.ID]
|
||||
for _, regrec := range endregs {
|
||||
if regrec.v == e && regrec.r != noRegister && regrec.c == e { // TODO: regrec.c != e implies different spill possible.
|
||||
|
||||
@@ -31,3 +31,68 @@ func TestLiveControlOps(t *testing.T) {
|
||||
regalloc(f.f)
|
||||
checkFunc(f.f)
|
||||
}
|
||||
|
||||
func TestSpillMove(t *testing.T) {
|
||||
// Test for issue 20472. We shouldn't move a spill out to exit blocks
|
||||
// if there is an exit block where the spill is dead but the pre-spill
|
||||
// value is live.
|
||||
c := testConfig(t)
|
||||
ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing
|
||||
arg1Aux := c.fe.Auto(TypeInt64)
|
||||
arg2Aux := c.fe.Auto(ptrType)
|
||||
f := Fun(c, "entry",
|
||||
Bloc("entry",
|
||||
Valu("mem", OpInitMem, TypeMem, 0, nil),
|
||||
Valu("x", OpArg, TypeInt64, 0, arg1Aux),
|
||||
Valu("p", OpArg, ptrType, 0, arg2Aux),
|
||||
Valu("a", OpAMD64TESTQ, TypeFlags, 0, nil, "x", "x"),
|
||||
Goto("loop1"),
|
||||
),
|
||||
Bloc("loop1",
|
||||
Valu("y", OpAMD64MULQ, TypeInt64, 0, nil, "x", "x"),
|
||||
Eq("a", "loop2", "exit1"),
|
||||
),
|
||||
Bloc("loop2",
|
||||
Eq("a", "loop1", "exit2"),
|
||||
),
|
||||
Bloc("exit1",
|
||||
// store before call, y is available in a register
|
||||
Valu("mem2", OpAMD64MOVQstore, TypeMem, 0, nil, "p", "y", "mem"),
|
||||
Valu("mem3", OpAMD64CALLstatic, TypeMem, 0, nil, "mem2"),
|
||||
Exit("mem3"),
|
||||
),
|
||||
Bloc("exit2",
|
||||
// store after call, y must be loaded from a spill location
|
||||
Valu("mem4", OpAMD64CALLstatic, TypeMem, 0, nil, "mem"),
|
||||
Valu("mem5", OpAMD64MOVQstore, TypeMem, 0, nil, "p", "y", "mem4"),
|
||||
Exit("mem5"),
|
||||
),
|
||||
)
|
||||
flagalloc(f.f)
|
||||
regalloc(f.f)
|
||||
checkFunc(f.f)
|
||||
// There should still be a spill in Loop1, and nowhere else.
|
||||
if numSpills(f.blocks["loop1"]) != 1 {
|
||||
t.Errorf("spill missing from loop1")
|
||||
}
|
||||
if numSpills(f.blocks["loop2"]) != 0 {
|
||||
t.Errorf("spill present in loop2")
|
||||
}
|
||||
if numSpills(f.blocks["exit1"]) != 0 {
|
||||
t.Errorf("spill present in exit1")
|
||||
}
|
||||
if numSpills(f.blocks["exit2"]) != 0 {
|
||||
t.Errorf("spill present in exit2")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func numSpills(b *Block) int {
|
||||
n := 0
|
||||
for _, v := range b.Values {
|
||||
if v.Op == OpStoreReg {
|
||||
n++
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
@@ -2503,6 +2503,28 @@ func rewriteValue386_Op386MOVBLSX(v *Value, config *Config) bool {
|
||||
func rewriteValue386_Op386MOVBLSXload(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVBLSXload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: (MOVBLSX x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
ptr := v.Args[0]
|
||||
v_1 := v.Args[1]
|
||||
if v_1.Op != Op386MOVBstore {
|
||||
break
|
||||
}
|
||||
off2 := v_1.AuxInt
|
||||
sym2 := v_1.Aux
|
||||
ptr2 := v_1.Args[0]
|
||||
x := v_1.Args[1]
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(Op386MOVBLSX)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBLSXload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
|
||||
// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)
|
||||
// result: (MOVBLSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
|
||||
@@ -2606,7 +2628,7 @@ func rewriteValue386_Op386MOVBload(v *Value, config *Config) bool {
|
||||
_ = b
|
||||
// match: (MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: x
|
||||
// result: (MOVBLZX x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -2622,8 +2644,7 @@ func rewriteValue386_Op386MOVBload(v *Value, config *Config) bool {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(Op386MOVBLZX)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
@@ -5248,6 +5269,28 @@ func rewriteValue386_Op386MOVWLSX(v *Value, config *Config) bool {
|
||||
func rewriteValue386_Op386MOVWLSXload(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVWLSXload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: (MOVWLSX x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
ptr := v.Args[0]
|
||||
v_1 := v.Args[1]
|
||||
if v_1.Op != Op386MOVWstore {
|
||||
break
|
||||
}
|
||||
off2 := v_1.AuxInt
|
||||
sym2 := v_1.Aux
|
||||
ptr2 := v_1.Args[0]
|
||||
x := v_1.Args[1]
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(Op386MOVWLSX)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWLSXload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
|
||||
// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)
|
||||
// result: (MOVWLSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
|
||||
@@ -5378,7 +5421,7 @@ func rewriteValue386_Op386MOVWload(v *Value, config *Config) bool {
|
||||
_ = b
|
||||
// match: (MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: x
|
||||
// result: (MOVWLZX x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -5394,8 +5437,7 @@ func rewriteValue386_Op386MOVWload(v *Value, config *Config) bool {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(Op386MOVWLZX)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -3361,6 +3361,28 @@ func rewriteValueAMD64_OpAMD64MOVBQSX(v *Value, config *Config) bool {
|
||||
func rewriteValueAMD64_OpAMD64MOVBQSXload(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVBQSXload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: (MOVBQSX x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
ptr := v.Args[0]
|
||||
v_1 := v.Args[1]
|
||||
if v_1.Op != OpAMD64MOVBstore {
|
||||
break
|
||||
}
|
||||
off2 := v_1.AuxInt
|
||||
sym2 := v_1.Aux
|
||||
ptr2 := v_1.Args[0]
|
||||
x := v_1.Args[1]
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64MOVBQSX)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBQSXload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
|
||||
// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
|
||||
// result: (MOVBQSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
|
||||
@@ -3539,7 +3561,7 @@ func rewriteValueAMD64_OpAMD64MOVBload(v *Value, config *Config) bool {
|
||||
_ = b
|
||||
// match: (MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: x
|
||||
// result: (MOVBQZX x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -3555,8 +3577,7 @@ func rewriteValueAMD64_OpAMD64MOVBload(v *Value, config *Config) bool {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpAMD64MOVBQZX)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
@@ -4834,6 +4855,28 @@ func rewriteValueAMD64_OpAMD64MOVLQSX(v *Value, config *Config) bool {
|
||||
func rewriteValueAMD64_OpAMD64MOVLQSXload(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVLQSXload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: (MOVLQSX x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
ptr := v.Args[0]
|
||||
v_1 := v.Args[1]
|
||||
if v_1.Op != OpAMD64MOVLstore {
|
||||
break
|
||||
}
|
||||
off2 := v_1.AuxInt
|
||||
sym2 := v_1.Aux
|
||||
ptr2 := v_1.Args[0]
|
||||
x := v_1.Args[1]
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64MOVLQSX)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVLQSXload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
|
||||
// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
|
||||
// result: (MOVLQSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
|
||||
@@ -5041,7 +5084,7 @@ func rewriteValueAMD64_OpAMD64MOVLload(v *Value, config *Config) bool {
|
||||
_ = b
|
||||
// match: (MOVLload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: x
|
||||
// result: (MOVLQZX x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -5057,8 +5100,7 @@ func rewriteValueAMD64_OpAMD64MOVLload(v *Value, config *Config) bool {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpAMD64MOVLQZX)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
@@ -8703,6 +8745,28 @@ func rewriteValueAMD64_OpAMD64MOVWQSX(v *Value, config *Config) bool {
|
||||
func rewriteValueAMD64_OpAMD64MOVWQSXload(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVWQSXload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: (MOVWQSX x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
ptr := v.Args[0]
|
||||
v_1 := v.Args[1]
|
||||
if v_1.Op != OpAMD64MOVWstore {
|
||||
break
|
||||
}
|
||||
off2 := v_1.AuxInt
|
||||
sym2 := v_1.Aux
|
||||
ptr2 := v_1.Args[0]
|
||||
x := v_1.Args[1]
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64MOVWQSX)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWQSXload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
|
||||
// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
|
||||
// result: (MOVWQSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
|
||||
@@ -8883,7 +8947,7 @@ func rewriteValueAMD64_OpAMD64MOVWload(v *Value, config *Config) bool {
|
||||
_ = b
|
||||
// match: (MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: x
|
||||
// result: (MOVWQZX x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -8899,8 +8963,7 @@ func rewriteValueAMD64_OpAMD64MOVWload(v *Value, config *Config) bool {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpAMD64MOVWQZX)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -5188,8 +5188,8 @@ func rewriteValueARM_OpARMMOVBUload(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)
|
||||
// result: x
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: (MOVBUreg x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -5202,11 +5202,10 @@ func rewriteValueARM_OpARMMOVBUload(v *Value, config *Config) bool {
|
||||
sym2 := v_1.Aux
|
||||
ptr2 := v_1.Args[0]
|
||||
x := v_1.Args[1]
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)) {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpARMMOVBUreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
@@ -5317,8 +5316,8 @@ func rewriteValueARM_OpARMMOVBload(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)
|
||||
// result: x
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: (MOVBreg x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -5331,11 +5330,10 @@ func rewriteValueARM_OpARMMOVBload(v *Value, config *Config) bool {
|
||||
sym2 := v_1.Aux
|
||||
ptr2 := v_1.Args[0]
|
||||
x := v_1.Args[1]
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)) {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpARMMOVBreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
@@ -5836,8 +5834,8 @@ func rewriteValueARM_OpARMMOVHUload(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)
|
||||
// result: x
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: (MOVHUreg x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -5850,11 +5848,10 @@ func rewriteValueARM_OpARMMOVHUload(v *Value, config *Config) bool {
|
||||
sym2 := v_1.Aux
|
||||
ptr2 := v_1.Args[0]
|
||||
x := v_1.Args[1]
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)) {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpARMMOVHUreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
@@ -5989,8 +5986,8 @@ func rewriteValueARM_OpARMMOVHload(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)
|
||||
// result: x
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: (MOVHreg x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -6003,11 +6000,10 @@ func rewriteValueARM_OpARMMOVHload(v *Value, config *Config) bool {
|
||||
sym2 := v_1.Aux
|
||||
ptr2 := v_1.Args[0]
|
||||
x := v_1.Args[1]
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)) {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpARMMOVHreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
@@ -14517,7 +14513,7 @@ func rewriteValueARM_OpLrot16(v *Value, config *Config) bool {
|
||||
_ = b
|
||||
// match: (Lrot16 <t> x [c])
|
||||
// cond:
|
||||
// result: (OR (SLLconst <t> x [c&15]) (SRLconst <t> x [16-c&15]))
|
||||
// result: (OR (SLLconst <t> x [c&15]) (SRLconst <t> (ZeroExt16to32 x) [16-c&15]))
|
||||
for {
|
||||
t := v.Type
|
||||
c := v.AuxInt
|
||||
@@ -14529,7 +14525,9 @@ func rewriteValueARM_OpLrot16(v *Value, config *Config) bool {
|
||||
v.AddArg(v0)
|
||||
v1 := b.NewValue0(v.Line, OpARMSRLconst, t)
|
||||
v1.AuxInt = 16 - c&15
|
||||
v1.AddArg(x)
|
||||
v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
|
||||
v2.AddArg(x)
|
||||
v1.AddArg(v2)
|
||||
v.AddArg(v1)
|
||||
return true
|
||||
}
|
||||
@@ -14554,7 +14552,7 @@ func rewriteValueARM_OpLrot8(v *Value, config *Config) bool {
|
||||
_ = b
|
||||
// match: (Lrot8 <t> x [c])
|
||||
// cond:
|
||||
// result: (OR (SLLconst <t> x [c&7]) (SRLconst <t> x [8-c&7]))
|
||||
// result: (OR (SLLconst <t> x [c&7]) (SRLconst <t> (ZeroExt8to32 x) [8-c&7]))
|
||||
for {
|
||||
t := v.Type
|
||||
c := v.AuxInt
|
||||
@@ -14566,7 +14564,9 @@ func rewriteValueARM_OpLrot8(v *Value, config *Config) bool {
|
||||
v.AddArg(v0)
|
||||
v1 := b.NewValue0(v.Line, OpARMSRLconst, t)
|
||||
v1.AuxInt = 8 - c&7
|
||||
v1.AddArg(x)
|
||||
v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
|
||||
v2.AddArg(x)
|
||||
v1.AddArg(v2)
|
||||
v.AddArg(v1)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -2625,7 +2625,7 @@ func rewriteValueARM64_OpARM64FMOVDload(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (FMOVDload [off1] {sym} (ADDconst [off2] ptr) mem)
|
||||
// cond: (off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
|
||||
// cond: is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
|
||||
// result: (FMOVDload [off1+off2] {sym} ptr mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -2637,7 +2637,7 @@ func rewriteValueARM64_OpARM64FMOVDload(v *Value, config *Config) bool {
|
||||
off2 := v_0.AuxInt
|
||||
ptr := v_0.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
|
||||
if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64FMOVDload)
|
||||
@@ -2648,7 +2648,7 @@ func rewriteValueARM64_OpARM64FMOVDload(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (FMOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
|
||||
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
|
||||
// result: (FMOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -2661,7 +2661,7 @@ func rewriteValueARM64_OpARM64FMOVDload(v *Value, config *Config) bool {
|
||||
sym2 := v_0.Aux
|
||||
ptr := v_0.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !(canMergeSym(sym1, sym2) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
|
||||
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64FMOVDload)
|
||||
@@ -2677,7 +2677,7 @@ func rewriteValueARM64_OpARM64FMOVDstore(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (FMOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem)
|
||||
// cond: (off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
|
||||
// cond: is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
|
||||
// result: (FMOVDstore [off1+off2] {sym} ptr val mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -2690,7 +2690,7 @@ func rewriteValueARM64_OpARM64FMOVDstore(v *Value, config *Config) bool {
|
||||
ptr := v_0.Args[0]
|
||||
val := v.Args[1]
|
||||
mem := v.Args[2]
|
||||
if !((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
|
||||
if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64FMOVDstore)
|
||||
@@ -2702,7 +2702,7 @@ func rewriteValueARM64_OpARM64FMOVDstore(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (FMOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
||||
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
|
||||
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
|
||||
// result: (FMOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -2716,7 +2716,7 @@ func rewriteValueARM64_OpARM64FMOVDstore(v *Value, config *Config) bool {
|
||||
ptr := v_0.Args[0]
|
||||
val := v.Args[1]
|
||||
mem := v.Args[2]
|
||||
if !(canMergeSym(sym1, sym2) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
|
||||
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64FMOVDstore)
|
||||
@@ -2733,7 +2733,7 @@ func rewriteValueARM64_OpARM64FMOVSload(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (FMOVSload [off1] {sym} (ADDconst [off2] ptr) mem)
|
||||
// cond: (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
|
||||
// cond: is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
|
||||
// result: (FMOVSload [off1+off2] {sym} ptr mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -2745,7 +2745,7 @@ func rewriteValueARM64_OpARM64FMOVSload(v *Value, config *Config) bool {
|
||||
off2 := v_0.AuxInt
|
||||
ptr := v_0.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
|
||||
if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64FMOVSload)
|
||||
@@ -2756,7 +2756,7 @@ func rewriteValueARM64_OpARM64FMOVSload(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (FMOVSload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
|
||||
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
|
||||
// result: (FMOVSload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -2769,7 +2769,7 @@ func rewriteValueARM64_OpARM64FMOVSload(v *Value, config *Config) bool {
|
||||
sym2 := v_0.Aux
|
||||
ptr := v_0.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !(canMergeSym(sym1, sym2) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
|
||||
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64FMOVSload)
|
||||
@@ -2785,7 +2785,7 @@ func rewriteValueARM64_OpARM64FMOVSstore(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (FMOVSstore [off1] {sym} (ADDconst [off2] ptr) val mem)
|
||||
// cond: (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
|
||||
// cond: is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
|
||||
// result: (FMOVSstore [off1+off2] {sym} ptr val mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -2798,7 +2798,7 @@ func rewriteValueARM64_OpARM64FMOVSstore(v *Value, config *Config) bool {
|
||||
ptr := v_0.Args[0]
|
||||
val := v.Args[1]
|
||||
mem := v.Args[2]
|
||||
if !((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
|
||||
if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64FMOVSstore)
|
||||
@@ -2810,7 +2810,7 @@ func rewriteValueARM64_OpARM64FMOVSstore(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (FMOVSstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
||||
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
|
||||
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
|
||||
// result: (FMOVSstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -2824,7 +2824,7 @@ func rewriteValueARM64_OpARM64FMOVSstore(v *Value, config *Config) bool {
|
||||
ptr := v_0.Args[0]
|
||||
val := v.Args[1]
|
||||
mem := v.Args[2]
|
||||
if !(canMergeSym(sym1, sym2) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
|
||||
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64FMOVSstore)
|
||||
@@ -3511,7 +3511,7 @@ func rewriteValueARM64_OpARM64MOVBUload(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVBUload [off1] {sym} (ADDconst [off2] ptr) mem)
|
||||
// cond:
|
||||
// cond: is32Bit(off1+off2)
|
||||
// result: (MOVBUload [off1+off2] {sym} ptr mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -3523,6 +3523,9 @@ func rewriteValueARM64_OpARM64MOVBUload(v *Value, config *Config) bool {
|
||||
off2 := v_0.AuxInt
|
||||
ptr := v_0.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !(is32Bit(off1 + off2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVBUload)
|
||||
v.AuxInt = off1 + off2
|
||||
v.Aux = sym
|
||||
@@ -3531,7 +3534,7 @@ func rewriteValueARM64_OpARM64MOVBUload(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
// cond: canMergeSym(sym1,sym2)
|
||||
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2)
|
||||
// result: (MOVBUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -3544,7 +3547,7 @@ func rewriteValueARM64_OpARM64MOVBUload(v *Value, config *Config) bool {
|
||||
sym2 := v_0.Aux
|
||||
ptr := v_0.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !(canMergeSym(sym1, sym2)) {
|
||||
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVBUload)
|
||||
@@ -3623,7 +3626,7 @@ func rewriteValueARM64_OpARM64MOVBload(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVBload [off1] {sym} (ADDconst [off2] ptr) mem)
|
||||
// cond:
|
||||
// cond: is32Bit(off1+off2)
|
||||
// result: (MOVBload [off1+off2] {sym} ptr mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -3635,6 +3638,9 @@ func rewriteValueARM64_OpARM64MOVBload(v *Value, config *Config) bool {
|
||||
off2 := v_0.AuxInt
|
||||
ptr := v_0.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !(is32Bit(off1 + off2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVBload)
|
||||
v.AuxInt = off1 + off2
|
||||
v.Aux = sym
|
||||
@@ -3643,7 +3649,7 @@ func rewriteValueARM64_OpARM64MOVBload(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (MOVBload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
// cond: canMergeSym(sym1,sym2)
|
||||
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2)
|
||||
// result: (MOVBload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -3656,7 +3662,7 @@ func rewriteValueARM64_OpARM64MOVBload(v *Value, config *Config) bool {
|
||||
sym2 := v_0.Aux
|
||||
ptr := v_0.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !(canMergeSym(sym1, sym2)) {
|
||||
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVBload)
|
||||
@@ -3735,7 +3741,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVBstore [off1] {sym} (ADDconst [off2] ptr) val mem)
|
||||
// cond:
|
||||
// cond: is32Bit(off1+off2)
|
||||
// result: (MOVBstore [off1+off2] {sym} ptr val mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -3748,6 +3754,9 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value, config *Config) bool {
|
||||
ptr := v_0.Args[0]
|
||||
val := v.Args[1]
|
||||
mem := v.Args[2]
|
||||
if !(is32Bit(off1 + off2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVBstore)
|
||||
v.AuxInt = off1 + off2
|
||||
v.Aux = sym
|
||||
@@ -3757,7 +3766,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (MOVBstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
||||
// cond: canMergeSym(sym1,sym2)
|
||||
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2)
|
||||
// result: (MOVBstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -3771,7 +3780,7 @@ func rewriteValueARM64_OpARM64MOVBstore(v *Value, config *Config) bool {
|
||||
ptr := v_0.Args[0]
|
||||
val := v.Args[1]
|
||||
mem := v.Args[2]
|
||||
if !(canMergeSym(sym1, sym2)) {
|
||||
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVBstore)
|
||||
@@ -3936,7 +3945,7 @@ func rewriteValueARM64_OpARM64MOVBstorezero(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVBstorezero [off1] {sym} (ADDconst [off2] ptr) mem)
|
||||
// cond:
|
||||
// cond: is32Bit(off1+off2)
|
||||
// result: (MOVBstorezero [off1+off2] {sym} ptr mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -3948,6 +3957,9 @@ func rewriteValueARM64_OpARM64MOVBstorezero(v *Value, config *Config) bool {
|
||||
off2 := v_0.AuxInt
|
||||
ptr := v_0.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !(is32Bit(off1 + off2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVBstorezero)
|
||||
v.AuxInt = off1 + off2
|
||||
v.Aux = sym
|
||||
@@ -3956,7 +3968,7 @@ func rewriteValueARM64_OpARM64MOVBstorezero(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (MOVBstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
// cond: canMergeSym(sym1,sym2)
|
||||
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2)
|
||||
// result: (MOVBstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -3969,7 +3981,7 @@ func rewriteValueARM64_OpARM64MOVBstorezero(v *Value, config *Config) bool {
|
||||
sym2 := v_0.Aux
|
||||
ptr := v_0.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !(canMergeSym(sym1, sym2)) {
|
||||
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVBstorezero)
|
||||
@@ -3985,7 +3997,7 @@ func rewriteValueARM64_OpARM64MOVDload(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVDload [off1] {sym} (ADDconst [off2] ptr) mem)
|
||||
// cond: (off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
|
||||
// cond: is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
|
||||
// result: (MOVDload [off1+off2] {sym} ptr mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -3997,7 +4009,7 @@ func rewriteValueARM64_OpARM64MOVDload(v *Value, config *Config) bool {
|
||||
off2 := v_0.AuxInt
|
||||
ptr := v_0.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
|
||||
if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDload)
|
||||
@@ -4008,7 +4020,7 @@ func rewriteValueARM64_OpARM64MOVDload(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (MOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
|
||||
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
|
||||
// result: (MOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -4021,7 +4033,7 @@ func rewriteValueARM64_OpARM64MOVDload(v *Value, config *Config) bool {
|
||||
sym2 := v_0.Aux
|
||||
ptr := v_0.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !(canMergeSym(sym1, sym2) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
|
||||
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDload)
|
||||
@@ -4088,7 +4100,7 @@ func rewriteValueARM64_OpARM64MOVDstore(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem)
|
||||
// cond: (off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
|
||||
// cond: is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
|
||||
// result: (MOVDstore [off1+off2] {sym} ptr val mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -4101,7 +4113,7 @@ func rewriteValueARM64_OpARM64MOVDstore(v *Value, config *Config) bool {
|
||||
ptr := v_0.Args[0]
|
||||
val := v.Args[1]
|
||||
mem := v.Args[2]
|
||||
if !((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
|
||||
if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDstore)
|
||||
@@ -4113,7 +4125,7 @@ func rewriteValueARM64_OpARM64MOVDstore(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (MOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
||||
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
|
||||
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
|
||||
// result: (MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -4127,7 +4139,7 @@ func rewriteValueARM64_OpARM64MOVDstore(v *Value, config *Config) bool {
|
||||
ptr := v_0.Args[0]
|
||||
val := v.Args[1]
|
||||
mem := v.Args[2]
|
||||
if !(canMergeSym(sym1, sym2) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
|
||||
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDstore)
|
||||
@@ -4166,7 +4178,7 @@ func rewriteValueARM64_OpARM64MOVDstorezero(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVDstorezero [off1] {sym} (ADDconst [off2] ptr) mem)
|
||||
// cond: (off1+off2)%2==8 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
|
||||
// cond: is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%2==8 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
|
||||
// result: (MOVDstorezero [off1+off2] {sym} ptr mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -4178,7 +4190,7 @@ func rewriteValueARM64_OpARM64MOVDstorezero(v *Value, config *Config) bool {
|
||||
off2 := v_0.AuxInt
|
||||
ptr := v_0.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !((off1+off2)%2 == 8 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
|
||||
if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%2 == 8 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDstorezero)
|
||||
@@ -4189,7 +4201,7 @@ func rewriteValueARM64_OpARM64MOVDstorezero(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (MOVDstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
|
||||
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
|
||||
// result: (MOVDstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -4202,7 +4214,7 @@ func rewriteValueARM64_OpARM64MOVDstorezero(v *Value, config *Config) bool {
|
||||
sym2 := v_0.Aux
|
||||
ptr := v_0.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !(canMergeSym(sym1, sym2) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
|
||||
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVDstorezero)
|
||||
@@ -4218,7 +4230,7 @@ func rewriteValueARM64_OpARM64MOVHUload(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVHUload [off1] {sym} (ADDconst [off2] ptr) mem)
|
||||
// cond: (off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
|
||||
// cond: is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
|
||||
// result: (MOVHUload [off1+off2] {sym} ptr mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -4230,7 +4242,7 @@ func rewriteValueARM64_OpARM64MOVHUload(v *Value, config *Config) bool {
|
||||
off2 := v_0.AuxInt
|
||||
ptr := v_0.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
|
||||
if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVHUload)
|
||||
@@ -4241,7 +4253,7 @@ func rewriteValueARM64_OpARM64MOVHUload(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (MOVHUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
|
||||
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
|
||||
// result: (MOVHUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -4254,7 +4266,7 @@ func rewriteValueARM64_OpARM64MOVHUload(v *Value, config *Config) bool {
|
||||
sym2 := v_0.Aux
|
||||
ptr := v_0.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !(canMergeSym(sym1, sym2) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
|
||||
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVHUload)
|
||||
@@ -4357,7 +4369,7 @@ func rewriteValueARM64_OpARM64MOVHload(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVHload [off1] {sym} (ADDconst [off2] ptr) mem)
|
||||
// cond: (off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
|
||||
// cond: is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
|
||||
// result: (MOVHload [off1+off2] {sym} ptr mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -4369,7 +4381,7 @@ func rewriteValueARM64_OpARM64MOVHload(v *Value, config *Config) bool {
|
||||
off2 := v_0.AuxInt
|
||||
ptr := v_0.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
|
||||
if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVHload)
|
||||
@@ -4380,7 +4392,7 @@ func rewriteValueARM64_OpARM64MOVHload(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (MOVHload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
|
||||
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
|
||||
// result: (MOVHload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -4393,7 +4405,7 @@ func rewriteValueARM64_OpARM64MOVHload(v *Value, config *Config) bool {
|
||||
sym2 := v_0.Aux
|
||||
ptr := v_0.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !(canMergeSym(sym1, sym2) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
|
||||
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVHload)
|
||||
@@ -4520,7 +4532,7 @@ func rewriteValueARM64_OpARM64MOVHstore(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVHstore [off1] {sym} (ADDconst [off2] ptr) val mem)
|
||||
// cond: (off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
|
||||
// cond: is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
|
||||
// result: (MOVHstore [off1+off2] {sym} ptr val mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -4533,7 +4545,7 @@ func rewriteValueARM64_OpARM64MOVHstore(v *Value, config *Config) bool {
|
||||
ptr := v_0.Args[0]
|
||||
val := v.Args[1]
|
||||
mem := v.Args[2]
|
||||
if !((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
|
||||
if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVHstore)
|
||||
@@ -4545,7 +4557,7 @@ func rewriteValueARM64_OpARM64MOVHstore(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (MOVHstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
||||
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
|
||||
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
|
||||
// result: (MOVHstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -4559,7 +4571,7 @@ func rewriteValueARM64_OpARM64MOVHstore(v *Value, config *Config) bool {
|
||||
ptr := v_0.Args[0]
|
||||
val := v.Args[1]
|
||||
mem := v.Args[2]
|
||||
if !(canMergeSym(sym1, sym2) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
|
||||
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVHstore)
|
||||
@@ -4682,7 +4694,7 @@ func rewriteValueARM64_OpARM64MOVHstorezero(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVHstorezero [off1] {sym} (ADDconst [off2] ptr) mem)
|
||||
// cond: (off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
|
||||
// cond: is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
|
||||
// result: (MOVHstorezero [off1+off2] {sym} ptr mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -4694,7 +4706,7 @@ func rewriteValueARM64_OpARM64MOVHstorezero(v *Value, config *Config) bool {
|
||||
off2 := v_0.AuxInt
|
||||
ptr := v_0.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
|
||||
if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVHstorezero)
|
||||
@@ -4705,7 +4717,7 @@ func rewriteValueARM64_OpARM64MOVHstorezero(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (MOVHstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
|
||||
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
|
||||
// result: (MOVHstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -4718,7 +4730,7 @@ func rewriteValueARM64_OpARM64MOVHstorezero(v *Value, config *Config) bool {
|
||||
sym2 := v_0.Aux
|
||||
ptr := v_0.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !(canMergeSym(sym1, sym2) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
|
||||
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVHstorezero)
|
||||
@@ -4734,7 +4746,7 @@ func rewriteValueARM64_OpARM64MOVWUload(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVWUload [off1] {sym} (ADDconst [off2] ptr) mem)
|
||||
// cond: (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
|
||||
// cond: is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
|
||||
// result: (MOVWUload [off1+off2] {sym} ptr mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -4746,7 +4758,7 @@ func rewriteValueARM64_OpARM64MOVWUload(v *Value, config *Config) bool {
|
||||
off2 := v_0.AuxInt
|
||||
ptr := v_0.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
|
||||
if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVWUload)
|
||||
@@ -4757,7 +4769,7 @@ func rewriteValueARM64_OpARM64MOVWUload(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (MOVWUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
|
||||
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
|
||||
// result: (MOVWUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -4770,7 +4782,7 @@ func rewriteValueARM64_OpARM64MOVWUload(v *Value, config *Config) bool {
|
||||
sym2 := v_0.Aux
|
||||
ptr := v_0.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !(canMergeSym(sym1, sym2) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
|
||||
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVWUload)
|
||||
@@ -4897,7 +4909,7 @@ func rewriteValueARM64_OpARM64MOVWload(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVWload [off1] {sym} (ADDconst [off2] ptr) mem)
|
||||
// cond: (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
|
||||
// cond: is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
|
||||
// result: (MOVWload [off1+off2] {sym} ptr mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -4909,7 +4921,7 @@ func rewriteValueARM64_OpARM64MOVWload(v *Value, config *Config) bool {
|
||||
off2 := v_0.AuxInt
|
||||
ptr := v_0.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
|
||||
if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVWload)
|
||||
@@ -4920,7 +4932,7 @@ func rewriteValueARM64_OpARM64MOVWload(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (MOVWload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
|
||||
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
|
||||
// result: (MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -4933,7 +4945,7 @@ func rewriteValueARM64_OpARM64MOVWload(v *Value, config *Config) bool {
|
||||
sym2 := v_0.Aux
|
||||
ptr := v_0.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !(canMergeSym(sym1, sym2) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
|
||||
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVWload)
|
||||
@@ -5108,7 +5120,7 @@ func rewriteValueARM64_OpARM64MOVWstore(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVWstore [off1] {sym} (ADDconst [off2] ptr) val mem)
|
||||
// cond: (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
|
||||
// cond: is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
|
||||
// result: (MOVWstore [off1+off2] {sym} ptr val mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -5121,7 +5133,7 @@ func rewriteValueARM64_OpARM64MOVWstore(v *Value, config *Config) bool {
|
||||
ptr := v_0.Args[0]
|
||||
val := v.Args[1]
|
||||
mem := v.Args[2]
|
||||
if !((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
|
||||
if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVWstore)
|
||||
@@ -5133,7 +5145,7 @@ func rewriteValueARM64_OpARM64MOVWstore(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (MOVWstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
||||
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
|
||||
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
|
||||
// result: (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -5147,7 +5159,7 @@ func rewriteValueARM64_OpARM64MOVWstore(v *Value, config *Config) bool {
|
||||
ptr := v_0.Args[0]
|
||||
val := v.Args[1]
|
||||
mem := v.Args[2]
|
||||
if !(canMergeSym(sym1, sym2) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
|
||||
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVWstore)
|
||||
@@ -5228,7 +5240,7 @@ func rewriteValueARM64_OpARM64MOVWstorezero(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVWstorezero [off1] {sym} (ADDconst [off2] ptr) mem)
|
||||
// cond: (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
|
||||
// cond: is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(sym))
|
||||
// result: (MOVWstorezero [off1+off2] {sym} ptr mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -5240,7 +5252,7 @@ func rewriteValueARM64_OpARM64MOVWstorezero(v *Value, config *Config) bool {
|
||||
off2 := v_0.AuxInt
|
||||
ptr := v_0.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
|
||||
if !(is32Bit(off1+off2) && !isArg(sym) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(sym))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVWstorezero)
|
||||
@@ -5251,7 +5263,7 @@ func rewriteValueARM64_OpARM64MOVWstorezero(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (MOVWstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||
// cond: canMergeSym(sym1,sym2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
|
||||
// cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1,sym2)) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isAuto(mergeSym(sym1,sym2)))
|
||||
// result: (MOVWstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
@@ -5264,7 +5276,7 @@ func rewriteValueARM64_OpARM64MOVWstorezero(v *Value, config *Config) bool {
|
||||
sym2 := v_0.Aux
|
||||
ptr := v_0.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !(canMergeSym(sym1, sym2) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
|
||||
if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2) && !isArg(mergeSym(sym1, sym2)) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isAuto(mergeSym(sym1, sym2)))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARM64MOVWstorezero)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user