mirror of
https://github.com/golang/go.git
synced 2026-01-29 23:22:06 +03:00
Compare commits
120 Commits
dev.corety
...
dev.boring
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
42cb4dcdb5 | ||
|
|
93c869ec16 | ||
|
|
6201a632a2 | ||
|
|
af56294e54 | ||
|
|
6e3cb838fc | ||
|
|
39d24b6b6d | ||
|
|
52f2e65060 | ||
|
|
0c01487988 | ||
|
|
deabc8dc44 | ||
|
|
86b7b52729 | ||
|
|
0bc83d7aaa | ||
|
|
f2a2dbe422 | ||
|
|
eb32dbc4f6 | ||
|
|
11e083e44b | ||
|
|
043302c56d | ||
|
|
20cf471364 | ||
|
|
f2ab41b02d | ||
|
|
2f048bcaf9 | ||
|
|
a6fa239225 | ||
|
|
d5efcb1ead | ||
|
|
4aff713ddb | ||
|
|
08c54565dc | ||
|
|
1da9aa90bc | ||
|
|
775b2384e7 | ||
|
|
fb11572dfd | ||
|
|
ddd775ff44 | ||
|
|
cb5b47443f | ||
|
|
33ebf73c45 | ||
|
|
065bb6eb30 | ||
|
|
367461427e | ||
|
|
497ad3015b | ||
|
|
73f9e27276 | ||
|
|
4ab59be66e | ||
|
|
4f6c6be21e | ||
|
|
e6ba6f7890 | ||
|
|
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 | ||
|
|
2a5f65a98c | ||
|
|
2f6c20b46c | ||
|
|
59f181b6fd | ||
|
|
d18087cb25 | ||
|
|
3de6e96e4b |
18
README.boringcrypto.md
Normal file
18
README.boringcrypto.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# dev.boringcrypto branch
|
||||
|
||||
We have been working inside Google on a fork of Go that uses
|
||||
BoringCrypto (the core of [BoringSSL](https://boringssl.googlesource.com/boringssl/)) for various crypto primitives, in
|
||||
furtherance of some [work related to FIPS 140-2](http://csrc.nist.gov/groups/STM/cmvp/documents/140-1/140sp/140sp2964.pdf). We have heard that
|
||||
some external users of Go would be interested in this code as well, so
|
||||
I intend to create a new branch dev.boringcrypto that will hold
|
||||
patches to make Go use BoringCrypto.
|
||||
|
||||
Unlike typical dev branches, we do not intend any eventual merge of
|
||||
this code into the master branch. Instead we intend to maintain in
|
||||
that branch the latest release plus BoringCrypto patches. In this
|
||||
sense it is a bit like dev.typealias holding go1.8+type alias patches.
|
||||
|
||||
To be clear, we are not making any statements or representations about
|
||||
the suitability of this code in relation to the FIPS 140-2 standard.
|
||||
Interested users will have to evaluate for themselves whether the code
|
||||
is useful for their own purposes.
|
||||
@@ -57,6 +57,7 @@ pkg crypto/x509, const SHA384WithRSAPSS SignatureAlgorithm
|
||||
pkg crypto/x509, const SHA512WithRSAPSS = 15
|
||||
pkg crypto/x509, const SHA512WithRSAPSS SignatureAlgorithm
|
||||
pkg crypto/x509, type UnknownAuthorityError struct, Cert *Certificate
|
||||
pkg crypto/x509, type VerifyOptions struct, IsBoring func(*Certificate) bool
|
||||
pkg database/sql, const LevelDefault = 0
|
||||
pkg database/sql, const LevelDefault IsolationLevel
|
||||
pkg database/sql, const LevelLinearizable = 7
|
||||
|
||||
@@ -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 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. It is not
|
||||
necessary to update the copyright year on files that you change.
|
||||
</p>
|
||||
|
||||
@@ -30,6 +30,39 @@ 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>
|
||||
|
||||
<h2 id="go1.7">go1.7 (released 2016/08/15)</h2>
|
||||
|
||||
<p>
|
||||
@@ -76,6 +109,13 @@ 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>
|
||||
|
||||
@@ -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>.
|
||||
@@ -799,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>
|
||||
@@ -1309,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>
|
||||
|
||||
@@ -143,7 +143,7 @@ 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.)
|
||||
@@ -221,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
|
||||
@@ -409,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>
|
||||
|
||||
1
misc/boring/VERSION
Normal file
1
misc/boring/VERSION
Normal file
@@ -0,0 +1 @@
|
||||
4
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -361,6 +361,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))
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -1312,9 +1312,32 @@ ok:
|
||||
// ../../../../runtime/type.go:/structType
|
||||
// for security, only the exported fields.
|
||||
case TSTRUCT:
|
||||
|
||||
// omitFieldForAwfulBoringCryptoKludge reports whether
|
||||
// the field t should be omitted from the reflect data.
|
||||
// In the crypto/... packages we omit an unexported field
|
||||
// named "boring", to keep from breaking client code that
|
||||
// expects rsa.PublicKey etc to have only public fields.
|
||||
// As the name suggests, this is an awful kludge, but it is
|
||||
// limited to the dev.boringcrypto branch and avoids
|
||||
// much more invasive effects elsewhere.
|
||||
omitFieldForAwfulBoringCryptoKludge := func(t *Field) bool {
|
||||
if t.Sym == nil || t.Sym.Name != "boring" || t.Sym.Pkg == nil {
|
||||
return false
|
||||
}
|
||||
path := t.Sym.Pkg.Path
|
||||
if t.Sym.Pkg == localpkg {
|
||||
path = myimportpath
|
||||
}
|
||||
return strings.HasPrefix(path, "crypto/")
|
||||
}
|
||||
|
||||
n := 0
|
||||
|
||||
for _, t1 := range t.Fields().Slice() {
|
||||
if omitFieldForAwfulBoringCryptoKludge(t1) {
|
||||
continue
|
||||
}
|
||||
dtypesym(t1.Type)
|
||||
n++
|
||||
}
|
||||
@@ -1342,6 +1365,9 @@ ok:
|
||||
ot = dextratype(s, ot, t, dataAdd)
|
||||
|
||||
for _, f := range t.Fields().Slice() {
|
||||
if omitFieldForAwfulBoringCryptoKludge(f) {
|
||||
continue
|
||||
}
|
||||
// ../../../../runtime/type.go:/structField
|
||||
ot = dnameField(s, ot, pkg, f)
|
||||
ot = dsymptr(s, ot, dtypesym(f.Type), 0)
|
||||
|
||||
@@ -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") }
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ->
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) -> (MOVDreg x)
|
||||
(MOVHZload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDreg x)
|
||||
(MOVWZload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDreg 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)
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -14517,7 +14517,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 +14529,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 +14556,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 +14568,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)
|
||||
|
||||
@@ -712,7 +712,7 @@ func rewriteValueMIPS_OpAtomicAnd8(v *Value, config *Config) bool {
|
||||
_ = b
|
||||
// match: (AtomicAnd8 ptr val mem)
|
||||
// cond: !config.BigEndian
|
||||
// result: (LoweredAtomicAnd (AND <config.fe.TypeUInt32().PtrTo()> (MOVWconst [^3]) ptr) (OR <config.fe.TypeUInt32()> (SLL <config.fe.TypeUInt32()> (ZeroExt8to32 val) (SLLconst <config.fe.TypeUInt32()> [3] (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)
|
||||
// result: (LoweredAtomicAnd (AND <config.fe.TypeUInt32().PtrTo()> (MOVWconst [^3]) ptr) (OR <config.fe.TypeUInt32()> (SLL <config.fe.TypeUInt32()> (ZeroExt8to32 val) (SLLconst <config.fe.TypeUInt32()> [3] (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] ptr))))) mem)
|
||||
for {
|
||||
ptr := v.Args[0]
|
||||
val := v.Args[1]
|
||||
@@ -750,10 +750,7 @@ func rewriteValueMIPS_OpAtomicAnd8(v *Value, config *Config) bool {
|
||||
v10.AuxInt = 3
|
||||
v11 := b.NewValue0(v.Line, OpMIPSANDconst, config.fe.TypeUInt32())
|
||||
v11.AuxInt = 3
|
||||
v12 := b.NewValue0(v.Line, OpMIPSXORconst, config.fe.TypeUInt32())
|
||||
v12.AuxInt = 3
|
||||
v12.AddArg(ptr)
|
||||
v11.AddArg(v12)
|
||||
v11.AddArg(ptr)
|
||||
v10.AddArg(v11)
|
||||
v8.AddArg(v10)
|
||||
v7.AddArg(v8)
|
||||
|
||||
@@ -524,6 +524,10 @@ func rewriteValueS390X(v *Value, config *Config) bool {
|
||||
return rewriteValueS390X_OpS390XMOVDload(v, config)
|
||||
case OpS390XMOVDloadidx:
|
||||
return rewriteValueS390X_OpS390XMOVDloadidx(v, config)
|
||||
case OpS390XMOVDnop:
|
||||
return rewriteValueS390X_OpS390XMOVDnop(v, config)
|
||||
case OpS390XMOVDreg:
|
||||
return rewriteValueS390X_OpS390XMOVDreg(v, config)
|
||||
case OpS390XMOVDstore:
|
||||
return rewriteValueS390X_OpS390XMOVDstore(v, config)
|
||||
case OpS390XMOVDstoreconst:
|
||||
@@ -3236,13 +3240,28 @@ func rewriteValueS390X_OpLoad(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (Load <t> ptr mem)
|
||||
// cond: is32BitInt(t)
|
||||
// cond: is32BitInt(t) && isSigned(t)
|
||||
// result: (MOVWload ptr mem)
|
||||
for {
|
||||
t := v.Type
|
||||
ptr := v.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !(is32BitInt(t) && isSigned(t)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpS390XMOVWload)
|
||||
v.AddArg(ptr)
|
||||
v.AddArg(mem)
|
||||
return true
|
||||
}
|
||||
// match: (Load <t> ptr mem)
|
||||
// cond: is32BitInt(t) && !isSigned(t)
|
||||
// result: (MOVWZload ptr mem)
|
||||
for {
|
||||
t := v.Type
|
||||
ptr := v.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !(is32BitInt(t)) {
|
||||
if !(is32BitInt(t) && !isSigned(t)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpS390XMOVWZload)
|
||||
@@ -3251,13 +3270,28 @@ func rewriteValueS390X_OpLoad(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (Load <t> ptr mem)
|
||||
// cond: is16BitInt(t)
|
||||
// cond: is16BitInt(t) && isSigned(t)
|
||||
// result: (MOVHload ptr mem)
|
||||
for {
|
||||
t := v.Type
|
||||
ptr := v.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !(is16BitInt(t) && isSigned(t)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpS390XMOVHload)
|
||||
v.AddArg(ptr)
|
||||
v.AddArg(mem)
|
||||
return true
|
||||
}
|
||||
// match: (Load <t> ptr mem)
|
||||
// cond: is16BitInt(t) && !isSigned(t)
|
||||
// result: (MOVHZload ptr mem)
|
||||
for {
|
||||
t := v.Type
|
||||
ptr := v.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !(is16BitInt(t)) {
|
||||
if !(is16BitInt(t) && !isSigned(t)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpS390XMOVHZload)
|
||||
@@ -3266,13 +3300,28 @@ func rewriteValueS390X_OpLoad(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (Load <t> ptr mem)
|
||||
// cond: (t.IsBoolean() || is8BitInt(t))
|
||||
// cond: is8BitInt(t) && isSigned(t)
|
||||
// result: (MOVBload ptr mem)
|
||||
for {
|
||||
t := v.Type
|
||||
ptr := v.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !(is8BitInt(t) && isSigned(t)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpS390XMOVBload)
|
||||
v.AddArg(ptr)
|
||||
v.AddArg(mem)
|
||||
return true
|
||||
}
|
||||
// match: (Load <t> ptr mem)
|
||||
// cond: (t.IsBoolean() || (is8BitInt(t) && !isSigned(t)))
|
||||
// result: (MOVBZload ptr mem)
|
||||
for {
|
||||
t := v.Type
|
||||
ptr := v.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !(t.IsBoolean() || is8BitInt(t)) {
|
||||
if !(t.IsBoolean() || (is8BitInt(t) && !isSigned(t))) {
|
||||
break
|
||||
}
|
||||
v.reset(OpS390XMOVBZload)
|
||||
@@ -6735,7 +6784,7 @@ func rewriteValueS390X_OpS390XCMPU(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (CMPU x (MOVDconst [c]))
|
||||
// cond: is32Bit(c)
|
||||
// cond: isU32Bit(c)
|
||||
// result: (CMPUconst x [int64(uint32(c))])
|
||||
for {
|
||||
x := v.Args[0]
|
||||
@@ -6744,7 +6793,7 @@ func rewriteValueS390X_OpS390XCMPU(v *Value, config *Config) bool {
|
||||
break
|
||||
}
|
||||
c := v_1.AuxInt
|
||||
if !(is32Bit(c)) {
|
||||
if !(isU32Bit(c)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpS390XCMPUconst)
|
||||
@@ -6753,7 +6802,7 @@ func rewriteValueS390X_OpS390XCMPU(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (CMPU (MOVDconst [c]) x)
|
||||
// cond: is32Bit(c)
|
||||
// cond: isU32Bit(c)
|
||||
// result: (InvertFlags (CMPUconst x [int64(uint32(c))]))
|
||||
for {
|
||||
v_0 := v.Args[0]
|
||||
@@ -6762,7 +6811,7 @@ func rewriteValueS390X_OpS390XCMPU(v *Value, config *Config) bool {
|
||||
}
|
||||
c := v_0.AuxInt
|
||||
x := v.Args[1]
|
||||
if !(is32Bit(c)) {
|
||||
if !(isU32Bit(c)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpS390XInvertFlags)
|
||||
@@ -7802,7 +7851,7 @@ func rewriteValueS390X_OpS390XMOVBZload(v *Value, config *Config) bool {
|
||||
_ = b
|
||||
// match: (MOVBZload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -7818,8 +7867,7 @@ func rewriteValueS390X_OpS390XMOVBZload(v *Value, config *Config) bool {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
@@ -7976,7 +8024,7 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
|
||||
_ = b
|
||||
// match: (MOVBZreg x:(MOVDLT (MOVDconst [c]) (MOVDconst [d]) _))
|
||||
// cond: int64(uint8(c)) == c && int64(uint8(d)) == d
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVDLT {
|
||||
@@ -7995,14 +8043,13 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
|
||||
if !(int64(uint8(c)) == c && int64(uint8(d)) == d) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBZreg x:(MOVDLE (MOVDconst [c]) (MOVDconst [d]) _))
|
||||
// cond: int64(uint8(c)) == c && int64(uint8(d)) == d
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVDLE {
|
||||
@@ -8021,14 +8068,13 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
|
||||
if !(int64(uint8(c)) == c && int64(uint8(d)) == d) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBZreg x:(MOVDGT (MOVDconst [c]) (MOVDconst [d]) _))
|
||||
// cond: int64(uint8(c)) == c && int64(uint8(d)) == d
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVDGT {
|
||||
@@ -8047,14 +8093,13 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
|
||||
if !(int64(uint8(c)) == c && int64(uint8(d)) == d) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBZreg x:(MOVDGE (MOVDconst [c]) (MOVDconst [d]) _))
|
||||
// cond: int64(uint8(c)) == c && int64(uint8(d)) == d
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVDGE {
|
||||
@@ -8073,14 +8118,13 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
|
||||
if !(int64(uint8(c)) == c && int64(uint8(d)) == d) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBZreg x:(MOVDEQ (MOVDconst [c]) (MOVDconst [d]) _))
|
||||
// cond: int64(uint8(c)) == c && int64(uint8(d)) == d
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVDEQ {
|
||||
@@ -8099,14 +8143,13 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
|
||||
if !(int64(uint8(c)) == c && int64(uint8(d)) == d) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBZreg x:(MOVDNE (MOVDconst [c]) (MOVDconst [d]) _))
|
||||
// cond: int64(uint8(c)) == c && int64(uint8(d)) == d
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVDNE {
|
||||
@@ -8125,14 +8168,13 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
|
||||
if !(int64(uint8(c)) == c && int64(uint8(d)) == d) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBZreg x:(MOVDGTnoinv (MOVDconst [c]) (MOVDconst [d]) _))
|
||||
// cond: int64(uint8(c)) == c && int64(uint8(d)) == d
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVDGTnoinv {
|
||||
@@ -8151,14 +8193,13 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
|
||||
if !(int64(uint8(c)) == c && int64(uint8(d)) == d) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBZreg x:(MOVDGEnoinv (MOVDconst [c]) (MOVDconst [d]) _))
|
||||
// cond: int64(uint8(c)) == c && int64(uint8(d)) == d
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVDGEnoinv {
|
||||
@@ -8177,27 +8218,25 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
|
||||
if !(int64(uint8(c)) == c && int64(uint8(d)) == d) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBZreg x:(MOVBZload _ _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVBZload {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBZreg x:(Arg <t>))
|
||||
// cond: is8BitInt(t) && !isSigned(t)
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpArg {
|
||||
@@ -8207,21 +8246,19 @@ func rewriteValueS390X_OpS390XMOVBZreg(v *Value, config *Config) bool {
|
||||
if !(is8BitInt(t) && !isSigned(t)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBZreg x:(MOVBZreg _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVBZreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
@@ -8349,20 +8386,19 @@ func rewriteValueS390X_OpS390XMOVBreg(v *Value, config *Config) bool {
|
||||
_ = b
|
||||
// match: (MOVBreg x:(MOVBload _ _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVBload {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBreg x:(Arg <t>))
|
||||
// cond: is8BitInt(t) && isSigned(t)
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpArg {
|
||||
@@ -8372,21 +8408,19 @@ func rewriteValueS390X_OpS390XMOVBreg(v *Value, config *Config) bool {
|
||||
if !(is8BitInt(t) && isSigned(t)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBreg x:(MOVBreg _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVBreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
@@ -9995,7 +10029,7 @@ func rewriteValueS390X_OpS390XMOVDload(v *Value, config *Config) bool {
|
||||
_ = b
|
||||
// match: (MOVDload [off] {sym} ptr (MOVDstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -10011,8 +10045,7 @@ func rewriteValueS390X_OpS390XMOVDload(v *Value, config *Config) bool {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
@@ -10164,6 +10197,82 @@ func rewriteValueS390X_OpS390XMOVDloadidx(v *Value, config *Config) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueS390X_OpS390XMOVDnop(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVDnop <t> x)
|
||||
// cond: t.Compare(x.Type) == CMPeq
|
||||
// result: x
|
||||
for {
|
||||
t := v.Type
|
||||
x := v.Args[0]
|
||||
if !(t.Compare(x.Type) == CMPeq) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVDnop (MOVDconst [c]))
|
||||
// cond:
|
||||
// result: (MOVDconst [c])
|
||||
for {
|
||||
v_0 := v.Args[0]
|
||||
if v_0.Op != OpS390XMOVDconst {
|
||||
break
|
||||
}
|
||||
c := v_0.AuxInt
|
||||
v.reset(OpS390XMOVDconst)
|
||||
v.AuxInt = c
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueS390X_OpS390XMOVDreg(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVDreg <t> x)
|
||||
// cond: t.Compare(x.Type) == CMPeq
|
||||
// result: x
|
||||
for {
|
||||
t := v.Type
|
||||
x := v.Args[0]
|
||||
if !(t.Compare(x.Type) == CMPeq) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVDreg (MOVDconst [c]))
|
||||
// cond:
|
||||
// result: (MOVDconst [c])
|
||||
for {
|
||||
v_0 := v.Args[0]
|
||||
if v_0.Op != OpS390XMOVDconst {
|
||||
break
|
||||
}
|
||||
c := v_0.AuxInt
|
||||
v.reset(OpS390XMOVDconst)
|
||||
v.AuxInt = c
|
||||
return true
|
||||
}
|
||||
// match: (MOVDreg x)
|
||||
// cond: x.Uses == 1
|
||||
// result: (MOVDnop x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if !(x.Uses == 1) {
|
||||
break
|
||||
}
|
||||
v.reset(OpS390XMOVDnop)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueS390X_OpS390XMOVDstore(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
@@ -10912,7 +11021,7 @@ func rewriteValueS390X_OpS390XMOVHZload(v *Value, config *Config) bool {
|
||||
_ = b
|
||||
// match: (MOVHZload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -10928,8 +11037,7 @@ func rewriteValueS390X_OpS390XMOVHZload(v *Value, config *Config) bool {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
@@ -11086,33 +11194,31 @@ func rewriteValueS390X_OpS390XMOVHZreg(v *Value, config *Config) bool {
|
||||
_ = b
|
||||
// match: (MOVHZreg x:(MOVBZload _ _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVBZload {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHZreg x:(MOVHZload _ _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVHZload {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHZreg x:(Arg <t>))
|
||||
// cond: (is8BitInt(t) || is16BitInt(t)) && !isSigned(t)
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpArg {
|
||||
@@ -11122,34 +11228,31 @@ func rewriteValueS390X_OpS390XMOVHZreg(v *Value, config *Config) bool {
|
||||
if !((is8BitInt(t) || is16BitInt(t)) && !isSigned(t)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHZreg x:(MOVBZreg _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVBZreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHZreg x:(MOVHZreg _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVHZreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
@@ -11277,46 +11380,43 @@ func rewriteValueS390X_OpS390XMOVHreg(v *Value, config *Config) bool {
|
||||
_ = b
|
||||
// match: (MOVHreg x:(MOVBload _ _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVBload {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHreg x:(MOVBZload _ _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVBZload {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHreg x:(MOVHload _ _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVHload {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHreg x:(Arg <t>))
|
||||
// cond: (is8BitInt(t) || is16BitInt(t)) && isSigned(t)
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpArg {
|
||||
@@ -11326,47 +11426,43 @@ func rewriteValueS390X_OpS390XMOVHreg(v *Value, config *Config) bool {
|
||||
if !((is8BitInt(t) || is16BitInt(t)) && isSigned(t)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHreg x:(MOVBreg _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVBreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHreg x:(MOVBZreg _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVBZreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVHreg x:(MOVHreg _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVHreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
@@ -12310,7 +12406,7 @@ func rewriteValueS390X_OpS390XMOVWZload(v *Value, config *Config) bool {
|
||||
_ = b
|
||||
// match: (MOVWZload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -12326,8 +12422,7 @@ func rewriteValueS390X_OpS390XMOVWZload(v *Value, config *Config) bool {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
@@ -12484,46 +12579,43 @@ func rewriteValueS390X_OpS390XMOVWZreg(v *Value, config *Config) bool {
|
||||
_ = b
|
||||
// match: (MOVWZreg x:(MOVBZload _ _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVBZload {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWZreg x:(MOVHZload _ _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVHZload {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWZreg x:(MOVWZload _ _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVWZload {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWZreg x:(Arg <t>))
|
||||
// cond: (is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && !isSigned(t)
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpArg {
|
||||
@@ -12533,47 +12625,43 @@ func rewriteValueS390X_OpS390XMOVWZreg(v *Value, config *Config) bool {
|
||||
if !((is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && !isSigned(t)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWZreg x:(MOVBZreg _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVBZreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWZreg x:(MOVHZreg _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVHZreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWZreg x:(MOVWZreg _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVWZreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
@@ -12701,72 +12789,67 @@ func rewriteValueS390X_OpS390XMOVWreg(v *Value, config *Config) bool {
|
||||
_ = b
|
||||
// match: (MOVWreg x:(MOVBload _ _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVBload {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVBZload _ _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVBZload {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVHload _ _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVHload {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVHZload _ _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVHZload {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVWload _ _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVWload {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(Arg <t>))
|
||||
// cond: (is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && isSigned(t)
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpArg {
|
||||
@@ -12776,73 +12859,67 @@ func rewriteValueS390X_OpS390XMOVWreg(v *Value, config *Config) bool {
|
||||
if !((is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && isSigned(t)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVBreg _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVBreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVBZreg _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVBZreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVHreg _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVHreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVHreg _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVHreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWreg x:(MOVWreg _))
|
||||
// cond:
|
||||
// result: x
|
||||
// result: (MOVDreg x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
if x.Op != OpS390XMOVWreg {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
@@ -18165,7 +18242,7 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
|
||||
}
|
||||
// match: (If cond yes no)
|
||||
// cond:
|
||||
// result: (NE (CMPWconst [0] (MOVBZreg cond)) yes no)
|
||||
// result: (NE (CMPWconst [0] (MOVBZreg <config.fe.TypeBool()> cond)) yes no)
|
||||
for {
|
||||
v := b.Control
|
||||
_ = v
|
||||
@@ -18175,7 +18252,7 @@ func rewriteBlockS390X(b *Block, config *Config) bool {
|
||||
b.Kind = BlockS390XNE
|
||||
v0 := b.NewValue0(v.Line, OpS390XCMPWconst, TypeFlags)
|
||||
v0.AuxInt = 0
|
||||
v1 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
|
||||
v1 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeBool())
|
||||
v1.AddArg(cond)
|
||||
v0.AddArg(v1)
|
||||
b.SetControl(v0)
|
||||
|
||||
@@ -14,6 +14,7 @@ const (
|
||||
ScoreMemory
|
||||
ScoreDefault
|
||||
ScoreFlags
|
||||
ScoreSelectCall
|
||||
ScoreControl // towards bottom of block
|
||||
)
|
||||
|
||||
@@ -110,10 +111,25 @@ func schedule(f *Func) {
|
||||
// We want all the vardefs next.
|
||||
score[v.ID] = ScoreVarDef
|
||||
case v.Type.IsMemory():
|
||||
// Schedule stores as early as possible. This tends to
|
||||
// reduce register pressure. It also helps make sure
|
||||
// VARDEF ops are scheduled before the corresponding LEA.
|
||||
score[v.ID] = ScoreMemory
|
||||
// Don't schedule independent operations after call to those functions.
|
||||
// runtime.selectgo will jump to next instruction after this call,
|
||||
// causing extra execution of those operations. Prevent it, by setting
|
||||
// priority to high value.
|
||||
if (v.Op == OpAMD64CALLstatic || v.Op == OpPPC64CALLstatic ||
|
||||
v.Op == OpARMCALLstatic || v.Op == OpARM64CALLstatic ||
|
||||
v.Op == Op386CALLstatic || v.Op == OpMIPS64CALLstatic ||
|
||||
v.Op == OpS390XCALLstatic || v.Op == OpMIPSCALLstatic) &&
|
||||
(isSameSym(v.Aux, "runtime.selectrecv") ||
|
||||
isSameSym(v.Aux, "runtime.selectrecv2") ||
|
||||
isSameSym(v.Aux, "runtime.selectsend") ||
|
||||
isSameSym(v.Aux, "runtime.selectdefault")) {
|
||||
score[v.ID] = ScoreSelectCall
|
||||
} else {
|
||||
// Schedule stores as early as possible. This tends to
|
||||
// reduce register pressure. It also helps make sure
|
||||
// VARDEF ops are scheduled before the corresponding LEA.
|
||||
score[v.ID] = ScoreMemory
|
||||
}
|
||||
case v.Op == OpSelect0 || v.Op == OpSelect1:
|
||||
// Schedule the pseudo-op of reading part of a tuple
|
||||
// immediately after the tuple-generating op, since
|
||||
@@ -132,19 +148,20 @@ func schedule(f *Func) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: make this logic permanent in types.IsMemory?
|
||||
isMem := func(v *Value) bool {
|
||||
return v.Type.IsMemory() || v.Type.IsTuple() && v.Type.FieldType(1).IsMemory()
|
||||
}
|
||||
|
||||
for _, b := range f.Blocks {
|
||||
// Find store chain for block.
|
||||
// Store chains for different blocks overwrite each other, so
|
||||
// the calculated store chain is good only for this block.
|
||||
for _, v := range b.Values {
|
||||
if v.Op != OpPhi && v.Type.IsMemory() {
|
||||
mem := v
|
||||
if v.Op == OpSelect1 {
|
||||
v = v.Args[0]
|
||||
}
|
||||
if v.Op != OpPhi && isMem(v) {
|
||||
for _, w := range v.Args {
|
||||
if w.Type.IsMemory() {
|
||||
nextMem[w.ID] = mem
|
||||
if isMem(w) {
|
||||
nextMem[w.ID] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -163,15 +180,15 @@ func schedule(f *Func) {
|
||||
uses[w.ID]++
|
||||
}
|
||||
// Any load must come before the following store.
|
||||
if v.Type.IsMemory() || !w.Type.IsMemory() {
|
||||
continue // not a load
|
||||
if !isMem(v) && isMem(w) {
|
||||
// v is a load.
|
||||
s := nextMem[w.ID]
|
||||
if s == nil || s.Block != b {
|
||||
continue
|
||||
}
|
||||
additionalArgs[s.ID] = append(additionalArgs[s.ID], v)
|
||||
uses[v.ID]++
|
||||
}
|
||||
s := nextMem[w.ID]
|
||||
if s == nil || s.Block != b {
|
||||
continue
|
||||
}
|
||||
additionalArgs[s.ID] = append(additionalArgs[s.ID], v)
|
||||
uses[v.ID]++
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1634,6 +1634,8 @@ func (p *parser) stmtBody(context string) []Stmt {
|
||||
return body
|
||||
}
|
||||
|
||||
var dummyCond = &Name{Value: "false"}
|
||||
|
||||
func (p *parser) header(forStmt bool) (init SimpleStmt, cond Expr, post SimpleStmt) {
|
||||
if p.tok == _Lbrace {
|
||||
return
|
||||
@@ -1680,7 +1682,8 @@ func (p *parser) header(forStmt bool) (init SimpleStmt, cond Expr, post SimpleSt
|
||||
case *ExprStmt:
|
||||
cond = s.X
|
||||
default:
|
||||
p.error("invalid condition, tag, or type switch guard")
|
||||
p.syntax_error(fmt.Sprintf("%s used as value", String(s)))
|
||||
cond = dummyCond // avoid follow-up error for if statements
|
||||
}
|
||||
|
||||
p.xnest = outer
|
||||
|
||||
@@ -31,4 +31,5 @@ func Init() {
|
||||
gc.Thearch.SSAMarkMoves = ssaMarkMoves
|
||||
gc.Thearch.SSAGenValue = ssaGenValue
|
||||
gc.Thearch.SSAGenBlock = ssaGenBlock
|
||||
gc.Thearch.ZeroAuto = zeroAuto
|
||||
}
|
||||
|
||||
@@ -84,6 +84,23 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, ax *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()
|
||||
for i := int64(0); i < size; i += 4 {
|
||||
p := gc.AddAsmAfter(x86.AMOVL, 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() {
|
||||
p := gc.Prog(x86.AXCHGL)
|
||||
p.From.Type = obj.TYPE_REG
|
||||
|
||||
@@ -3073,6 +3073,26 @@ func (b *builder) ccompile(p *Package, outfile string, flags []string, file stri
|
||||
desc := p.ImportPath
|
||||
output, err := b.runOut(p.Dir, desc, nil, compiler, flags, "-o", outfile, "-c", file)
|
||||
if len(output) > 0 {
|
||||
// On FreeBSD 11, when we pass -g to clang 3.8 it
|
||||
// invokes its internal assembler with -dwarf-version=2.
|
||||
// When it sees .section .note.GNU-stack, it warns
|
||||
// "DWARF2 only supports one section per compilation unit".
|
||||
// This warning makes no sense, since the section is empty,
|
||||
// but it confuses people.
|
||||
// We work around the problem by detecting the warning
|
||||
// and dropping -g and trying again.
|
||||
if bytes.Contains(output, []byte("DWARF2 only supports one section per compilation unit")) {
|
||||
newFlags := make([]string, 0, len(flags))
|
||||
for _, f := range flags {
|
||||
if !strings.HasPrefix(f, "-g") {
|
||||
newFlags = append(newFlags, f)
|
||||
}
|
||||
}
|
||||
if len(newFlags) < len(flags) {
|
||||
return b.ccompile(p, outfile, newFlags, file, compiler)
|
||||
}
|
||||
}
|
||||
|
||||
b.showOutput(p.Dir, desc, b.processOutput(output))
|
||||
if err != nil {
|
||||
err = errPrintedOutput
|
||||
|
||||
@@ -428,7 +428,7 @@ func downloadPackage(p *Package) error {
|
||||
return fmt.Errorf("cannot download, $GOPATH not set. For more details see: 'go help gopath'")
|
||||
}
|
||||
// Guard against people setting GOPATH=$GOROOT.
|
||||
if list[0] == goroot {
|
||||
if filepath.Clean(list[0]) == filepath.Clean(goroot) {
|
||||
return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: 'go help gopath'")
|
||||
}
|
||||
if _, err := os.Stat(filepath.Join(list[0], "src/cmd/go/alldocs.go")); err == nil {
|
||||
|
||||
20
src/cmd/go/go_boring_test.go
Normal file
20
src/cmd/go/go_boring_test.go
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright 2015 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_test
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestBoringInternalLink(t *testing.T) {
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
tg.tempFile("main.go", `package main
|
||||
import "crypto/sha1"
|
||||
func main() {
|
||||
sha1.New()
|
||||
}`)
|
||||
tg.run("build", "-ldflags=-w -extld=false", tg.path("main.go"))
|
||||
tg.run("build", "-ldflags=-extld=false", tg.path("main.go"))
|
||||
}
|
||||
@@ -1683,173 +1683,111 @@ func homeEnvName() string {
|
||||
}
|
||||
}
|
||||
|
||||
// Test go env missing GOPATH shows default.
|
||||
func TestMissingGOPATHEnvShowsDefault(t *testing.T) {
|
||||
func TestDefaultGOPATH(t *testing.T) {
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
tg.setenv("GOPATH", "")
|
||||
tg.tempDir("home/go")
|
||||
tg.setenv(homeEnvName(), tg.path("home"))
|
||||
|
||||
tg.run("env", "GOPATH")
|
||||
tg.grepStdout(regexp.QuoteMeta(tg.path("home/go")), "want GOPATH=$HOME/go")
|
||||
|
||||
want := filepath.Join(os.Getenv(homeEnvName()), "go")
|
||||
got := strings.TrimSpace(tg.getStdout())
|
||||
if got != want {
|
||||
t.Errorf("got %q; want %q", got, want)
|
||||
}
|
||||
tg.setenv("GOROOT", tg.path("home/go"))
|
||||
tg.run("env", "GOPATH")
|
||||
tg.grepStdoutNot(".", "want unset GOPATH because GOROOT=$HOME/go")
|
||||
|
||||
tg.setenv("GOROOT", tg.path("home/go")+"/")
|
||||
tg.run("env", "GOPATH")
|
||||
tg.grepStdoutNot(".", "want unset GOPATH because GOROOT=$HOME/go/")
|
||||
}
|
||||
|
||||
// Test go get missing GOPATH causes go get to warn if directory doesn't exist.
|
||||
func TestMissingGOPATHGetWarnsIfNotExists(t *testing.T) {
|
||||
func TestDefaultGOPATHGet(t *testing.T) {
|
||||
testenv.MustHaveExternalNetwork(t)
|
||||
|
||||
if _, err := exec.LookPath("git"); err != nil {
|
||||
t.Skip("skipping because git binary not found")
|
||||
}
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
|
||||
// setenv variables for test and defer deleting temporary home directory.
|
||||
tg.setenv("GOPATH", "")
|
||||
tmp, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("could not create tmp home: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmp)
|
||||
tg.setenv(homeEnvName(), tmp)
|
||||
tg.tempDir("home")
|
||||
tg.setenv(homeEnvName(), tg.path("home"))
|
||||
|
||||
// warn for creating directory
|
||||
tg.run("get", "-v", "github.com/golang/example/hello")
|
||||
tg.grepStderr("created GOPATH="+regexp.QuoteMeta(tg.path("home/go"))+"; see 'go help gopath'", "did not create GOPATH")
|
||||
|
||||
want := fmt.Sprintf("created GOPATH=%s; see 'go help gopath'", filepath.Join(tmp, "go"))
|
||||
got := strings.TrimSpace(tg.getStderr())
|
||||
if !strings.Contains(got, want) {
|
||||
t.Errorf("got %q; want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// Test go get missing GOPATH causes no warning if directory exists.
|
||||
func TestMissingGOPATHGetDoesntWarnIfExists(t *testing.T) {
|
||||
testenv.MustHaveExternalNetwork(t)
|
||||
|
||||
if _, err := exec.LookPath("git"); err != nil {
|
||||
t.Skip("skipping because git binary not found")
|
||||
}
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
|
||||
// setenv variables for test and defer resetting them.
|
||||
tg.setenv("GOPATH", "")
|
||||
tmp, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("could not create tmp home: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmp)
|
||||
if err := os.Mkdir(filepath.Join(tmp, "go"), 0777); err != nil {
|
||||
t.Fatalf("could not create $HOME/go: %v", err)
|
||||
}
|
||||
|
||||
tg.setenv(homeEnvName(), tmp)
|
||||
|
||||
// no warning if directory already exists
|
||||
tg.must(os.RemoveAll(tg.path("home/go")))
|
||||
tg.tempDir("home/go")
|
||||
tg.run("get", "github.com/golang/example/hello")
|
||||
tg.grepStderrNot(".", "expected no output on standard error")
|
||||
|
||||
got := strings.TrimSpace(tg.getStderr())
|
||||
if got != "" {
|
||||
t.Errorf("got %q; wants empty", got)
|
||||
}
|
||||
// error if $HOME/go is a file
|
||||
tg.must(os.RemoveAll(tg.path("home/go")))
|
||||
tg.tempFile("home/go", "")
|
||||
tg.runFail("get", "github.com/golang/example/hello")
|
||||
tg.grepStderr(`mkdir .*[/\\]go: .*(not a directory|cannot find the path)`, "expected error because $HOME/go is a file")
|
||||
}
|
||||
|
||||
// Test go get missing GOPATH fails if pointed file is not a directory.
|
||||
func TestMissingGOPATHGetFailsIfItsNotDirectory(t *testing.T) {
|
||||
testenv.MustHaveExternalNetwork(t)
|
||||
|
||||
func TestDefaultGOPATHPrintedSearchList(t *testing.T) {
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
|
||||
// setenv variables for test and defer resetting them.
|
||||
tg.setenv("GOPATH", "")
|
||||
tmp, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("could not create tmp home: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmp)
|
||||
tg.tempDir("home")
|
||||
tg.setenv(homeEnvName(), tg.path("home"))
|
||||
|
||||
path := filepath.Join(tmp, "go")
|
||||
if err := ioutil.WriteFile(path, nil, 0777); err != nil {
|
||||
t.Fatalf("could not create GOPATH at %s: %v", path, err)
|
||||
}
|
||||
tg.setenv(homeEnvName(), tmp)
|
||||
|
||||
const pkg = "github.com/golang/example/hello"
|
||||
tg.runFail("get", pkg)
|
||||
|
||||
msg := "not a directory"
|
||||
if runtime.GOOS == "windows" {
|
||||
msg = "The system cannot find the path specified."
|
||||
}
|
||||
want := fmt.Sprintf("package %s: mkdir %s: %s", pkg, filepath.Join(tmp, "go"), msg)
|
||||
got := strings.TrimSpace(tg.getStderr())
|
||||
if got != want {
|
||||
t.Errorf("got %q; wants %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// Test go install of missing package when missing GOPATH fails and shows default GOPATH.
|
||||
func TestMissingGOPATHInstallMissingPackageFailsAndShowsDefault(t *testing.T) {
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
|
||||
// setenv variables for test and defer resetting them.
|
||||
tg.setenv("GOPATH", "")
|
||||
tmp, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("could not create tmp home: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmp)
|
||||
if err := os.Mkdir(filepath.Join(tmp, "go"), 0777); err != nil {
|
||||
t.Fatalf("could not create $HOME/go: %v", err)
|
||||
}
|
||||
tg.setenv(homeEnvName(), tmp)
|
||||
|
||||
const pkg = "github.com/golang/example/hello"
|
||||
tg.runFail("install", pkg)
|
||||
|
||||
pkgPath := filepath.Join(strings.Split(pkg, "/")...)
|
||||
want := fmt.Sprintf("can't load package: package %s: cannot find package \"%s\" in any of:", pkg, pkg) +
|
||||
fmt.Sprintf("\n\t%s (from $GOROOT)", filepath.Join(runtime.GOROOT(), "src", pkgPath)) +
|
||||
fmt.Sprintf("\n\t%s (from $GOPATH)", filepath.Join(tmp, "go", "src", pkgPath))
|
||||
|
||||
got := strings.TrimSpace(tg.getStderr())
|
||||
if got != want {
|
||||
t.Errorf("got %q; wants %q", got, want)
|
||||
}
|
||||
tg.runFail("install", "github.com/golang/example/hello")
|
||||
tg.grepStderr(regexp.QuoteMeta(tg.path("home/go/src/github.com/golang/example/hello"))+`.*from \$GOPATH`, "expected default GOPATH")
|
||||
}
|
||||
|
||||
// Issue 4186. go get cannot be used to download packages to $GOROOT.
|
||||
// Test that without GOPATH set, go get should fail.
|
||||
func TestWithoutGOPATHGoGetFails(t *testing.T) {
|
||||
func TestGoGetIntoGOROOT(t *testing.T) {
|
||||
testenv.MustHaveExternalNetwork(t)
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
tg.tempDir("src")
|
||||
tg.setenv("GOPATH", "")
|
||||
tg.setenv("GOROOT", tg.path("."))
|
||||
tg.runFail("get", "-d", "golang.org/x/codereview/cmd/hgpatch")
|
||||
}
|
||||
|
||||
// Test that with GOPATH=$GOROOT, go get should fail.
|
||||
func TestWithGOPATHEqualsGOROOTGoGetFails(t *testing.T) {
|
||||
testenv.MustHaveExternalNetwork(t)
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
tg.tempDir("src")
|
||||
// Fails because GOROOT=GOPATH
|
||||
tg.setenv("GOPATH", tg.path("."))
|
||||
tg.setenv("GOROOT", tg.path("."))
|
||||
tg.runFail("get", "-d", "golang.org/x/codereview/cmd/hgpatch")
|
||||
tg.runFail("get", "-d", "github.com/golang/example/hello")
|
||||
tg.grepStderr("warning: GOPATH set to GOROOT", "go should detect GOPATH=GOROOT")
|
||||
tg.grepStderr(`\$GOPATH must not be set to \$GOROOT`, "go should detect GOPATH=GOROOT")
|
||||
|
||||
// Fails because GOROOT=GOPATH after cleaning.
|
||||
tg.setenv("GOPATH", tg.path(".")+"/")
|
||||
tg.setenv("GOROOT", tg.path("."))
|
||||
tg.runFail("get", "-d", "github.com/golang/example/hello")
|
||||
tg.grepStderr("warning: GOPATH set to GOROOT", "go should detect GOPATH=GOROOT")
|
||||
tg.grepStderr(`\$GOPATH must not be set to \$GOROOT`, "go should detect GOPATH=GOROOT")
|
||||
|
||||
tg.setenv("GOPATH", tg.path("."))
|
||||
tg.setenv("GOROOT", tg.path(".")+"/")
|
||||
tg.runFail("get", "-d", "github.com/golang/example/hello")
|
||||
tg.grepStderr("warning: GOPATH set to GOROOT", "go should detect GOPATH=GOROOT")
|
||||
tg.grepStderr(`\$GOPATH must not be set to \$GOROOT`, "go should detect GOPATH=GOROOT")
|
||||
|
||||
// Fails because GOROOT=$HOME/go so default GOPATH unset.
|
||||
tg.tempDir("home/go")
|
||||
tg.setenv(homeEnvName(), tg.path("home"))
|
||||
tg.setenv("GOPATH", "")
|
||||
tg.setenv("GOROOT", tg.path("home/go"))
|
||||
tg.runFail("get", "-d", "github.com/golang/example/hello")
|
||||
tg.grepStderr(`\$GOPATH not set`, "expected GOPATH not set")
|
||||
|
||||
tg.setenv(homeEnvName(), tg.path("home")+"/")
|
||||
tg.setenv("GOPATH", "")
|
||||
tg.setenv("GOROOT", tg.path("home/go"))
|
||||
tg.runFail("get", "-d", "github.com/golang/example/hello")
|
||||
tg.grepStderr(`\$GOPATH not set`, "expected GOPATH not set")
|
||||
|
||||
tg.setenv(homeEnvName(), tg.path("home"))
|
||||
tg.setenv("GOPATH", "")
|
||||
tg.setenv("GOROOT", tg.path("home/go")+"/")
|
||||
tg.runFail("get", "-d", "github.com/golang/example/hello")
|
||||
tg.grepStderr(`\$GOPATH not set`, "expected GOPATH not set")
|
||||
}
|
||||
|
||||
func TestLdflagsArgumentsWithSpacesIssue3941(t *testing.T) {
|
||||
@@ -2289,6 +2227,24 @@ func TestTestEmpty(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTestRaceInstall(t *testing.T) {
|
||||
if !canRace {
|
||||
t.Skip("no race detector")
|
||||
}
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
|
||||
|
||||
tg.tempDir("pkg")
|
||||
pkgdir := tg.path("pkg")
|
||||
tg.run("install", "-race", "-pkgdir="+pkgdir, "std")
|
||||
tg.run("test", "-race", "-pkgdir="+pkgdir, "-i", "-v", "empty/pkg")
|
||||
if tg.getStderr() != "" {
|
||||
t.Error("go test -i -race: rebuilds cached packages")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildDryRunWithCgo(t *testing.T) {
|
||||
if !canCgo {
|
||||
t.Skip("skipping because cgo not enabled")
|
||||
@@ -3541,8 +3497,8 @@ func TestBinaryOnlyPackages(t *testing.T) {
|
||||
tg.grepStdout("false", "did not see BinaryOnly=false for p4")
|
||||
}
|
||||
|
||||
// Issue 16050.
|
||||
func TestAlwaysLinkSysoFiles(t *testing.T) {
|
||||
// Issue 16050 and 21884.
|
||||
func TestLinkSysoFiles(t *testing.T) {
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
@@ -3561,6 +3517,10 @@ func TestAlwaysLinkSysoFiles(t *testing.T) {
|
||||
tg.setenv("CGO_ENABLED", "0")
|
||||
tg.run("list", "-f", "{{.SysoFiles}}", "syso")
|
||||
tg.grepStdout("a.syso", "missing syso file with CGO_ENABLED=0")
|
||||
|
||||
tg.setenv("CGO_ENABLED", "1")
|
||||
tg.run("list", "-msan", "-f", "{{.SysoFiles}}", "syso")
|
||||
tg.grepStdoutNot("a.syso", "unexpected syso file with -msan")
|
||||
}
|
||||
|
||||
// Issue 16120.
|
||||
@@ -3744,6 +3704,13 @@ func TestMatchesOnlySubtestParallelIsOK(t *testing.T) {
|
||||
tg.grepBoth(okPattern, "go test did not say ok")
|
||||
}
|
||||
|
||||
// Issue 18845
|
||||
func TestBenchTimeout(t *testing.T) {
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.run("test", "-bench", ".", "-timeout", "750ms", "testdata/timeoutbench_test.go")
|
||||
}
|
||||
|
||||
func TestLinkXImportPathEscape(t *testing.T) {
|
||||
// golang.org/issue/16710
|
||||
tg := testgo(t)
|
||||
|
||||
@@ -136,7 +136,7 @@ func main() {
|
||||
// Diagnose common mistake: GOPATH==GOROOT.
|
||||
// This setting is equivalent to not setting GOPATH at all,
|
||||
// which is not what most people want when they do it.
|
||||
if gopath := buildContext.GOPATH; gopath == runtime.GOROOT() {
|
||||
if gopath := buildContext.GOPATH; filepath.Clean(gopath) == filepath.Clean(runtime.GOROOT()) {
|
||||
fmt.Fprintf(os.Stderr, "warning: GOPATH set to GOROOT (%s) has no effect\n", gopath)
|
||||
} else {
|
||||
for _, p := range filepath.SplitList(gopath) {
|
||||
|
||||
@@ -173,6 +173,12 @@ func (p *Package) copyBuild(pp *build.Package) {
|
||||
p.SwigFiles = pp.SwigFiles
|
||||
p.SwigCXXFiles = pp.SwigCXXFiles
|
||||
p.SysoFiles = pp.SysoFiles
|
||||
if buildMSan {
|
||||
// There's no way for .syso files to be built both with and without
|
||||
// support for memory sanitizer. Assume they are built without,
|
||||
// and drop them.
|
||||
p.SysoFiles = nil
|
||||
}
|
||||
p.CgoCFLAGS = pp.CgoCFLAGS
|
||||
p.CgoCPPFLAGS = pp.CgoCPPFLAGS
|
||||
p.CgoCXXFLAGS = pp.CgoCXXFLAGS
|
||||
@@ -955,10 +961,6 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
|
||||
if p.Name == "main" && goarch == "arm" {
|
||||
importPaths = append(importPaths, "math")
|
||||
}
|
||||
// In coverage atomic mode everything depends on sync/atomic.
|
||||
if testCoverMode == "atomic" && (!p.Standard || (p.ImportPath != "runtime/cgo" && p.ImportPath != "runtime/race" && p.ImportPath != "sync/atomic")) {
|
||||
importPaths = append(importPaths, "sync/atomic")
|
||||
}
|
||||
}
|
||||
|
||||
// Runtime and its internal packages depend on runtime/internal/sys,
|
||||
|
||||
@@ -545,6 +545,10 @@ func runTest(cmd *Command, args []string) {
|
||||
|
||||
// Prepare build + run + print actions for all packages being tested.
|
||||
for _, p := range pkgs {
|
||||
// sync/atomic import is inserted by the cover tool. See #18486
|
||||
if testCover && testCoverMode == "atomic" {
|
||||
ensureImport(p, "sync/atomic")
|
||||
}
|
||||
buildTest, runTest, printTest, err := b.test(p)
|
||||
if err != nil {
|
||||
str := err.Error()
|
||||
@@ -636,6 +640,23 @@ func runTest(cmd *Command, args []string) {
|
||||
b.do(root)
|
||||
}
|
||||
|
||||
// ensures that package p imports the named package.
|
||||
func ensureImport(p *Package, pkg string) {
|
||||
for _, d := range p.deps {
|
||||
if d.Name == pkg {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
a := loadPackage(pkg, &importStack{})
|
||||
if a.Error != nil {
|
||||
fatalf("load %s: %v", pkg, a.Error)
|
||||
}
|
||||
computeStale(a)
|
||||
|
||||
p.imports = append(p.imports, a)
|
||||
}
|
||||
|
||||
func contains(x []string, s string) bool {
|
||||
for _, t := range x {
|
||||
if t == s {
|
||||
|
||||
10
src/cmd/go/testdata/timeoutbench_test.go
vendored
Normal file
10
src/cmd/go/testdata/timeoutbench_test.go
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
package timeoutbench_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func BenchmarkSleep1s(b *testing.B) {
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
125
src/cmd/link/dwarf_test.go
Normal file
125
src/cmd/link/dwarf_test.go
Normal file
@@ -0,0 +1,125 @@
|
||||
// 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 (
|
||||
"cmd/internal/objfile"
|
||||
"debug/dwarf"
|
||||
"internal/testenv"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDWARF(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("DWARF is not supported on Windows")
|
||||
}
|
||||
|
||||
testenv.MustHaveCGO(t)
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
if runtime.GOOS == "plan9" {
|
||||
t.Skip("skipping on plan9; no DWARF symbol table in executables")
|
||||
}
|
||||
|
||||
out, err := exec.Command(testenv.GoToolPath(t), "list", "-f", "{{.Stale}}", "cmd/link").CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("go list: %v\n%s", err, out)
|
||||
}
|
||||
if string(out) != "false\n" {
|
||||
t.Fatalf("cmd/link is stale - run go install cmd/link")
|
||||
}
|
||||
|
||||
tmpDir, err := ioutil.TempDir("", "go-link-TestDWARF")
|
||||
if err != nil {
|
||||
t.Fatal("TempDir failed: ", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
for _, prog := range []string{"testprog", "testprogcgo"} {
|
||||
t.Run(prog, func(t *testing.T) {
|
||||
exe := filepath.Join(tmpDir, prog+".exe")
|
||||
dir := "../../runtime/testdata/" + prog
|
||||
out, err := exec.Command(testenv.GoToolPath(t), "build", "-o", exe, dir).CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("go build -o %v %v: %v\n%s", exe, dir, err, out)
|
||||
}
|
||||
|
||||
f, err := objfile.Open(exe)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
syms, err := f.Symbols()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var addr uint64
|
||||
for _, sym := range syms {
|
||||
if sym.Name == "main.main" {
|
||||
addr = sym.Addr
|
||||
break
|
||||
}
|
||||
}
|
||||
if addr == 0 {
|
||||
t.Fatal("cannot find main.main in symbols")
|
||||
}
|
||||
|
||||
d, err := f.DWARF()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// TODO: We'd like to use filepath.Join here.
|
||||
// Also related: golang.org/issue/19784.
|
||||
wantFile := path.Join(prog, "main.go")
|
||||
wantLine := 24
|
||||
r := d.Reader()
|
||||
var line dwarf.LineEntry
|
||||
for {
|
||||
cu, err := r.Next()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if cu == nil {
|
||||
break
|
||||
}
|
||||
if cu.Tag != dwarf.TagCompileUnit {
|
||||
r.SkipChildren()
|
||||
continue
|
||||
}
|
||||
lr, err := d.LineReader(cu)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for {
|
||||
err := lr.Next(&line)
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if line.Address == addr {
|
||||
if !strings.HasSuffix(line.File.Name, wantFile) || line.Line != wantLine {
|
||||
t.Errorf("%#x is %s:%d, want %s:%d", addr, line.File.Name, line.Line, filepath.Join("...", wantFile), wantLine)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
t.Fatalf("did not find file:line for %#x (main.main)", addr)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -118,6 +118,17 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
|
||||
r.Add += 4
|
||||
return true
|
||||
|
||||
case 256 + ld.R_X86_64_PC64:
|
||||
if targ.Type == obj.SDYNIMPORT {
|
||||
ld.Errorf(s, "unexpected R_X86_64_PC64 relocation for dynamic symbol %s", targ.Name)
|
||||
}
|
||||
if targ.Type == 0 || targ.Type == obj.SXREF {
|
||||
ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
|
||||
}
|
||||
r.Type = obj.R_PCREL
|
||||
r.Add += 8
|
||||
return true
|
||||
|
||||
case 256 + ld.R_X86_64_PLT32:
|
||||
r.Type = obj.R_PCREL
|
||||
r.Add += 4
|
||||
|
||||
@@ -238,6 +238,8 @@ func determineLinkMode(ctxt *Link) {
|
||||
Linkmode = LinkExternal
|
||||
} else if iscgo && externalobj {
|
||||
Linkmode = LinkExternal
|
||||
} else if Buildmode == BuildmodePIE {
|
||||
Linkmode = LinkExternal // https://golang.org/issue/18968
|
||||
} else {
|
||||
Linkmode = LinkInternal
|
||||
}
|
||||
|
||||
@@ -1836,6 +1836,11 @@ func (ctxt *Link) dodata() {
|
||||
datsize = Rnd(datsize, int64(sect.Align))
|
||||
sect.Vaddr = uint64(datsize)
|
||||
for _, s := range dwarfp[i:] {
|
||||
// Syms can (incorrectly) appear twice on the list. Ignore repeats.
|
||||
// See golang.org/issue/21566.
|
||||
if s.Type == obj.SRODATA {
|
||||
continue
|
||||
}
|
||||
if s.Type != obj.SDWARFINFO {
|
||||
break
|
||||
}
|
||||
|
||||
@@ -1201,6 +1201,7 @@ func relSize(ctxt *Link, pn string, elftype uint32) uint8 {
|
||||
return 4
|
||||
|
||||
case AMD64 | R_X86_64_64<<24,
|
||||
AMD64 | R_X86_64_PC64<<24,
|
||||
PPC64 | R_PPC64_ADDR64<<24,
|
||||
S390X | R_390_GLOB_DAT<<24,
|
||||
S390X | R_390_RELATIVE<<24,
|
||||
|
||||
@@ -430,6 +430,10 @@ func (ctxt *Link) loadlib() {
|
||||
// We now have enough information to determine the link mode.
|
||||
determineLinkMode(ctxt)
|
||||
|
||||
if Headtype == obj.Hdarwin && Linkmode == LinkExternal {
|
||||
*FlagTextAddr = 0
|
||||
}
|
||||
|
||||
if Linkmode == LinkExternal && SysArch.Family == sys.PPC64 {
|
||||
toc := ctxt.Syms.Lookup(".TOC.", 0)
|
||||
toc.Type = obj.SDYNIMPORT
|
||||
@@ -804,6 +808,7 @@ var hostobj []Hostobj
|
||||
// These packages can use internal linking mode.
|
||||
// Others trigger external mode.
|
||||
var internalpkg = []string{
|
||||
"crypto/internal/boring",
|
||||
"crypto/x509",
|
||||
"net",
|
||||
"os/user",
|
||||
@@ -998,6 +1003,10 @@ func (l *Link) hostlink() {
|
||||
|
||||
if !*FlagS && !debug_s {
|
||||
argv = append(argv, "-gdwarf-2")
|
||||
} else if Headtype == obj.Hdarwin {
|
||||
// Recent versions of macOS print
|
||||
// ld: warning: option -s is obsolete and being ignored
|
||||
// so do not pass any arguments.
|
||||
} else {
|
||||
argv = append(argv, "-s")
|
||||
}
|
||||
@@ -1219,7 +1228,7 @@ func (l *Link) hostlink() {
|
||||
l.Logf("%s", out)
|
||||
}
|
||||
|
||||
if !*FlagS && !debug_s && Headtype == obj.Hdarwin {
|
||||
if !*FlagS && !*FlagW && !debug_s && Headtype == obj.Hdarwin {
|
||||
// Skip combining dwarf on arm.
|
||||
if !SysArch.InFamily(sys.ARM, sys.ARM64) {
|
||||
dsym := filepath.Join(*flagTmpdir, "go.dwarf")
|
||||
|
||||
@@ -449,7 +449,7 @@ func Asmbmacho(ctxt *Link) {
|
||||
ms.filesize = Segdata.Fileoff + Segdata.Filelen - Segtext.Fileoff
|
||||
} else {
|
||||
ms.filesize = Segdwarf.Fileoff + Segdwarf.Filelen - Segtext.Fileoff
|
||||
ms.vsize = ms.filesize
|
||||
ms.vsize = Segdwarf.Vaddr + Segdwarf.Length - Segtext.Vaddr
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
|
||||
var realdwarf, linkseg *macho.Segment
|
||||
var dwarfstart, linkstart int64
|
||||
var dwarfaddr, linkaddr int64
|
||||
var linkoffset uint32
|
||||
|
||||
const (
|
||||
@@ -41,8 +42,7 @@ const (
|
||||
LC_DYLIB_CODE_SIGN_DRS = 0x2B
|
||||
LC_ENCRYPTION_INFO_64 = 0x2C
|
||||
|
||||
dwarfMinAlign = 6 // 64 = 1 << 6
|
||||
pageAlign = 12 // 4096 = 1 << 12
|
||||
pageAlign = 12 // 4096 = 1 << 12
|
||||
)
|
||||
|
||||
type loadCmd struct {
|
||||
@@ -157,16 +157,13 @@ func machoCombineDwarf(inexe, dsym, outexe string) error {
|
||||
}
|
||||
|
||||
// Now copy the dwarf data into the output.
|
||||
maxalign := uint32(dwarfMinAlign) //
|
||||
for _, sect := range dwarfm.Sections {
|
||||
if sect.Align > maxalign {
|
||||
maxalign = sect.Align
|
||||
}
|
||||
}
|
||||
dwarfstart = machoCalcStart(realdwarf.Offset, linkseg.Offset, maxalign)
|
||||
// Kernel requires all loaded segments to be page-aligned in the file,
|
||||
// even though we mark this one as being 0 bytes of virtual address space.
|
||||
dwarfstart = machoCalcStart(realdwarf.Offset, linkseg.Offset, pageAlign)
|
||||
if _, err = outf.Seek(dwarfstart, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
dwarfaddr = int64((linkseg.Addr + linkseg.Memsz + 1<<pageAlign - 1) &^ (1<<pageAlign - 1))
|
||||
|
||||
if _, err = dwarff.Seek(int64(realdwarf.Offset), 0); err != nil {
|
||||
return err
|
||||
@@ -277,10 +274,10 @@ func machoUpdateSegment(r loadCmdReader, seg, sect interface{}) error {
|
||||
return err
|
||||
}
|
||||
// There shouldn't be any sections, but just to make sure...
|
||||
return machoUpdateSections(r, segValue, reflect.ValueOf(sect), uint64(linkoffset))
|
||||
return machoUpdateSections(r, segValue, reflect.ValueOf(sect), uint64(linkoffset), 0)
|
||||
}
|
||||
|
||||
func machoUpdateSections(r loadCmdReader, seg, sect reflect.Value, delta uint64) error {
|
||||
func machoUpdateSections(r loadCmdReader, seg, sect reflect.Value, deltaOffset, deltaAddr uint64) error {
|
||||
iseg := reflect.Indirect(seg)
|
||||
nsect := iseg.FieldByName("Nsect").Uint()
|
||||
if nsect == 0 {
|
||||
@@ -291,16 +288,20 @@ func machoUpdateSections(r loadCmdReader, seg, sect reflect.Value, delta uint64)
|
||||
isect := reflect.Indirect(sect)
|
||||
offsetField := isect.FieldByName("Offset")
|
||||
reloffField := isect.FieldByName("Reloff")
|
||||
addrField := isect.FieldByName("Addr")
|
||||
sectSize := int64(isect.Type().Size())
|
||||
for i := uint64(0); i < nsect; i++ {
|
||||
if err := r.ReadAt(sectOffset, sect.Interface()); err != nil {
|
||||
return err
|
||||
}
|
||||
if offsetField.Uint() != 0 {
|
||||
offsetField.SetUint(offsetField.Uint() + delta)
|
||||
offsetField.SetUint(offsetField.Uint() + deltaOffset)
|
||||
}
|
||||
if reloffField.Uint() != 0 {
|
||||
reloffField.SetUint(reloffField.Uint() + delta)
|
||||
reloffField.SetUint(reloffField.Uint() + deltaOffset)
|
||||
}
|
||||
if addrField.Uint() != 0 {
|
||||
addrField.SetUint(addrField.Uint() + deltaAddr)
|
||||
}
|
||||
if err := r.WriteAt(sectOffset, sect.Interface()); err != nil {
|
||||
return err
|
||||
@@ -327,15 +328,30 @@ func machoUpdateDwarfHeader(r *loadCmdReader) error {
|
||||
if err := r.ReadAt(0, seg); err != nil {
|
||||
return err
|
||||
}
|
||||
segValue := reflect.ValueOf(seg)
|
||||
offset := reflect.Indirect(segValue).FieldByName("Offset")
|
||||
segv := reflect.ValueOf(seg).Elem()
|
||||
|
||||
segv.FieldByName("Offset").SetUint(uint64(dwarfstart))
|
||||
segv.FieldByName("Addr").SetUint(uint64(dwarfaddr))
|
||||
|
||||
deltaOffset := uint64(dwarfstart) - realdwarf.Offset
|
||||
deltaAddr := uint64(dwarfaddr) - realdwarf.Addr
|
||||
|
||||
// If we set Memsz to 0 (and might as well set Addr too),
|
||||
// then the xnu kernel will bail out halfway through load_segment
|
||||
// and not apply further sanity checks that we might fail in the future.
|
||||
// We don't need the DWARF information actually available in memory.
|
||||
// But if we do this for buildmode=c-shared then the user-space
|
||||
// dynamic loader complains about memsz < filesz. Sigh.
|
||||
if Buildmode != BuildmodeCShared {
|
||||
segv.FieldByName("Addr").SetUint(0)
|
||||
segv.FieldByName("Memsz").SetUint(0)
|
||||
deltaAddr = 0
|
||||
}
|
||||
|
||||
delta := uint64(dwarfstart) - realdwarf.Offset
|
||||
offset.SetUint(offset.Uint() + delta)
|
||||
if err := r.WriteAt(0, seg); err != nil {
|
||||
return err
|
||||
}
|
||||
return machoUpdateSections(*r, segValue, reflect.ValueOf(sect), delta)
|
||||
return machoUpdateSections(*r, segv, reflect.ValueOf(sect), deltaOffset, deltaAddr)
|
||||
}
|
||||
|
||||
func machoUpdateLoadCommand(r loadCmdReader, cmd interface{}, fields ...string) error {
|
||||
|
||||
@@ -87,6 +87,7 @@ func genplt(ctxt *ld.Link) {
|
||||
//
|
||||
// This assumes "case 1" from the ABI, where the caller needs
|
||||
// us to save and restore the TOC pointer.
|
||||
var stubs []*ld.Symbol
|
||||
for _, s := range ctxt.Textp {
|
||||
for i := range s.R {
|
||||
r := &s.R[i]
|
||||
@@ -108,7 +109,7 @@ func genplt(ctxt *ld.Link) {
|
||||
if stub.Size == 0 {
|
||||
// Need outer to resolve .TOC.
|
||||
stub.Outer = s
|
||||
ctxt.Textp = append(ctxt.Textp, stub)
|
||||
stubs = append(stubs, stub)
|
||||
gencallstub(ctxt, 1, stub, r.Sym)
|
||||
}
|
||||
|
||||
@@ -121,6 +122,11 @@ func genplt(ctxt *ld.Link) {
|
||||
ctxt.Arch.ByteOrder.PutUint32(s.P[r.Off+4:], o1)
|
||||
}
|
||||
}
|
||||
// Put call stubs at the beginning (instead of the end).
|
||||
// So when resolving the relocations to calls to the stubs,
|
||||
// the addresses are known and trampolines can be inserted
|
||||
// when necessary.
|
||||
ctxt.Textp = append(stubs, ctxt.Textp...)
|
||||
}
|
||||
|
||||
func genaddmoduledata(ctxt *ld.Link) {
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
|
||||
func TestLargeText(t *testing.T) {
|
||||
if testing.Short() || (obj.GOARCH != "ppc64le" && obj.GOARCH != "ppc64" && obj.GOARCH != "arm") {
|
||||
t.Skip("Skipping large text section test in short mode or on %s", obj.GOARCH)
|
||||
t.Skipf("Skipping large text section test in short mode or on %s", obj.GOARCH)
|
||||
}
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ package aes
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"crypto/internal/boring"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
@@ -36,6 +37,9 @@ func NewCipher(key []byte) (cipher.Block, error) {
|
||||
case 16, 24, 32:
|
||||
break
|
||||
}
|
||||
if boring.Enabled {
|
||||
return boring.NewAESCipher(key)
|
||||
}
|
||||
return newCipher(key)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ package aes
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"crypto/internal/boring"
|
||||
"crypto/internal/cipherhw"
|
||||
)
|
||||
|
||||
@@ -46,6 +47,7 @@ func newCipher(key []byte) (cipher.Block, error) {
|
||||
func (c *aesCipherAsm) BlockSize() int { return BlockSize }
|
||||
|
||||
func (c *aesCipherAsm) Encrypt(dst, src []byte) {
|
||||
boring.Unreachable()
|
||||
if len(src) < BlockSize {
|
||||
panic("crypto/aes: input not full block")
|
||||
}
|
||||
@@ -56,6 +58,7 @@ func (c *aesCipherAsm) Encrypt(dst, src []byte) {
|
||||
}
|
||||
|
||||
func (c *aesCipherAsm) Decrypt(dst, src []byte) {
|
||||
boring.Unreachable()
|
||||
if len(src) < BlockSize {
|
||||
panic("crypto/aes: input not full block")
|
||||
}
|
||||
|
||||
100
src/crypto/ecdsa/boring.go
Normal file
100
src/crypto/ecdsa/boring.go
Normal file
@@ -0,0 +1,100 @@
|
||||
// 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 ecdsa
|
||||
|
||||
import (
|
||||
"crypto/internal/boring"
|
||||
"math/big"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Cached conversions from Go PublicKey/PrivateKey to BoringCrypto.
|
||||
//
|
||||
// A new 'boring atomic.Value' field in both PublicKey and PrivateKey
|
||||
// serves as a cache for the most recent conversion. The cache is an
|
||||
// atomic.Value because code might reasonably set up a key and then
|
||||
// (thinking it immutable) use it from multiple goroutines simultaneously.
|
||||
// The first operation initializes the cache; if there are multiple simultaneous
|
||||
// first operations, they will do redundant work but not step on each other.
|
||||
//
|
||||
// We could just assume that once used in a Sign or Verify operation,
|
||||
// a particular key is never again modified, but that has not been a
|
||||
// stated assumption before. Just in case there is any existing code that
|
||||
// does modify the key between operations, we save the original values
|
||||
// alongside the cached BoringCrypto key and check that the real key
|
||||
// still matches before using the cached key. The theory is that the real
|
||||
// operations are significantly more expensive than the comparison.
|
||||
|
||||
type boringPub struct {
|
||||
key *boring.PublicKeyECDSA
|
||||
orig PublicKey
|
||||
}
|
||||
|
||||
func boringPublicKey(pub *PublicKey) (*boring.PublicKeyECDSA, error) {
|
||||
b := (*boringPub)(atomic.LoadPointer(&pub.boring))
|
||||
if b != nil && publicKeyEqual(&b.orig, pub) {
|
||||
return b.key, nil
|
||||
}
|
||||
|
||||
b = new(boringPub)
|
||||
b.orig = copyPublicKey(pub)
|
||||
key, err := boring.NewPublicKeyECDSA(b.orig.Curve.Params().Name, b.orig.X, b.orig.Y)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b.key = key
|
||||
atomic.StorePointer(&pub.boring, unsafe.Pointer(b))
|
||||
return key, nil
|
||||
}
|
||||
|
||||
type boringPriv struct {
|
||||
key *boring.PrivateKeyECDSA
|
||||
orig PrivateKey
|
||||
}
|
||||
|
||||
func boringPrivateKey(priv *PrivateKey) (*boring.PrivateKeyECDSA, error) {
|
||||
b := (*boringPriv)(atomic.LoadPointer(&priv.boring))
|
||||
if b != nil && privateKeyEqual(&b.orig, priv) {
|
||||
return b.key, nil
|
||||
}
|
||||
|
||||
b = new(boringPriv)
|
||||
b.orig = copyPrivateKey(priv)
|
||||
key, err := boring.NewPrivateKeyECDSA(b.orig.Curve.Params().Name, b.orig.X, b.orig.Y, b.orig.D)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b.key = key
|
||||
atomic.StorePointer(&priv.boring, unsafe.Pointer(b))
|
||||
return key, nil
|
||||
}
|
||||
|
||||
func publicKeyEqual(k1, k2 *PublicKey) bool {
|
||||
return k1.X != nil &&
|
||||
k1.Curve.Params() == k2.Curve.Params() &&
|
||||
k1.X.Cmp(k2.X) == 0 &&
|
||||
k1.Y.Cmp(k2.Y) == 0
|
||||
}
|
||||
|
||||
func privateKeyEqual(k1, k2 *PrivateKey) bool {
|
||||
return publicKeyEqual(&k1.PublicKey, &k2.PublicKey) &&
|
||||
k1.D.Cmp(k2.D) == 0
|
||||
}
|
||||
|
||||
func copyPublicKey(k *PublicKey) PublicKey {
|
||||
return PublicKey{
|
||||
Curve: k.Curve,
|
||||
X: new(big.Int).Set(k.X),
|
||||
Y: new(big.Int).Set(k.Y),
|
||||
}
|
||||
}
|
||||
|
||||
func copyPrivateKey(k *PrivateKey) PrivateKey {
|
||||
return PrivateKey{
|
||||
PublicKey: copyPublicKey(&k.PublicKey),
|
||||
D: new(big.Int).Set(k.D),
|
||||
}
|
||||
}
|
||||
@@ -21,11 +21,13 @@ import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/elliptic"
|
||||
"crypto/internal/boring"
|
||||
"crypto/sha512"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
"io"
|
||||
"math/big"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// A invertible implements fast inverse mod Curve.Params().N
|
||||
@@ -47,12 +49,16 @@ const (
|
||||
type PublicKey struct {
|
||||
elliptic.Curve
|
||||
X, Y *big.Int
|
||||
|
||||
boring unsafe.Pointer
|
||||
}
|
||||
|
||||
// PrivateKey represents a ECDSA private key.
|
||||
type PrivateKey struct {
|
||||
PublicKey
|
||||
D *big.Int
|
||||
|
||||
boring unsafe.Pointer
|
||||
}
|
||||
|
||||
type ecdsaSignature struct {
|
||||
@@ -69,6 +75,15 @@ func (priv *PrivateKey) Public() crypto.PublicKey {
|
||||
// hardware module. Common uses should use the Sign function in this package
|
||||
// directly.
|
||||
func (priv *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) {
|
||||
if boring.Enabled && rand == boring.RandReader {
|
||||
b, err := boringPrivateKey(priv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return boring.SignMarshalECDSA(b, msg)
|
||||
}
|
||||
boring.UnreachableExceptTests()
|
||||
|
||||
r, s, err := Sign(rand, priv, msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -98,6 +113,15 @@ func randFieldElement(c elliptic.Curve, rand io.Reader) (k *big.Int, err error)
|
||||
|
||||
// GenerateKey generates a public and private key pair.
|
||||
func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) {
|
||||
if boring.Enabled && rand == boring.RandReader {
|
||||
x, y, d, err := boring.GenerateKeyECDSA(c.Params().Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &PrivateKey{PublicKey: PublicKey{Curve: c, X: x, Y: y}, D: d}, nil
|
||||
}
|
||||
boring.UnreachableExceptTests()
|
||||
|
||||
k, err := randFieldElement(c, rand)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -149,6 +173,15 @@ var errZeroParam = errors.New("zero parameter")
|
||||
// returns the signature as a pair of integers. The security of the private key
|
||||
// depends on the entropy of rand.
|
||||
func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
|
||||
if boring.Enabled && rand == boring.RandReader {
|
||||
b, err := boringPrivateKey(priv)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return boring.SignECDSA(b, hash)
|
||||
}
|
||||
boring.UnreachableExceptTests()
|
||||
|
||||
// Get min(log2(q) / 2, 256) bits of entropy from rand.
|
||||
entropylen := (priv.Curve.Params().BitSize + 7) / 16
|
||||
if entropylen > 32 {
|
||||
@@ -225,6 +258,15 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
|
||||
// Verify verifies the signature in r, s of hash using the public key, pub. Its
|
||||
// return value records whether the signature is valid.
|
||||
func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
|
||||
if boring.Enabled {
|
||||
b, err := boringPublicKey(pub)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return boring.VerifyECDSA(b, hash, r, s)
|
||||
}
|
||||
boring.UnreachableExceptTests()
|
||||
|
||||
// See [NSA] 3.4.2
|
||||
c := pub.Curve
|
||||
N := c.Params().N
|
||||
|
||||
@@ -300,6 +300,29 @@ var p224BaseMultTests = []baseMultTest{
|
||||
},
|
||||
}
|
||||
|
||||
type scalarMultTest struct {
|
||||
k string
|
||||
xIn, yIn string
|
||||
xOut, yOut string
|
||||
}
|
||||
|
||||
var p256MultTests = []scalarMultTest{
|
||||
{
|
||||
"2a265f8bcbdcaf94d58519141e578124cb40d64a501fba9c11847b28965bc737",
|
||||
"023819813ac969847059028ea88a1f30dfbcde03fc791d3a252c6b41211882ea",
|
||||
"f93e4ae433cc12cf2a43fc0ef26400c0e125508224cdb649380f25479148a4ad",
|
||||
"4d4de80f1534850d261075997e3049321a0864082d24a917863366c0724f5ae3",
|
||||
"a22d2b7f7818a3563e0f7a76c9bf0921ac55e06e2e4d11795b233824b1db8cc0",
|
||||
},
|
||||
{
|
||||
"313f72ff9fe811bf573176231b286a3bdb6f1b14e05c40146590727a71c3bccd",
|
||||
"cc11887b2d66cbae8f4d306627192522932146b42f01d3c6f92bd5c8ba739b06",
|
||||
"a2f08a029cd06b46183085bae9248b0ed15b70280c7ef13a457f5af382426031",
|
||||
"831c3f6b5f762d2f461901577af41354ac5f228c2591f84f8a6e51e2e3f17991",
|
||||
"93f90934cd0ef2c698cc471c60a93524e87ab31ca2412252337f364513e43684",
|
||||
},
|
||||
}
|
||||
|
||||
func TestBaseMult(t *testing.T) {
|
||||
p224 := P224()
|
||||
for i, e := range p224BaseMultTests {
|
||||
@@ -379,6 +402,19 @@ func TestP256Mult(t *testing.T) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for i, e := range p256MultTests {
|
||||
x, _ := new(big.Int).SetString(e.xIn, 16)
|
||||
y, _ := new(big.Int).SetString(e.yIn, 16)
|
||||
k, _ := new(big.Int).SetString(e.k, 16)
|
||||
expectedX, _ := new(big.Int).SetString(e.xOut, 16)
|
||||
expectedY, _ := new(big.Int).SetString(e.yOut, 16)
|
||||
|
||||
xx, yy := p256.ScalarMult(x, y, k.Bytes())
|
||||
if xx.Cmp(expectedX) != 0 || yy.Cmp(expectedY) != 0 {
|
||||
t.Errorf("#%d: got (%x, %x), want (%x, %x)", i, xx, yy, expectedX, expectedY)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInfinity(t *testing.T) {
|
||||
|
||||
@@ -1314,12 +1314,12 @@ TEXT p256SubInternal(SB),NOSPLIT,$0
|
||||
ADCQ p256const0<>(SB), acc5
|
||||
ADCQ $0, acc6
|
||||
ADCQ p256const1<>(SB), acc7
|
||||
ADCQ $0, mul0
|
||||
ANDQ $1, mul0
|
||||
|
||||
CMOVQNE acc0, acc4
|
||||
CMOVQNE acc1, acc5
|
||||
CMOVQNE acc2, acc6
|
||||
CMOVQNE acc3, acc7
|
||||
CMOVQEQ acc0, acc4
|
||||
CMOVQEQ acc1, acc5
|
||||
CMOVQEQ acc2, acc6
|
||||
CMOVQEQ acc3, acc7
|
||||
|
||||
RET
|
||||
/* ---------------------------------------*/
|
||||
|
||||
@@ -22,6 +22,7 @@ timing side-channels:
|
||||
package hmac
|
||||
|
||||
import (
|
||||
"crypto/internal/boring"
|
||||
"crypto/subtle"
|
||||
"hash"
|
||||
)
|
||||
@@ -65,6 +66,13 @@ func (h *hmac) Reset() {
|
||||
|
||||
// New returns a new HMAC hash using the given hash.Hash type and key.
|
||||
func New(h func() hash.Hash, key []byte) hash.Hash {
|
||||
if boring.Enabled {
|
||||
hm := boring.NewHMAC(h, key)
|
||||
if hm != nil {
|
||||
return hm
|
||||
}
|
||||
// BoringCrypto did not recognize h, so fall through to standard Go code.
|
||||
}
|
||||
hm := new(hmac)
|
||||
hm.outer = h()
|
||||
hm.inner = h()
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
package hmac
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
@@ -518,6 +519,31 @@ var hmacTests = []hmacTest{
|
||||
sha512.Size,
|
||||
sha512.BlockSize,
|
||||
},
|
||||
// HMAC without key is dumb but should probably not fail.
|
||||
{
|
||||
sha1.New,
|
||||
[]byte{},
|
||||
[]byte("message"),
|
||||
"d5d1ed05121417247616cfc8378f360a39da7cfa",
|
||||
sha1.Size,
|
||||
sha1.BlockSize,
|
||||
},
|
||||
{
|
||||
sha256.New,
|
||||
[]byte{},
|
||||
[]byte("message"),
|
||||
"eb08c1f56d5ddee07f7bdf80468083da06b64cf4fac64fe3a90883df5feacae4",
|
||||
sha256.Size,
|
||||
sha256.BlockSize,
|
||||
},
|
||||
{
|
||||
sha512.New,
|
||||
[]byte{},
|
||||
[]byte("message"),
|
||||
"08fce52f6395d59c2a3fb8abb281d74ad6f112b9a9c787bcea290d94dadbc82b2ca3e5e12bf2277c7fedbb0154d5493e41bb7459f63c8e39554ea3651b812492",
|
||||
sha512.Size,
|
||||
sha512.BlockSize,
|
||||
},
|
||||
}
|
||||
|
||||
func TestHMAC(t *testing.T) {
|
||||
@@ -569,6 +595,42 @@ func TestEqual(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteAfterSum(t *testing.T) {
|
||||
h := New(sha1.New, nil)
|
||||
h.Write([]byte("hello"))
|
||||
sumHello := h.Sum(nil)
|
||||
|
||||
h = New(sha1.New, nil)
|
||||
h.Write([]byte("hello world"))
|
||||
sumHelloWorld := h.Sum(nil)
|
||||
|
||||
// Test that Sum has no effect on future Sum or Write operations.
|
||||
// This is a bit unusual as far as usage, but it's allowed
|
||||
// by the definition of Go hash.Hash, and some clients expect it to work.
|
||||
h = New(sha1.New, nil)
|
||||
h.Write([]byte("hello"))
|
||||
if sum := h.Sum(nil); !bytes.Equal(sum, sumHello) {
|
||||
t.Fatalf("1st Sum after hello = %x, want %x", sum, sumHello)
|
||||
}
|
||||
if sum := h.Sum(nil); !bytes.Equal(sum, sumHello) {
|
||||
t.Fatalf("2nd Sum after hello = %x, want %x", sum, sumHello)
|
||||
}
|
||||
|
||||
h.Write([]byte(" world"))
|
||||
if sum := h.Sum(nil); !bytes.Equal(sum, sumHelloWorld) {
|
||||
t.Fatalf("1st Sum after hello world = %x, want %x", sum, sumHelloWorld)
|
||||
}
|
||||
if sum := h.Sum(nil); !bytes.Equal(sum, sumHelloWorld) {
|
||||
t.Fatalf("2nd Sum after hello world = %x, want %x", sum, sumHelloWorld)
|
||||
}
|
||||
|
||||
h.Reset()
|
||||
h.Write([]byte("hello"))
|
||||
if sum := h.Sum(nil); !bytes.Equal(sum, sumHello) {
|
||||
t.Fatalf("Sum after Reset + hello = %x, want %x", sum, sumHello)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkHMACSHA256_1K(b *testing.B) {
|
||||
key := make([]byte, 32)
|
||||
buf := make([]byte, 1024)
|
||||
|
||||
200
src/crypto/internal/boring/LICENSE
Normal file
200
src/crypto/internal/boring/LICENSE
Normal file
@@ -0,0 +1,200 @@
|
||||
The Go source code and supporting files in this directory
|
||||
are covered by the usual Go license (see ../../../../LICENSE).
|
||||
|
||||
The goboringcrypto_linux_amd64.syso object file is built
|
||||
from BoringSSL source code by build/build.sh and is covered
|
||||
by the BoringSSL license reproduced below and also at
|
||||
https://boringssl.googlesource.com/boringssl/+/fips-20170615/LICENSE.
|
||||
|
||||
BoringSSL is a fork of OpenSSL. As such, large parts of it fall under OpenSSL
|
||||
licensing. Files that are completely new have a Google copyright and an ISC
|
||||
license. This license is reproduced at the bottom of this file.
|
||||
|
||||
Contributors to BoringSSL are required to follow the CLA rules for Chromium:
|
||||
https://cla.developers.google.com/clas
|
||||
|
||||
Some files from Intel are under yet another license, which is also included
|
||||
underneath.
|
||||
|
||||
The OpenSSL toolkit stays under a dual license, i.e. both the conditions of the
|
||||
OpenSSL License and the original SSLeay license apply to the toolkit. See below
|
||||
for the actual license texts. Actually both licenses are BSD-style Open Source
|
||||
licenses. In case of any license issues related to OpenSSL please contact
|
||||
openssl-core@openssl.org.
|
||||
|
||||
The following are Google-internal bug numbers where explicit permission from
|
||||
some authors is recorded for use of their work. (This is purely for our own
|
||||
record keeping.)
|
||||
27287199
|
||||
27287880
|
||||
27287883
|
||||
|
||||
OpenSSL License
|
||||
---------------
|
||||
|
||||
/* ====================================================================
|
||||
* Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this
|
||||
* software must display the following acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
|
||||
*
|
||||
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* prior written permission. For written permission, please contact
|
||||
* openssl-core@openssl.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "OpenSSL"
|
||||
* nor may "OpenSSL" appear in their names without prior written
|
||||
* permission of the OpenSSL Project.
|
||||
*
|
||||
* 6. Redistributions of any form whatsoever must retain the following
|
||||
* acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
|
||||
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*
|
||||
* This product includes cryptographic software written by Eric Young
|
||||
* (eay@cryptsoft.com). This product includes software written by Tim
|
||||
* Hudson (tjh@cryptsoft.com).
|
||||
*
|
||||
*/
|
||||
|
||||
Original SSLeay License
|
||||
-----------------------
|
||||
|
||||
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* This package is an SSL implementation written
|
||||
* by Eric Young (eay@cryptsoft.com).
|
||||
* The implementation was written so as to conform with Netscapes SSL.
|
||||
*
|
||||
* This library is free for commercial and non-commercial use as long as
|
||||
* the following conditions are aheared to. The following conditions
|
||||
* apply to all code found in this distribution, be it the RC4, RSA,
|
||||
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
|
||||
* included with this distribution is covered by the same copyright terms
|
||||
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
|
||||
*
|
||||
* Copyright remains Eric Young's, and as such any Copyright notices in
|
||||
* the code are not to be removed.
|
||||
* If this package is used in a product, Eric Young should be given attribution
|
||||
* as the author of the parts of the library used.
|
||||
* This can be in the form of a textual message at program startup or
|
||||
* in documentation (online or textual) provided with the package.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* "This product includes cryptographic software written by
|
||||
* Eric Young (eay@cryptsoft.com)"
|
||||
* The word 'cryptographic' can be left out if the rouines from the library
|
||||
* being used are not cryptographic related :-).
|
||||
* 4. If you include any Windows specific code (or a derivative thereof) from
|
||||
* the apps directory (application code) you must include an acknowledgement:
|
||||
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* The licence and distribution terms for any publically available version or
|
||||
* derivative of this code cannot be changed. i.e. this code cannot simply be
|
||||
* copied and put under another distribution licence
|
||||
* [including the GNU Public Licence.]
|
||||
*/
|
||||
|
||||
|
||||
ISC license used for completely new code in BoringSSL:
|
||||
|
||||
/* Copyright (c) 2015, Google Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
|
||||
Some files from Intel carry the following license:
|
||||
|
||||
# Copyright (c) 2012, Intel Corporation
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# * Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
#
|
||||
# * Neither the name of the Intel Corporation nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY
|
||||
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
357
src/crypto/internal/boring/aes.go
Normal file
357
src/crypto/internal/boring/aes.go
Normal file
@@ -0,0 +1,357 @@
|
||||
// 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.
|
||||
|
||||
// +build linux,amd64
|
||||
// +build !android
|
||||
// +build !cmd_go_bootstrap
|
||||
// +build !msan
|
||||
|
||||
package boring
|
||||
|
||||
// #include "goboringcrypto.h"
|
||||
import "C"
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"errors"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type aesKeySizeError int
|
||||
|
||||
func (k aesKeySizeError) Error() string {
|
||||
return "crypto/aes: invalid key size " + strconv.Itoa(int(k))
|
||||
}
|
||||
|
||||
const aesBlockSize = 16
|
||||
|
||||
type aesCipher struct {
|
||||
key []byte
|
||||
enc C.GO_AES_KEY
|
||||
dec C.GO_AES_KEY
|
||||
}
|
||||
|
||||
type extraModes interface {
|
||||
// Copied out of crypto/aes/modes.go.
|
||||
NewCBCEncrypter(iv []byte) cipher.BlockMode
|
||||
NewCBCDecrypter(iv []byte) cipher.BlockMode
|
||||
NewCTR(iv []byte) cipher.Stream
|
||||
NewGCM(nonceSize int) (cipher.AEAD, error)
|
||||
|
||||
// Invented for BoringCrypto.
|
||||
NewGCMTLS() (cipher.AEAD, error)
|
||||
}
|
||||
|
||||
var _ extraModes = (*aesCipher)(nil)
|
||||
|
||||
func NewAESCipher(key []byte) (cipher.Block, error) {
|
||||
c := &aesCipher{key: make([]byte, len(key))}
|
||||
copy(c.key, key)
|
||||
// Note: 0 is success, contradicting the usual BoringCrypto convention.
|
||||
if C._goboringcrypto_AES_set_decrypt_key((*C.uint8_t)(unsafe.Pointer(&c.key[0])), C.uint(8*len(c.key)), &c.dec) != 0 ||
|
||||
C._goboringcrypto_AES_set_encrypt_key((*C.uint8_t)(unsafe.Pointer(&c.key[0])), C.uint(8*len(c.key)), &c.enc) != 0 {
|
||||
return nil, aesKeySizeError(len(key))
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c *aesCipher) BlockSize() int { return aesBlockSize }
|
||||
|
||||
func (c *aesCipher) Encrypt(dst, src []byte) {
|
||||
if inexactOverlap(dst, src) {
|
||||
panic("crypto/cipher: invalid buffer overlap")
|
||||
}
|
||||
if len(src) < aesBlockSize {
|
||||
panic("crypto/aes: input not full block")
|
||||
}
|
||||
if len(dst) < aesBlockSize {
|
||||
panic("crypto/aes: output not full block")
|
||||
}
|
||||
C._goboringcrypto_AES_encrypt(
|
||||
(*C.uint8_t)(unsafe.Pointer(&src[0])),
|
||||
(*C.uint8_t)(unsafe.Pointer(&dst[0])),
|
||||
&c.enc)
|
||||
}
|
||||
|
||||
func (c *aesCipher) Decrypt(dst, src []byte) {
|
||||
if inexactOverlap(dst, src) {
|
||||
panic("crypto/cipher: invalid buffer overlap")
|
||||
}
|
||||
if len(src) < aesBlockSize {
|
||||
panic("crypto/aes: input not full block")
|
||||
}
|
||||
if len(dst) < aesBlockSize {
|
||||
panic("crypto/aes: output not full block")
|
||||
}
|
||||
C._goboringcrypto_AES_decrypt(
|
||||
(*C.uint8_t)(unsafe.Pointer(&src[0])),
|
||||
(*C.uint8_t)(unsafe.Pointer(&dst[0])),
|
||||
&c.dec)
|
||||
}
|
||||
|
||||
type aesCBC struct {
|
||||
key *C.GO_AES_KEY
|
||||
mode C.int
|
||||
iv [aesBlockSize]byte
|
||||
}
|
||||
|
||||
func (x *aesCBC) BlockSize() int { return aesBlockSize }
|
||||
|
||||
func (x *aesCBC) CryptBlocks(dst, src []byte) {
|
||||
if inexactOverlap(dst, src) {
|
||||
panic("crypto/cipher: invalid buffer overlap")
|
||||
}
|
||||
if len(src)%aesBlockSize != 0 {
|
||||
panic("crypto/cipher: input not full blocks")
|
||||
}
|
||||
if len(dst) < len(src) {
|
||||
panic("crypto/cipher: output smaller than input")
|
||||
}
|
||||
if len(src) > 0 {
|
||||
C._goboringcrypto_AES_cbc_encrypt(
|
||||
(*C.uint8_t)(unsafe.Pointer(&src[0])),
|
||||
(*C.uint8_t)(unsafe.Pointer(&dst[0])),
|
||||
C.size_t(len(src)), x.key,
|
||||
(*C.uint8_t)(unsafe.Pointer(&x.iv[0])), x.mode)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *aesCBC) SetIV(iv []byte) {
|
||||
if len(iv) != aesBlockSize {
|
||||
panic("cipher: incorrect length IV")
|
||||
}
|
||||
copy(x.iv[:], iv)
|
||||
}
|
||||
|
||||
func (c *aesCipher) NewCBCEncrypter(iv []byte) cipher.BlockMode {
|
||||
x := &aesCBC{key: &c.enc, mode: C.GO_AES_ENCRYPT}
|
||||
copy(x.iv[:], iv)
|
||||
return x
|
||||
}
|
||||
|
||||
func (c *aesCipher) NewCBCDecrypter(iv []byte) cipher.BlockMode {
|
||||
x := &aesCBC{key: &c.dec, mode: C.GO_AES_DECRYPT}
|
||||
copy(x.iv[:], iv)
|
||||
return x
|
||||
}
|
||||
|
||||
type aesCTR struct {
|
||||
key *C.GO_AES_KEY
|
||||
iv [aesBlockSize]byte
|
||||
num C.uint
|
||||
ecount_buf [16]C.uint8_t
|
||||
}
|
||||
|
||||
func (x *aesCTR) XORKeyStream(dst, src []byte) {
|
||||
if inexactOverlap(dst, src) {
|
||||
panic("crypto/cipher: invalid buffer overlap")
|
||||
}
|
||||
if len(dst) < len(src) {
|
||||
panic("crypto/cipher: output smaller than input")
|
||||
}
|
||||
if len(src) == 0 {
|
||||
return
|
||||
}
|
||||
C._goboringcrypto_AES_ctr128_encrypt(
|
||||
(*C.uint8_t)(unsafe.Pointer(&src[0])),
|
||||
(*C.uint8_t)(unsafe.Pointer(&dst[0])),
|
||||
C.size_t(len(src)), x.key, (*C.uint8_t)(unsafe.Pointer(&x.iv[0])),
|
||||
&x.ecount_buf[0], &x.num)
|
||||
}
|
||||
|
||||
func (c *aesCipher) NewCTR(iv []byte) cipher.Stream {
|
||||
x := &aesCTR{key: &c.enc}
|
||||
copy(x.iv[:], iv)
|
||||
return x
|
||||
}
|
||||
|
||||
type aesGCM struct {
|
||||
ctx C.GO_EVP_AEAD_CTX
|
||||
aead *C.GO_EVP_AEAD
|
||||
}
|
||||
|
||||
const (
|
||||
gcmBlockSize = 16
|
||||
gcmTagSize = 16
|
||||
gcmStandardNonceSize = 12
|
||||
)
|
||||
|
||||
type aesNonceSizeError int
|
||||
|
||||
func (n aesNonceSizeError) Error() string {
|
||||
return "crypto/aes: invalid GCM nonce size " + strconv.Itoa(int(n))
|
||||
}
|
||||
|
||||
type noGCM struct {
|
||||
cipher.Block
|
||||
}
|
||||
|
||||
func (c *aesCipher) NewGCM(nonceSize int) (cipher.AEAD, error) {
|
||||
return c.newGCM(nonceSize, false)
|
||||
}
|
||||
|
||||
func (c *aesCipher) NewGCMTLS() (cipher.AEAD, error) {
|
||||
return c.newGCM(gcmStandardNonceSize, true)
|
||||
}
|
||||
|
||||
func (c *aesCipher) newGCM(nonceSize int, tls bool) (cipher.AEAD, error) {
|
||||
if nonceSize != gcmStandardNonceSize {
|
||||
// Fall back to standard library for GCM with non-standard nonce size.
|
||||
return cipher.NewGCMWithNonceSize(&noGCM{c}, nonceSize)
|
||||
}
|
||||
|
||||
var aead *C.GO_EVP_AEAD
|
||||
switch len(c.key) * 8 {
|
||||
case 128:
|
||||
if tls {
|
||||
aead = C._goboringcrypto_EVP_aead_aes_128_gcm_tls12()
|
||||
} else {
|
||||
aead = C._goboringcrypto_EVP_aead_aes_128_gcm()
|
||||
}
|
||||
case 256:
|
||||
if tls {
|
||||
aead = C._goboringcrypto_EVP_aead_aes_256_gcm_tls12()
|
||||
} else {
|
||||
aead = C._goboringcrypto_EVP_aead_aes_256_gcm()
|
||||
}
|
||||
default:
|
||||
// Fall back to standard library for GCM with non-standard key size.
|
||||
return cipher.NewGCMWithNonceSize(&noGCM{c}, nonceSize)
|
||||
}
|
||||
|
||||
g := &aesGCM{aead: aead}
|
||||
if C._goboringcrypto_EVP_AEAD_CTX_init(&g.ctx, aead, (*C.uint8_t)(unsafe.Pointer(&c.key[0])), C.size_t(len(c.key)), C.GO_EVP_AEAD_DEFAULT_TAG_LENGTH, nil) == 0 {
|
||||
return nil, fail("EVP_AEAD_CTX_init")
|
||||
}
|
||||
// Note: Because of the finalizer, any time g.ctx is passed to cgo,
|
||||
// that call must be followed by a call to runtime.KeepAlive(g),
|
||||
// to make sure g is not collected (and finalized) before the cgo
|
||||
// call returns.
|
||||
runtime.SetFinalizer(g, (*aesGCM).finalize)
|
||||
if g.NonceSize() != nonceSize {
|
||||
panic("boringcrypto: internal confusion about nonce size")
|
||||
}
|
||||
if g.Overhead() != gcmTagSize {
|
||||
panic("boringcrypto: internal confusion about tag size")
|
||||
}
|
||||
|
||||
return g, nil
|
||||
}
|
||||
|
||||
func (g *aesGCM) finalize() {
|
||||
C._goboringcrypto_EVP_AEAD_CTX_cleanup(&g.ctx)
|
||||
}
|
||||
|
||||
func (g *aesGCM) NonceSize() int {
|
||||
return int(C._goboringcrypto_EVP_AEAD_nonce_length(g.aead))
|
||||
}
|
||||
|
||||
func (g *aesGCM) Overhead() int {
|
||||
return int(C._goboringcrypto_EVP_AEAD_max_overhead(g.aead))
|
||||
}
|
||||
|
||||
// base returns the address of the underlying array in b,
|
||||
// being careful not to panic when b has zero length.
|
||||
func base(b []byte) *C.uint8_t {
|
||||
if len(b) == 0 {
|
||||
return nil
|
||||
}
|
||||
return (*C.uint8_t)(unsafe.Pointer(&b[0]))
|
||||
}
|
||||
|
||||
func (g *aesGCM) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
|
||||
if len(nonce) != gcmStandardNonceSize {
|
||||
panic("cipher: incorrect nonce length given to GCM")
|
||||
}
|
||||
if uint64(len(plaintext)) > ((1<<32)-2)*aesBlockSize || len(plaintext)+gcmTagSize < len(plaintext) {
|
||||
panic("cipher: message too large for GCM")
|
||||
}
|
||||
if len(dst)+len(plaintext)+gcmTagSize < len(dst) {
|
||||
panic("cipher: message too large for buffer")
|
||||
}
|
||||
|
||||
// Make room in dst to append plaintext+overhead.
|
||||
n := len(dst)
|
||||
for cap(dst) < n+len(plaintext)+gcmTagSize {
|
||||
dst = append(dst[:cap(dst)], 0)
|
||||
}
|
||||
dst = dst[:n+len(plaintext)+gcmTagSize]
|
||||
|
||||
// Check delayed until now to make sure len(dst) is accurate.
|
||||
if inexactOverlap(dst[n:], plaintext) {
|
||||
panic("cipher: invalid buffer overlap")
|
||||
}
|
||||
|
||||
var outLen C.size_t
|
||||
ok := C._goboringcrypto_EVP_AEAD_CTX_seal(
|
||||
&g.ctx,
|
||||
(*C.uint8_t)(unsafe.Pointer(&dst[n])), &outLen, C.size_t(len(plaintext)+gcmTagSize),
|
||||
base(nonce), C.size_t(len(nonce)),
|
||||
base(plaintext), C.size_t(len(plaintext)),
|
||||
base(additionalData), C.size_t(len(additionalData)))
|
||||
runtime.KeepAlive(g)
|
||||
if ok == 0 {
|
||||
panic(fail("EVP_AEAD_CTX_seal"))
|
||||
}
|
||||
if outLen != C.size_t(len(plaintext)+gcmTagSize) {
|
||||
panic("boringcrypto: internal confusion about GCM tag size")
|
||||
}
|
||||
return dst[:n+int(outLen)]
|
||||
}
|
||||
|
||||
var errOpen = errors.New("cipher: message authentication failed")
|
||||
|
||||
func (g *aesGCM) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
||||
if len(nonce) != gcmStandardNonceSize {
|
||||
panic("cipher: incorrect nonce length given to GCM")
|
||||
}
|
||||
if len(ciphertext) < gcmTagSize {
|
||||
return nil, errOpen
|
||||
}
|
||||
if uint64(len(ciphertext)) > ((1<<32)-2)*aesBlockSize+gcmTagSize {
|
||||
return nil, errOpen
|
||||
}
|
||||
|
||||
// Make room in dst to append ciphertext without tag.
|
||||
n := len(dst)
|
||||
for cap(dst) < n+len(ciphertext)-gcmTagSize {
|
||||
dst = append(dst[:cap(dst)], 0)
|
||||
}
|
||||
dst = dst[:n+len(ciphertext)-gcmTagSize]
|
||||
|
||||
// Check delayed until now to make sure len(dst) is accurate.
|
||||
if inexactOverlap(dst[n:], ciphertext) {
|
||||
panic("cipher: invalid buffer overlap")
|
||||
}
|
||||
|
||||
var outLen C.size_t
|
||||
ok := C._goboringcrypto_EVP_AEAD_CTX_open(
|
||||
&g.ctx,
|
||||
base(dst[n:]), &outLen, C.size_t(len(ciphertext)-gcmTagSize),
|
||||
base(nonce), C.size_t(len(nonce)),
|
||||
base(ciphertext), C.size_t(len(ciphertext)),
|
||||
base(additionalData), C.size_t(len(additionalData)))
|
||||
runtime.KeepAlive(g)
|
||||
if ok == 0 {
|
||||
return nil, errOpen
|
||||
}
|
||||
if outLen != C.size_t(len(ciphertext)-gcmTagSize) {
|
||||
panic("boringcrypto: internal confusion about GCM tag size")
|
||||
}
|
||||
return dst[:n+int(outLen)], nil
|
||||
}
|
||||
|
||||
func anyOverlap(x, y []byte) bool {
|
||||
return len(x) > 0 && len(y) > 0 &&
|
||||
uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) &&
|
||||
uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1]))
|
||||
}
|
||||
|
||||
func inexactOverlap(x, y []byte) bool {
|
||||
if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
|
||||
return false
|
||||
}
|
||||
return anyOverlap(x, y)
|
||||
}
|
||||
83
src/crypto/internal/boring/boring.go
Normal file
83
src/crypto/internal/boring/boring.go
Normal file
@@ -0,0 +1,83 @@
|
||||
// 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.
|
||||
|
||||
// +build linux,amd64
|
||||
// +build !android
|
||||
// +build !cmd_go_bootstrap
|
||||
// +build !msan
|
||||
|
||||
package boring
|
||||
|
||||
// #include "goboringcrypto.h"
|
||||
import "C"
|
||||
import (
|
||||
"crypto/internal/boring/sig"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
const available = true
|
||||
|
||||
func init() {
|
||||
C._goboringcrypto_BORINGSSL_bcm_power_on_self_test()
|
||||
if C._goboringcrypto_FIPS_mode() != 1 {
|
||||
panic("boringcrypto: not in FIPS mode")
|
||||
}
|
||||
sig.BoringCrypto()
|
||||
}
|
||||
|
||||
// Unreachable marks code that should be unreachable
|
||||
// when BoringCrypto is in use. It panics.
|
||||
func Unreachable() {
|
||||
panic("boringcrypto: invalid code execution")
|
||||
}
|
||||
|
||||
// provided by runtime to avoid os import
|
||||
func runtime_arg0() string
|
||||
|
||||
func hasSuffix(s, t string) bool {
|
||||
return len(s) > len(t) && s[len(s)-len(t):] == t
|
||||
}
|
||||
|
||||
// UnreachableExceptTests marks code that should be unreachable
|
||||
// when BoringCrypto is in use. It panics.
|
||||
func UnreachableExceptTests() {
|
||||
name := runtime_arg0()
|
||||
// If BoringCrypto ran on Windows we'd need to allow _test.exe and .test.exe as well.
|
||||
if !hasSuffix(name, "_test") && !hasSuffix(name, ".test") {
|
||||
println("boringcrypto: unexpected code execution in", name)
|
||||
panic("boringcrypto: invalid code execution")
|
||||
}
|
||||
}
|
||||
|
||||
type fail string
|
||||
|
||||
func (e fail) Error() string { return "boringcrypto: " + string(e) + " failed" }
|
||||
|
||||
func bigToBN(x *big.Int) *C.GO_BIGNUM {
|
||||
raw := x.Bytes()
|
||||
return C._goboringcrypto_BN_bin2bn(base(raw), C.size_t(len(raw)), nil)
|
||||
}
|
||||
|
||||
func bnToBig(bn *C.GO_BIGNUM) *big.Int {
|
||||
raw := make([]byte, C._goboringcrypto_BN_num_bytes(bn))
|
||||
n := C._goboringcrypto_BN_bn2bin(bn, base(raw))
|
||||
return new(big.Int).SetBytes(raw[:n])
|
||||
}
|
||||
|
||||
func bigToBn(bnp **C.GO_BIGNUM, b *big.Int) bool {
|
||||
if *bnp != nil {
|
||||
C._goboringcrypto_BN_free(*bnp)
|
||||
*bnp = nil
|
||||
}
|
||||
if b == nil {
|
||||
return true
|
||||
}
|
||||
raw := b.Bytes()
|
||||
bn := C._goboringcrypto_BN_bin2bn(base(raw), C.size_t(len(raw)), nil)
|
||||
if bn == nil {
|
||||
return false
|
||||
}
|
||||
*bnp = bn
|
||||
return true
|
||||
}
|
||||
34
src/crypto/internal/boring/boring_test.go
Normal file
34
src/crypto/internal/boring/boring_test.go
Normal file
@@ -0,0 +1,34 @@
|
||||
// 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.
|
||||
|
||||
// Most functionality in this package is tested by replacing existing code
|
||||
// and inheriting that code's tests.
|
||||
|
||||
package boring
|
||||
|
||||
import "testing"
|
||||
|
||||
// Test that func init does not panic.
|
||||
func TestInit(t *testing.T) {}
|
||||
|
||||
// Test that Unreachable panics.
|
||||
func TestUnreachable(t *testing.T) {
|
||||
defer func() {
|
||||
if Enabled {
|
||||
if err := recover(); err == nil {
|
||||
t.Fatal("expected Unreachable to panic")
|
||||
}
|
||||
} else {
|
||||
if err := recover(); err != nil {
|
||||
t.Fatalf("expected Unreachable to be a no-op")
|
||||
}
|
||||
}
|
||||
}()
|
||||
Unreachable()
|
||||
}
|
||||
|
||||
// Test that UnreachableExceptTests does not panic (this is a test).
|
||||
func TestUnreachableExceptTests(t *testing.T) {
|
||||
UnreachableExceptTests()
|
||||
}
|
||||
1
src/crypto/internal/boring/build/.gitignore
vendored
Normal file
1
src/crypto/internal/boring/build/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
boringssl-24e5886c0edfc409c8083d10f9f1120111efd6f5.tar.xz
|
||||
6
src/crypto/internal/boring/build/README
Normal file
6
src/crypto/internal/boring/build/README
Normal file
@@ -0,0 +1,6 @@
|
||||
This is not a Go package. The directory must not contain Go sources,
|
||||
to prevent it from being considered a Go package.
|
||||
|
||||
This directory holds the script for building ../goboringcrypto_*.syso.
|
||||
Run build.sh on an Ubuntu system.
|
||||
See the comment at the top of build.sh for details.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user