mirror of
https://github.com/golang/go.git
synced 2026-02-03 09:25:06 +03:00
Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f40c1214d | ||
|
|
598433b17a | ||
|
|
815cad3ed0 | ||
|
|
1900d34a10 | ||
|
|
a39bcecea6 | ||
|
|
d9e64910af | ||
|
|
c8aec4095e | ||
|
|
b8c9ef9f09 | ||
|
|
136f4a6b2a | ||
|
|
867be4c60c | ||
|
|
9a4e7942ea | ||
|
|
ff38035a62 | ||
|
|
42046e8989 | ||
|
|
fbf7e1f295 | ||
|
|
21312a4b5e | ||
|
|
5927854f7d | ||
|
|
65717b2dca | ||
|
|
048c9cfaac | ||
|
|
cff0de3da3 | ||
|
|
579120323f | ||
|
|
380525598c | ||
|
|
f096b5b340 | ||
|
|
3e3da54633 | ||
|
|
9b1e7cf2ac | ||
|
|
b01db023b1 | ||
|
|
a279b53a18 | ||
|
|
909f409a8d | ||
|
|
58ad0176ca | ||
|
|
92dac21d29 | ||
|
|
9bb98e02de | ||
|
|
78d74fc2cd | ||
|
|
5495047223 | ||
|
|
890e0e862f | ||
|
|
be596f049a | ||
|
|
0173631d53 | ||
|
|
ac0ccf3cd2 | ||
|
|
cc402c2c4d | ||
|
|
f396fa4285 | ||
|
|
664cd26c89 | ||
|
|
a8730cd93a | ||
|
|
b63db76c4a | ||
|
|
193eda7291 | ||
|
|
6f08c935a9 | ||
|
|
f20944de78 | ||
|
|
196492a299 | ||
|
|
1a6d87d4bf | ||
|
|
623e2c4603 | ||
|
|
780249eed4 | ||
|
|
31b2c4cc25 | ||
|
|
ac29f30dbb | ||
|
|
7320506bc5 | ||
|
|
45a4609c0a | ||
|
|
e157fac02d | ||
|
|
835dfef939 | ||
|
|
df91b8044d | ||
|
|
3d9475c04b | ||
|
|
b9661a14ea | ||
|
|
65c6c88a94 | ||
|
|
fbc9b49790 |
0
.github/SUPPORT → .github/SUPPORT.md
vendored
0
.github/SUPPORT → .github/SUPPORT.md
vendored
@@ -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.9">Go 1.9</a> <small>(August 2017)</small></li>
|
||||
<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>
|
||||
|
||||
@@ -20,7 +20,20 @@ For example, Go 1.8 is supported until Go 1.10 is released,
|
||||
and Go 1.9 is supported until Go 1.11 is released.
|
||||
We fix critical problems, including <a href="/security">critical security problems</a>,
|
||||
in supported releases as needed by issuing minor revisions
|
||||
(for example, Go 1.8.1, Go 1.8.2, and so on).
|
||||
(for example, Go 1.9.1, Go 1.9.2, and so on).
|
||||
</p>
|
||||
|
||||
<h2 id="go1.9">go1.9 (released 2017/08/24)</h2>
|
||||
|
||||
<p>
|
||||
Go 1.9 is a major release of Go.
|
||||
Read the <a href="/doc/go1.9">Go 1.9 Release Notes</a> for more information.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.9.1 (released 2017/10/04) includes two security fixes.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.9.1">Go
|
||||
1.9.1 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<h2 id="go1.8">go1.8 (released 2017/02/16)</h2>
|
||||
@@ -56,6 +69,13 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.8.3">Go
|
||||
1.8.3 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.8.4 (released 2017/10/04) includes two security fixes.
|
||||
It contains the same fixes as Go 1.9.1 and was released at the same time.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.8.4">Go
|
||||
1.8.4 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<h2 id="go1.7">go1.7 (released 2016/08/15)</h2>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -19,11 +19,12 @@ editing, navigation, testing, and debugging experience.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://github.com/fatih/vim-go">Vim Go</a>: a plugin for Vim to provide Go programming language support</li>
|
||||
<li><a href="https://marketplace.visualstudio.com/items?itemName=lukehoban.Go">Visual Studio Code Go</a>:
|
||||
an extension for Visual Studio Code to provide support for the Go programming language</li>
|
||||
<li><a href="https://github.com/fatih/vim-go">vim</a>: vim-go plugin provides Go programming language support</li>
|
||||
<li><a href="https://marketplace.visualstudio.com/items?itemName=lukehoban.Go">Visual Studio Code</a>:
|
||||
Go extension provides support for the Go programming language</li>
|
||||
<li><a href="https://www.jetbrains.com/go">Gogland</a>: Gogland is distributed either as a standalone IDE
|
||||
or as a plugin for the IntelliJ Platform IDEs</li>
|
||||
or as a plugin for the commercial IntelliJ Platform IDEs</li>
|
||||
<li><a href="https://atom.io/packages/go-plus">Atom</a>: Go-Plus is an Atom package that provides enhanced Go support</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
@@ -41,133 +42,155 @@ The following feature matrix lists and compares the most significant features.
|
||||
<table class="features-matrix">
|
||||
<tr>
|
||||
<th></th>
|
||||
<th><img title="Vim Go" src="/doc/editors/vimgo.png"><br>Vim Go</th>
|
||||
<th><img title="Visual Studio Code" src="/doc/editors/vscodego.png"><br>Visual Studio Code Go</th>
|
||||
<th><img title="Vim Go" src="/doc/editors/vimgo.png"><br>vim</th>
|
||||
<th><img title="Visual Studio Code" src="/doc/editors/vscodego.png"><br>Visual Studio Code</th>
|
||||
<th><img title="Gogland" src="/doc/editors/gogland.png"><br>Gogland</th>
|
||||
<th><img title="Go-Plus" src="/doc/editors/go-plus.png"><br>Atom</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="feature-row" colspan="4">Editing features</td>
|
||||
<td class="feature-row" colspan="5">Editing features</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Build and run from the editor/IDE</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Autocompletion of identifers (variable, method, and function names)</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Autocompletion based on type</td>
|
||||
<td class="no">No</td>
|
||||
<td class="no">No</td>
|
||||
<td class="yes">Yes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Type-aware autocompletion</td>
|
||||
<td class="no">No</td>
|
||||
<td class="no">No</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="no">No</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Rename identifiers</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Auto format, build, vet, and lint on save</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes<sup>1</sup></td>
|
||||
<td class="yes">Yes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Auto insert import paths and remove unused on save</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes<sup>2</sup></td>
|
||||
<td class="yes">Yes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Auto generate JSON, XML tags for struct fields</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="feature-row" colspan="4">Navigation features</td>
|
||||
<td class="feature-row" colspan="5">Navigation features</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Display documentation inline, or open godoc in browser</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Switch between <code>*.go</code> and <code>*_test.go</code> file</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">No</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Jump to definition and referees</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Look up for interface implementations</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Search for callers and callees</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="feature-row" colspan="4">Testing and debugging features</td>
|
||||
<td class="feature-row" colspan="5">Testing and debugging features</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Debugger support</td>
|
||||
<td class="no">No</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes<sup>3</sup></td>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Run a single test case, all tests from file, or all tests from a package</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="no">No</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Auto generate tests for packages, files and identifiers</td>
|
||||
<td class="no">No</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="no">No</td>
|
||||
<td class="no">No</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Debug tests</td>
|
||||
<td class="no">No</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes<sup>3</sup></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Display test coverage</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
<td class="yes">Yes</td>
|
||||
</tr>
|
||||
<tr class="download">
|
||||
<td></td>
|
||||
<td><a href="https://github.com/fatih/vim-go">Install<a/></td>
|
||||
<td><a href="https://marketplace.visualstudio.com/items?itemName=lukehoban.Go">Install<a/></td>
|
||||
<td><a href="https://www.jetbrains.com/go">Install<a/></td>
|
||||
<td><a href="https://atom.io/packages/go-plus">Install</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
<sup>1</sup>: Possible when enabled via Settings > Go > On Save, <code>go</code> <code>vet</code> and <code>golint</code> are available via plugins. Also runs tests on save if configured.
|
||||
<sup>1</sup>Possible when enabled via Settings > Go > On Save, <code>go</code> <code>vet</code> and <code>golint</code> are available via plugins. Also runs tests on save if configured.
|
||||
<br>
|
||||
<sup>2</sup>: Additionally, user input can disambiguate when two or more options are available.
|
||||
<sup>2</sup>Additionally, user input can disambiguate when two or more options are available.
|
||||
<br>
|
||||
<sup>3</sup>Available if the <a href="https://atom.io/packages/go-debug">go-debug</a> package is installed.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
@@ -206,5 +229,3 @@ The following feature matrix lists and compares the most significant features.
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--TODO(jbd): Add the Atom comparison-->
|
||||
BIN
doc/editors/go-plus.png
Normal file
BIN
doc/editors/go-plus.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@@ -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.9</h2>
|
||||
|
||||
<p><strong>
|
||||
Go 1.9 is not yet released. These are work-in-progress
|
||||
release notes. Go 1.9 is expected to be released in August 2017.
|
||||
</strong></p>
|
||||
<h2 id="introduction">Introduction to Go 1.9</h2>
|
||||
|
||||
<p>
|
||||
The latest Go release, version 1.9, arrives six months
|
||||
@@ -156,6 +151,21 @@ type T1 = T2
|
||||
directories, write <code>./vendor/...</code>.
|
||||
</p>
|
||||
|
||||
<h3 id="goroot">Moved GOROOT</h3>
|
||||
|
||||
<p><!-- CL 42533 -->
|
||||
The <a href="/cmd/go/">go tool</a> will now use the path from which it
|
||||
was invoked to attempt to locate the root of the Go install tree.
|
||||
This means that if the entire Go installation is moved to a new
|
||||
location, the go tool should continue to work as usual.
|
||||
This may be overridden by setting <code>GOROOT</code> in the environment,
|
||||
which should only be done in unusual circumstances.
|
||||
Note that this does not affect the result of
|
||||
the <a href="/pkg/runtime/#GOROOT">runtime.GOROOT</a> function, which
|
||||
will continue to report the original installation location;
|
||||
this may be fixed in later releases.
|
||||
</p>
|
||||
|
||||
<h3 id="compiler">Compiler Toolchain</h3>
|
||||
|
||||
<p><!-- CL 37441 -->
|
||||
@@ -473,6 +483,15 @@ version of gccgo.
|
||||
populated.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 36696 -->
|
||||
|
||||
If any SAN extension, including with no DNS names, is present
|
||||
in the certificate, then the Common Name from
|
||||
<a href="/pkg/crypto/x509/#Certificate.Subject"><code>Subject</code></a> is ignored.
|
||||
In previous releases, the code tested only whether DNS-name SANs were
|
||||
present in a certificate.
|
||||
</p>
|
||||
|
||||
</dl><!-- crypto/x509 -->
|
||||
|
||||
<dl id="database/sql"><dt><a href="/pkg/database/sql/">database/sql</a></dt>
|
||||
@@ -721,6 +740,11 @@ version of gccgo.
|
||||
and
|
||||
<a href="/pkg/context/#WithValue"><code>context.WithValue</code></a> instead.
|
||||
</li>
|
||||
|
||||
<li><!-- CL 35490 -->
|
||||
<a href="/pkg/net/http/#LocalAddrContextKey"><code>LocalAddrContextKey</code></a> now contains
|
||||
the connection's actual network address instead of the interface address used by the listener.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>Client & Transport changes:</p>
|
||||
@@ -728,7 +752,7 @@ version of gccgo.
|
||||
<li><!-- CL 35488 -->
|
||||
The <a href="/pkg/net/http/#Transport"><code>Transport</code></a>
|
||||
now supports making requests via SOCKS5 proxy when the URL returned by
|
||||
<a href="/net/http/#Transport.Proxy"><code>Transport.Proxy</code></a>
|
||||
<a href="/pkg/net/http/#Transport.Proxy"><code>Transport.Proxy</code></a>
|
||||
has the scheme <code>socks5</code>.
|
||||
</li>
|
||||
</ul>
|
||||
@@ -764,6 +788,16 @@ version of gccgo.
|
||||
|
||||
</dl><!-- net/http/httptest -->
|
||||
|
||||
<dl id="net/http/httputil"><dt><a href="/pkg/net/http/httputil/">net/http/httputil</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 43712 -->
|
||||
The <a href="/pkg/net/http/httputil/#ReverseProxy"><code>ReverseProxy</code></a>
|
||||
now proxies all HTTP/2 response trailers, even those not declared in the initial response
|
||||
header. Such undeclared trailers are used by the gRPC protocol.
|
||||
</p>
|
||||
|
||||
</dl><!-- net/http/httputil -->
|
||||
|
||||
<dl id="os"><dt><a href="/pkg/os/">os</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 36800 -->
|
||||
|
||||
@@ -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.8.1</code>, for example):</p>
|
||||
(<code class="versionTag">go1.9</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.8.1</code>.
|
||||
<code class="versionTag">go1.9</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
||||
144
doc/root.html
144
doc/root.html
@@ -6,7 +6,9 @@
|
||||
<div class="left">
|
||||
|
||||
<div id="learn">
|
||||
{{if not $.GoogleCN}}
|
||||
<a class="popout share">Pop-out</a>
|
||||
{{end}}
|
||||
<div class="rootHeading">Try Go</div>
|
||||
<div class="input">
|
||||
<textarea spellcheck="false" class="code">// You can edit this code!
|
||||
@@ -26,10 +28,10 @@ Hello, 世界
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<a class="run" href="#" title="Run this code [shift-enter]">Run</a>
|
||||
{{if $.Share}}
|
||||
{{if not $.GoogleCN}}
|
||||
<a class="share" href="#" title="Share this code">Share</a>
|
||||
{{end}}
|
||||
<a class="tour" href="//tour.golang.org/" title="Learn Go from your browser">Tour</a>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="toys">
|
||||
<select>
|
||||
@@ -68,85 +70,91 @@ Linux, Mac OS X, Windows, and more.
|
||||
|
||||
<div style="clear: both"></div>
|
||||
|
||||
{{if not $.GoogleCN}}
|
||||
<div class="left">
|
||||
|
||||
<div id="video">
|
||||
<div class="rootHeading">Featured video</div>
|
||||
<iframe width="415" height="241" src="//www.youtube.com/embed/ytEkHepK08c" frameborder="0" allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
<div id="video">
|
||||
<div class="rootHeading">Featured video</div>
|
||||
<iframe width="415" height="241" src="//www.youtube.com/embed/ytEkHepK08c" frameborder="0" allowfullscreen></iframe>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="right">
|
||||
|
||||
<div id="blog">
|
||||
<div class="rootHeading">Featured articles</div>
|
||||
<div class="read"><a href="//blog.golang.org/">Read more</a></div>
|
||||
</div>
|
||||
|
||||
<div id="blog">
|
||||
<div class="rootHeading">Featured articles</div>
|
||||
<div class="read"><a href="//blog.golang.org/">Read more</a></div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<div style="clear: both;"></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
<script>
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
function readableTime(t) {
|
||||
var m = ["January", "February", "March", "April", "May", "June", "July",
|
||||
"August", "September", "October", "November", "December"];
|
||||
var p = t.substring(0, t.indexOf("T")).split("-");
|
||||
var d = new Date(p[0], p[1]-1, p[2]);
|
||||
return d.getDate() + " " + m[d.getMonth()] + " " + d.getFullYear();
|
||||
}
|
||||
window.initFuncs.push(function() {
|
||||
// Set up playground if enabled.
|
||||
if (window.playground) {
|
||||
window.playground({
|
||||
"codeEl": "#learn .code",
|
||||
"outputEl": "#learn .output",
|
||||
"runEl": "#learn .run",
|
||||
"shareEl": "#learn .share",
|
||||
"shareRedirect": "//play.golang.org/p/",
|
||||
"toysEl": "#learn .toys select"
|
||||
});
|
||||
} else {
|
||||
$('#learn').hide()
|
||||
}
|
||||
});
|
||||
|
||||
function feedLoaded(result) {
|
||||
var blog = document.getElementById("blog");
|
||||
var read = blog.getElementsByClassName("read")[0];
|
||||
for (var i = 0; i < result.length && i < 2; i++) {
|
||||
var entry = result[i];
|
||||
var title = document.createElement("a");
|
||||
title.className = "title";
|
||||
title.href = entry.Link;
|
||||
title.innerHTML = entry.Title;
|
||||
blog.insertBefore(title, read);
|
||||
var extract = document.createElement("div");
|
||||
extract.className = "extract";
|
||||
extract.innerHTML = entry.Summary;
|
||||
blog.insertBefore(extract, read);
|
||||
var when = document.createElement("div");
|
||||
when.className = "when";
|
||||
when.innerHTML = "Published " + readableTime(entry.Time);
|
||||
blog.insertBefore(when, read);
|
||||
}
|
||||
}
|
||||
{{if not $.GoogleCN}}
|
||||
|
||||
window.initFuncs.push(function() {
|
||||
// Set up playground if enabled.
|
||||
if (window.playground) {
|
||||
window.playground({
|
||||
"codeEl": "#learn .code",
|
||||
"outputEl": "#learn .output",
|
||||
"runEl": "#learn .run",
|
||||
"shareEl": "#learn .share",
|
||||
"shareRedirect": "//play.golang.org/p/",
|
||||
"toysEl": "#learn .toys select"
|
||||
});
|
||||
} else {
|
||||
$('#learn').hide()
|
||||
function readableTime(t) {
|
||||
var m = ["January", "February", "March", "April", "May", "June", "July",
|
||||
"August", "September", "October", "November", "December"];
|
||||
var p = t.substring(0, t.indexOf("T")).split("-");
|
||||
var d = new Date(p[0], p[1]-1, p[2]);
|
||||
return d.getDate() + " " + m[d.getMonth()] + " " + d.getFullYear();
|
||||
}
|
||||
|
||||
// Load blog feed.
|
||||
$('<script/>').attr('text', 'text/javascript')
|
||||
.attr('src', '//blog.golang.org/.json?jsonp=feedLoaded')
|
||||
.appendTo('body');
|
||||
window.feedLoaded = function(result) {
|
||||
var blog = document.getElementById("blog");
|
||||
var read = blog.getElementsByClassName("read")[0];
|
||||
for (var i = 0; i < result.length && i < 2; i++) {
|
||||
var entry = result[i];
|
||||
var title = document.createElement("a");
|
||||
title.className = "title";
|
||||
title.href = entry.Link;
|
||||
title.innerHTML = entry.Title;
|
||||
blog.insertBefore(title, read);
|
||||
var extract = document.createElement("div");
|
||||
extract.className = "extract";
|
||||
extract.innerHTML = entry.Summary;
|
||||
blog.insertBefore(extract, read);
|
||||
var when = document.createElement("div");
|
||||
when.className = "when";
|
||||
when.innerHTML = "Published " + readableTime(entry.Time);
|
||||
blog.insertBefore(when, read);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the video at random.
|
||||
var videos = [
|
||||
{h: 241, s: "//www.youtube.com/embed/ytEkHepK08c"}, // Tour of Go
|
||||
{h: 241, s: "//www.youtube.com/embed/f6kdp27TYZs"}, // Concurrency Patterns
|
||||
{h: 233, s: "//player.vimeo.com/video/69237265"} // Simple environment
|
||||
];
|
||||
var v = videos[Math.floor(Math.random()*videos.length)];
|
||||
$('#video iframe').attr('height', v.h).attr('src', v.s);
|
||||
});
|
||||
window.initFuncs.push(function() {
|
||||
// Load blog feed.
|
||||
$('<script/>').attr('text', 'text/javascript')
|
||||
.attr('src', '//blog.golang.org/.json?jsonp=feedLoaded')
|
||||
.appendTo('body');
|
||||
|
||||
// Set the video at random.
|
||||
var videos = [
|
||||
{h: 241, s: "//www.youtube.com/embed/ytEkHepK08c"}, // Tour of Go
|
||||
{h: 241, s: "//www.youtube.com/embed/f6kdp27TYZs"}, // Concurrency Patterns
|
||||
{h: 233, s: "//player.vimeo.com/video/69237265"} // Simple environment
|
||||
];
|
||||
var v = videos[Math.floor(Math.random()*videos.length)];
|
||||
$('#video iframe').attr('height', v.h).attr('src', v.s);
|
||||
});
|
||||
|
||||
{{end}}
|
||||
})();
|
||||
</script>
|
||||
|
||||
@@ -343,6 +343,14 @@ var ptrTests = []ptrTest{
|
||||
body: `var b C.char; p := &b; C.f((*C.u)(unsafe.Pointer(&p)))`,
|
||||
fail: false,
|
||||
},
|
||||
{
|
||||
// Issue #21306.
|
||||
name: "preempt-during-call",
|
||||
c: `void f() {}`,
|
||||
imports: []string{"runtime", "sync"},
|
||||
body: `var wg sync.WaitGroup; wg.Add(100); for i := 0; i < 100; i++ { go func(i int) { for j := 0; j < 100; j++ { C.f(); runtime.GOMAXPROCS(i) }; wg.Done() }(i) }; wg.Wait()`,
|
||||
fail: false,
|
||||
},
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
@@ -156,15 +156,18 @@ if test "$tsan" = "yes"; then
|
||||
if ! $CC -fsanitize=thread ${TMPDIR}/testsanitizers$$.c -o ${TMPDIR}/testsanitizers$$ &> ${TMPDIR}/testsanitizers$$.err; then
|
||||
ok=no
|
||||
fi
|
||||
if grep "unrecognized" ${TMPDIR}/testsanitizers$$.err >& /dev/null; then
|
||||
if grep "unrecognized" ${TMPDIR}/testsanitizers$$.err >& /dev/null; then
|
||||
echo "skipping tsan tests: -fsanitize=thread not supported"
|
||||
tsan=no
|
||||
elif test "$ok" != "yes"; then
|
||||
cat ${TMPDIR}/testsanitizers$$.err
|
||||
echo "skipping tsan tests: -fsanitizer=thread build failed"
|
||||
tsan=no
|
||||
fi
|
||||
rm -f ${TMPDIR}/testsanitizers$$*
|
||||
elif test "$ok" != "yes"; then
|
||||
cat ${TMPDIR}/testsanitizers$$.err
|
||||
echo "skipping tsan tests: -fsanitizer=thread build failed"
|
||||
tsan=no
|
||||
elif ! ${TMPDIR}/testsanitizers$$ 2>&1; then
|
||||
echo "skipping tsan tests: running tsan program failed"
|
||||
tsan=no
|
||||
fi
|
||||
rm -f ${TMPDIR}/testsanitizers$$*
|
||||
fi
|
||||
|
||||
# Run a TSAN test.
|
||||
@@ -196,8 +199,10 @@ if test "$tsan" = "yes"; then
|
||||
# These tests are only reliable using clang or GCC version 7 or later.
|
||||
# Otherwise runtime/cgo/libcgo.h can't tell whether TSAN is in use.
|
||||
ok=false
|
||||
clang=false
|
||||
if ${CC} --version | grep clang >/dev/null 2>&1; then
|
||||
ok=true
|
||||
clang=true
|
||||
else
|
||||
ver=$($CC -dumpversion)
|
||||
major=$(echo $ver | sed -e 's/\([0-9]*\).*/\1/')
|
||||
@@ -213,9 +218,13 @@ if test "$tsan" = "yes"; then
|
||||
testtsan tsan5.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
|
||||
testtsan tsan6.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
|
||||
testtsan tsan7.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
|
||||
testtsan tsan10.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
|
||||
testtsan tsan11.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
|
||||
testtsan tsan12.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
|
||||
|
||||
# The remaining tests reportedly hang when built with GCC; issue #21196.
|
||||
if test "$clang" = "true"; then
|
||||
testtsan tsan10.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
|
||||
testtsan tsan11.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
|
||||
testtsan tsan12.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
|
||||
fi
|
||||
|
||||
testtsanshared
|
||||
fi
|
||||
|
||||
@@ -571,16 +571,9 @@ var knownFormats = map[string]string{
|
||||
"*cmd/compile/internal/ssa.Block %s": "",
|
||||
"*cmd/compile/internal/ssa.Block %v": "",
|
||||
"*cmd/compile/internal/ssa.Func %s": "",
|
||||
"*cmd/compile/internal/ssa.Func %v": "",
|
||||
"*cmd/compile/internal/ssa.FuncDebug %v": "",
|
||||
"*cmd/compile/internal/ssa.LocalSlot %+v": "",
|
||||
"*cmd/compile/internal/ssa.LocalSlot %v": "",
|
||||
"*cmd/compile/internal/ssa.Register %v": "",
|
||||
"*cmd/compile/internal/ssa.SparseTreeNode %v": "",
|
||||
"*cmd/compile/internal/ssa.Value %s": "",
|
||||
"*cmd/compile/internal/ssa.Value %v": "",
|
||||
"*cmd/compile/internal/ssa.VarLoc %+v": "",
|
||||
"*cmd/compile/internal/ssa.VarLoc %v": "",
|
||||
"*cmd/compile/internal/ssa.sparseTreeMapEntry %v": "",
|
||||
"*cmd/compile/internal/types.Field %p": "",
|
||||
"*cmd/compile/internal/types.Field %v": "",
|
||||
@@ -599,7 +592,6 @@ var knownFormats = map[string]string{
|
||||
"*cmd/compile/internal/types.Type %p": "",
|
||||
"*cmd/compile/internal/types.Type %s": "",
|
||||
"*cmd/compile/internal/types.Type %v": "",
|
||||
"*cmd/internal/dwarf.Location %#v": "",
|
||||
"*cmd/internal/obj.Addr %v": "",
|
||||
"*cmd/internal/obj.LSym %v": "",
|
||||
"*cmd/internal/obj.Prog %s": "",
|
||||
@@ -608,21 +600,17 @@ var knownFormats = map[string]string{
|
||||
"[16]byte %x": "",
|
||||
"[]*cmd/compile/internal/gc.Node %v": "",
|
||||
"[]*cmd/compile/internal/gc.Sig %#v": "",
|
||||
"[]*cmd/compile/internal/ssa.Block %+v": "",
|
||||
"[]*cmd/compile/internal/ssa.Value %v": "",
|
||||
"[][]cmd/compile/internal/ssa.SlotID %v": "",
|
||||
"[]byte %s": "",
|
||||
"[]byte %x": "",
|
||||
"[]cmd/compile/internal/ssa.Edge %v": "",
|
||||
"[]cmd/compile/internal/ssa.ID %v": "",
|
||||
"[]cmd/compile/internal/ssa.VarLocList %v": "",
|
||||
"[]string %v": "",
|
||||
"bool %v": "",
|
||||
"byte %08b": "",
|
||||
"byte %c": "",
|
||||
"cmd/compile/internal/arm.shift %d": "",
|
||||
"cmd/compile/internal/gc.Class %d": "",
|
||||
"cmd/compile/internal/gc.Class %v": "",
|
||||
"cmd/compile/internal/gc.Ctype %d": "",
|
||||
"cmd/compile/internal/gc.Ctype %v": "",
|
||||
"cmd/compile/internal/gc.Level %d": "",
|
||||
@@ -642,13 +630,11 @@ var knownFormats = map[string]string{
|
||||
"cmd/compile/internal/ssa.Edge %v": "",
|
||||
"cmd/compile/internal/ssa.GCNode %v": "",
|
||||
"cmd/compile/internal/ssa.ID %d": "",
|
||||
"cmd/compile/internal/ssa.ID %v": "",
|
||||
"cmd/compile/internal/ssa.LocalSlot %v": "",
|
||||
"cmd/compile/internal/ssa.Location %v": "",
|
||||
"cmd/compile/internal/ssa.Op %s": "",
|
||||
"cmd/compile/internal/ssa.Op %v": "",
|
||||
"cmd/compile/internal/ssa.ValAndOff %s": "",
|
||||
"cmd/compile/internal/ssa.VarLocList %v": "",
|
||||
"cmd/compile/internal/ssa.rbrank %d": "",
|
||||
"cmd/compile/internal/ssa.regMask %d": "",
|
||||
"cmd/compile/internal/ssa.register %d": "",
|
||||
@@ -662,7 +648,6 @@ var knownFormats = map[string]string{
|
||||
"cmd/compile/internal/types.EType %d": "",
|
||||
"cmd/compile/internal/types.EType %s": "",
|
||||
"cmd/compile/internal/types.EType %v": "",
|
||||
"cmd/internal/dwarf.Location %#v": "",
|
||||
"cmd/internal/src.Pos %s": "",
|
||||
"cmd/internal/src.Pos %v": "",
|
||||
"error %v": "",
|
||||
|
||||
@@ -464,6 +464,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
case ssa.OpARMMOVWaddr:
|
||||
p := s.Prog(arm.AMOVW)
|
||||
p.From.Type = obj.TYPE_ADDR
|
||||
p.From.Reg = v.Args[0].Reg()
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = v.Reg()
|
||||
|
||||
@@ -485,7 +486,6 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
case nil:
|
||||
// No sym, just MOVW $off(SP), R
|
||||
wantreg = "SP"
|
||||
p.From.Reg = arm.REGSP
|
||||
p.From.Offset = v.AuxInt
|
||||
}
|
||||
if reg := v.Args[0].RegName(); reg != wantreg {
|
||||
|
||||
@@ -260,6 +260,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
case ssa.OpARM64MOVDaddr:
|
||||
p := s.Prog(arm64.AMOVD)
|
||||
p.From.Type = obj.TYPE_ADDR
|
||||
p.From.Reg = v.Args[0].Reg()
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = v.Reg()
|
||||
|
||||
@@ -281,7 +282,6 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
case nil:
|
||||
// No sym, just MOVD $off(SP), R
|
||||
wantreg = "SP"
|
||||
p.From.Reg = arm64.REGSP
|
||||
p.From.Offset = v.AuxInt
|
||||
}
|
||||
if reg := v.Args[0].RegName(); reg != wantreg {
|
||||
|
||||
@@ -898,6 +898,17 @@ var linuxAMD64Tests = []*asmTest{
|
||||
}`,
|
||||
[]string{"\tCMPL\t[A-Z]"},
|
||||
},
|
||||
{
|
||||
// make sure assembly output has matching offset and base register.
|
||||
`
|
||||
func f72(a, b int) int {
|
||||
var x [16]byte // use some frame
|
||||
_ = x
|
||||
return b
|
||||
}
|
||||
`,
|
||||
[]string{"b\\+40\\(SP\\)"},
|
||||
},
|
||||
}
|
||||
|
||||
var linux386Tests = []*asmTest{
|
||||
@@ -1302,6 +1313,17 @@ var linuxARMTests = []*asmTest{
|
||||
`,
|
||||
[]string{"\tCLZ\t"},
|
||||
},
|
||||
{
|
||||
// make sure assembly output has matching offset and base register.
|
||||
`
|
||||
func f13(a, b int) int {
|
||||
var x [16]byte // use some frame
|
||||
_ = x
|
||||
return b
|
||||
}
|
||||
`,
|
||||
[]string{"b\\+4\\(FP\\)"},
|
||||
},
|
||||
}
|
||||
|
||||
var linuxARM64Tests = []*asmTest{
|
||||
@@ -1473,7 +1495,7 @@ var linuxARM64Tests = []*asmTest{
|
||||
return
|
||||
}
|
||||
`,
|
||||
[]string{"\tMOVD\t\"\"\\.a\\+[0-9]+\\(RSP\\), R[0-9]+", "\tMOVD\tR[0-9]+, \"\"\\.b\\+[0-9]+\\(RSP\\)"},
|
||||
[]string{"\tMOVD\t\"\"\\.a\\+[0-9]+\\(FP\\), R[0-9]+", "\tMOVD\tR[0-9]+, \"\"\\.b\\+[0-9]+\\(FP\\)"},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -293,4 +293,8 @@ var (
|
||||
typedmemmove,
|
||||
typedmemclr,
|
||||
Udiv *obj.LSym
|
||||
|
||||
// GO386=387
|
||||
ControlWord64trunc,
|
||||
ControlWord32 *obj.LSym
|
||||
)
|
||||
|
||||
@@ -44,7 +44,6 @@ var (
|
||||
Debug_vlog bool
|
||||
Debug_wb int
|
||||
Debug_pctab string
|
||||
Debug_locationlist int
|
||||
)
|
||||
|
||||
// Debug arguments.
|
||||
@@ -70,7 +69,6 @@ var debugtab = []struct {
|
||||
{"wb", "print information about write barriers", &Debug_wb},
|
||||
{"export", "print export data", &Debug_export},
|
||||
{"pctab", "print named pc-value table", &Debug_pctab},
|
||||
{"locationlists", "print information about DWARF location list creation", &Debug_locationlist},
|
||||
}
|
||||
|
||||
const debugHelpHeader = `usage: -d arg[,arg]* and arg is <key>[=<value>]
|
||||
@@ -194,7 +192,6 @@ func Main(archInit func(*Arch)) {
|
||||
flag.BoolVar(&pure_go, "complete", false, "compiling complete package (no C or assembly)")
|
||||
flag.StringVar(&debugstr, "d", "", "print debug information about items in `list`; try -d help")
|
||||
flag.BoolVar(&flagDWARF, "dwarf", true, "generate DWARF symbols")
|
||||
flag.BoolVar(&Ctxt.Flag_locationlists, "dwarflocationlists", false, "add location lists to DWARF in optimized mode")
|
||||
objabi.Flagcount("e", "no limit on number of errors reported", &Debug['e'])
|
||||
objabi.Flagcount("f", "debug stack frames", &Debug['f'])
|
||||
objabi.Flagcount("h", "halt on error", &Debug['h'])
|
||||
@@ -301,9 +298,6 @@ func Main(archInit func(*Arch)) {
|
||||
if nBackendWorkers > 1 && !concurrentBackendAllowed() {
|
||||
log.Fatalf("cannot use concurrent backend compilation with provided flags; invoked as %v", os.Args)
|
||||
}
|
||||
if Ctxt.Flag_locationlists && len(Ctxt.Arch.DWARFRegisters) == 0 {
|
||||
log.Fatalf("location lists requested but register mapping not available on %v", Ctxt.Arch.Name)
|
||||
}
|
||||
|
||||
// parse -d argument
|
||||
if debugstr != "" {
|
||||
@@ -389,7 +383,7 @@ func Main(archInit func(*Arch)) {
|
||||
Debug['l'] = 1 - Debug['l']
|
||||
}
|
||||
|
||||
trackScopes = flagDWARF && ((Debug['l'] == 0 && Debug['N'] != 0) || Ctxt.Flag_locationlists)
|
||||
trackScopes = flagDWARF && Debug['l'] == 0 && Debug['N'] != 0
|
||||
|
||||
Widthptr = thearch.LinkArch.PtrSize
|
||||
Widthreg = thearch.LinkArch.RegSize
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"cmd/internal/src"
|
||||
"cmd/internal/sys"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"sort"
|
||||
"sync"
|
||||
@@ -304,77 +303,29 @@ func compileFunctions() {
|
||||
|
||||
func debuginfo(fnsym *obj.LSym, curfn interface{}) []dwarf.Scope {
|
||||
fn := curfn.(*Node)
|
||||
debugInfo := fn.Func.DebugInfo
|
||||
fn.Func.DebugInfo = nil
|
||||
if expect := fn.Func.Nname.Sym.Linksym(); fnsym != expect {
|
||||
Fatalf("unexpected fnsym: %v != %v", fnsym, expect)
|
||||
}
|
||||
|
||||
var automDecls []*Node
|
||||
// Populate Automs for fn.
|
||||
var dwarfVars []*dwarf.Var
|
||||
var varScopes []ScopeID
|
||||
|
||||
for _, n := range fn.Func.Dcl {
|
||||
if n.Op != ONAME { // might be OTYPE or OLITERAL
|
||||
continue
|
||||
}
|
||||
|
||||
var name obj.AddrName
|
||||
var abbrev int
|
||||
offs := n.Xoffset
|
||||
|
||||
switch n.Class() {
|
||||
case PAUTO:
|
||||
if !n.Name.Used() {
|
||||
Fatalf("debuginfo unused node (AllocFrame should truncate fn.Func.Dcl)")
|
||||
}
|
||||
name = obj.NAME_AUTO
|
||||
case PPARAM, PPARAMOUT:
|
||||
name = obj.NAME_PARAM
|
||||
default:
|
||||
continue
|
||||
}
|
||||
automDecls = append(automDecls, n)
|
||||
gotype := ngotype(n).Linksym()
|
||||
fnsym.Func.Autom = append(fnsym.Func.Autom, &obj.Auto{
|
||||
Asym: Ctxt.Lookup(n.Sym.Name),
|
||||
Aoffset: int32(n.Xoffset),
|
||||
Name: name,
|
||||
Gotype: gotype,
|
||||
})
|
||||
}
|
||||
|
||||
var dwarfVars []*dwarf.Var
|
||||
var decls []*Node
|
||||
if Ctxt.Flag_locationlists && Ctxt.Flag_optimize {
|
||||
decls, dwarfVars = createComplexVars(fn, debugInfo)
|
||||
} else {
|
||||
decls, dwarfVars = createSimpleVars(automDecls)
|
||||
}
|
||||
|
||||
var varScopes []ScopeID
|
||||
for _, decl := range decls {
|
||||
var scope ScopeID
|
||||
if !decl.Name.Captured() && !decl.Name.Byval() {
|
||||
// n.Pos of captured variables is their first
|
||||
// use in the closure but they should always
|
||||
// be assigned to scope 0 instead.
|
||||
// TODO(mdempsky): Verify this.
|
||||
scope = findScope(fn.Func.Marks, decl.Pos)
|
||||
}
|
||||
varScopes = append(varScopes, scope)
|
||||
}
|
||||
return assembleScopes(fnsym, fn, dwarfVars, varScopes)
|
||||
}
|
||||
|
||||
// createSimpleVars creates a DWARF entry for every variable declared in the
|
||||
// function, claiming that they are permanently on the stack.
|
||||
func createSimpleVars(automDecls []*Node) ([]*Node, []*dwarf.Var) {
|
||||
var vars []*dwarf.Var
|
||||
var decls []*Node
|
||||
for _, n := range automDecls {
|
||||
if n.IsAutoTmp() {
|
||||
continue
|
||||
}
|
||||
var abbrev int
|
||||
offs := n.Xoffset
|
||||
|
||||
switch n.Class() {
|
||||
case PAUTO:
|
||||
abbrev = dwarf.DW_ABRV_AUTO
|
||||
if Ctxt.FixedFrameSize() == 0 {
|
||||
offs -= int64(Widthptr)
|
||||
@@ -384,288 +335,48 @@ func createSimpleVars(automDecls []*Node) ([]*Node, []*dwarf.Var) {
|
||||
}
|
||||
|
||||
case PPARAM, PPARAMOUT:
|
||||
name = obj.NAME_PARAM
|
||||
|
||||
abbrev = dwarf.DW_ABRV_PARAM
|
||||
offs += Ctxt.FixedFrameSize()
|
||||
|
||||
default:
|
||||
Fatalf("createSimpleVars unexpected type %v for node %v", n.Class(), n)
|
||||
continue
|
||||
}
|
||||
|
||||
typename := dwarf.InfoPrefix + typesymname(n.Type)
|
||||
decls = append(decls, n)
|
||||
vars = append(vars, &dwarf.Var{
|
||||
Name: n.Sym.Name,
|
||||
Abbrev: abbrev,
|
||||
StackOffset: int32(offs),
|
||||
Type: Ctxt.Lookup(typename),
|
||||
gotype := ngotype(n).Linksym()
|
||||
fnsym.Func.Autom = append(fnsym.Func.Autom, &obj.Auto{
|
||||
Asym: Ctxt.Lookup(n.Sym.Name),
|
||||
Aoffset: int32(n.Xoffset),
|
||||
Name: name,
|
||||
Gotype: gotype,
|
||||
})
|
||||
}
|
||||
return decls, vars
|
||||
}
|
||||
|
||||
type varPart struct {
|
||||
varOffset int64
|
||||
slot ssa.SlotID
|
||||
locs ssa.VarLocList
|
||||
}
|
||||
|
||||
func createComplexVars(fn *Node, debugInfo *ssa.FuncDebug) ([]*Node, []*dwarf.Var) {
|
||||
for _, locList := range debugInfo.Variables {
|
||||
for _, loc := range locList.Locations {
|
||||
if loc.StartProg != nil {
|
||||
loc.StartPC = loc.StartProg.Pc
|
||||
}
|
||||
if loc.EndProg != nil {
|
||||
loc.EndPC = loc.EndProg.Pc
|
||||
}
|
||||
if Debug_locationlist == 0 {
|
||||
loc.EndProg = nil
|
||||
loc.StartProg = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Group SSA variables by the user variable they were decomposed from.
|
||||
varParts := map[*Node][]varPart{}
|
||||
for slotID, locList := range debugInfo.Variables {
|
||||
if len(locList.Locations) == 0 {
|
||||
continue
|
||||
}
|
||||
slot := debugInfo.Slots[slotID]
|
||||
for slot.SplitOf != nil {
|
||||
slot = slot.SplitOf
|
||||
}
|
||||
n := slot.N.(*Node)
|
||||
varParts[n] = append(varParts[n], varPart{varOffset(slot), ssa.SlotID(slotID), locList})
|
||||
}
|
||||
|
||||
// Produce a DWARF variable entry for each user variable.
|
||||
// Don't iterate over the map -- that's nondeterministic, and
|
||||
// createComplexVar has side effects. Instead, go by slot.
|
||||
var decls []*Node
|
||||
var vars []*dwarf.Var
|
||||
for _, slot := range debugInfo.Slots {
|
||||
for slot.SplitOf != nil {
|
||||
slot = slot.SplitOf
|
||||
}
|
||||
n := slot.N.(*Node)
|
||||
parts := varParts[n]
|
||||
if parts == nil {
|
||||
if n.IsAutoTmp() {
|
||||
continue
|
||||
}
|
||||
|
||||
// Get the order the parts need to be in to represent the memory
|
||||
// of the decomposed user variable.
|
||||
sort.Sort(partsByVarOffset(parts))
|
||||
typename := dwarf.InfoPrefix + gotype.Name[len("type."):]
|
||||
dwarfVars = append(dwarfVars, &dwarf.Var{
|
||||
Name: n.Sym.Name,
|
||||
Abbrev: abbrev,
|
||||
Offset: int32(offs),
|
||||
Type: Ctxt.Lookup(typename),
|
||||
})
|
||||
|
||||
if dvar := createComplexVar(debugInfo, n, parts); dvar != nil {
|
||||
decls = append(decls, n)
|
||||
vars = append(vars, dvar)
|
||||
}
|
||||
}
|
||||
return decls, vars
|
||||
}
|
||||
|
||||
// varOffset returns the offset of slot within the user variable it was
|
||||
// decomposed from. This has nothing to do with its stack offset.
|
||||
func varOffset(slot *ssa.LocalSlot) int64 {
|
||||
offset := slot.Off
|
||||
for ; slot.SplitOf != nil; slot = slot.SplitOf {
|
||||
offset += slot.SplitOffset
|
||||
}
|
||||
return offset
|
||||
}
|
||||
|
||||
type partsByVarOffset []varPart
|
||||
|
||||
func (a partsByVarOffset) Len() int { return len(a) }
|
||||
func (a partsByVarOffset) Less(i, j int) bool { return a[i].varOffset < a[j].varOffset }
|
||||
func (a partsByVarOffset) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
|
||||
// createComplexVar builds a DWARF variable entry and location list representing n.
|
||||
func createComplexVar(debugInfo *ssa.FuncDebug, n *Node, parts []varPart) *dwarf.Var {
|
||||
slots := debugInfo.Slots
|
||||
var offs int64 // base stack offset for this kind of variable
|
||||
var abbrev int
|
||||
switch n.Class() {
|
||||
case PAUTO:
|
||||
abbrev = dwarf.DW_ABRV_AUTO_LOCLIST
|
||||
if Ctxt.FixedFrameSize() == 0 {
|
||||
offs -= int64(Widthptr)
|
||||
}
|
||||
if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) {
|
||||
offs -= int64(Widthptr)
|
||||
var scope ScopeID
|
||||
if !n.Name.Captured() && !n.Name.Byval() {
|
||||
// n.Pos of captured variables is their first
|
||||
// use in the closure but they should always
|
||||
// be assigned to scope 0 instead.
|
||||
// TODO(mdempsky): Verify this.
|
||||
scope = findScope(fn.Func.Marks, n.Pos)
|
||||
}
|
||||
|
||||
case PPARAM, PPARAMOUT:
|
||||
abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
|
||||
offs += Ctxt.FixedFrameSize()
|
||||
default:
|
||||
return nil
|
||||
varScopes = append(varScopes, scope)
|
||||
}
|
||||
|
||||
gotype := ngotype(n).Linksym()
|
||||
typename := dwarf.InfoPrefix + gotype.Name[len("type."):]
|
||||
// The stack offset is used as a sorting key, so for decomposed
|
||||
// variables just give it the lowest one. It's not used otherwise.
|
||||
stackOffset := debugInfo.Slots[parts[0].slot].N.(*Node).Xoffset + offs
|
||||
dvar := &dwarf.Var{
|
||||
Name: n.Sym.Name,
|
||||
Abbrev: abbrev,
|
||||
Type: Ctxt.Lookup(typename),
|
||||
StackOffset: int32(stackOffset),
|
||||
}
|
||||
|
||||
if Debug_locationlist != 0 {
|
||||
Ctxt.Logf("Building location list for %+v. Parts:\n", n)
|
||||
for _, part := range parts {
|
||||
Ctxt.Logf("\t%v => %v\n", debugInfo.Slots[part.slot], part.locs)
|
||||
}
|
||||
}
|
||||
|
||||
// Given a variable that's been decomposed into multiple parts,
|
||||
// its location list may need a new entry after the beginning or
|
||||
// end of every location entry for each of its parts. For example:
|
||||
//
|
||||
// [variable] [pc range]
|
||||
// string.ptr |----|-----| |----|
|
||||
// string.len |------------| |--|
|
||||
// ... needs a location list like:
|
||||
// string |----|-----|-| |--|-|
|
||||
//
|
||||
// Note that location entries may or may not line up with each other,
|
||||
// and some of the result will only have one or the other part.
|
||||
//
|
||||
// To build the resulting list:
|
||||
// - keep a "current" pointer for each part
|
||||
// - find the next transition point
|
||||
// - advance the current pointer for each part up to that transition point
|
||||
// - build the piece for the range between that transition point and the next
|
||||
// - repeat
|
||||
|
||||
curLoc := make([]int, len(slots))
|
||||
|
||||
// findBoundaryAfter finds the next beginning or end of a piece after currentPC.
|
||||
findBoundaryAfter := func(currentPC int64) int64 {
|
||||
min := int64(math.MaxInt64)
|
||||
for slot, part := range parts {
|
||||
// For each part, find the first PC greater than current. Doesn't
|
||||
// matter if it's a start or an end, since we're looking for any boundary.
|
||||
// If it's the new winner, save it.
|
||||
onePart:
|
||||
for i := curLoc[slot]; i < len(part.locs.Locations); i++ {
|
||||
for _, pc := range [2]int64{part.locs.Locations[i].StartPC, part.locs.Locations[i].EndPC} {
|
||||
if pc > currentPC {
|
||||
if pc < min {
|
||||
min = pc
|
||||
}
|
||||
break onePart
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return min
|
||||
}
|
||||
var start int64
|
||||
end := findBoundaryAfter(0)
|
||||
for {
|
||||
// Advance to the next chunk.
|
||||
start = end
|
||||
end = findBoundaryAfter(start)
|
||||
if end == math.MaxInt64 {
|
||||
break
|
||||
}
|
||||
|
||||
dloc := dwarf.Location{StartPC: start, EndPC: end}
|
||||
if Debug_locationlist != 0 {
|
||||
Ctxt.Logf("Processing range %x -> %x\n", start, end)
|
||||
}
|
||||
|
||||
// Advance curLoc to the last location that starts before/at start.
|
||||
// After this loop, if there's a location that covers [start, end), it will be current.
|
||||
// Otherwise the current piece will be too early.
|
||||
for _, part := range parts {
|
||||
choice := -1
|
||||
for i := curLoc[part.slot]; i < len(part.locs.Locations); i++ {
|
||||
if part.locs.Locations[i].StartPC > start {
|
||||
break //overshot
|
||||
}
|
||||
choice = i // best yet
|
||||
}
|
||||
if choice != -1 {
|
||||
curLoc[part.slot] = choice
|
||||
}
|
||||
if Debug_locationlist != 0 {
|
||||
Ctxt.Logf("\t %v => %v", slots[part.slot], curLoc[part.slot])
|
||||
}
|
||||
}
|
||||
if Debug_locationlist != 0 {
|
||||
Ctxt.Logf("\n")
|
||||
}
|
||||
// Assemble the location list entry for this chunk.
|
||||
present := 0
|
||||
for _, part := range parts {
|
||||
dpiece := dwarf.Piece{
|
||||
Length: slots[part.slot].Type.Size(),
|
||||
}
|
||||
locIdx := curLoc[part.slot]
|
||||
if locIdx >= len(part.locs.Locations) ||
|
||||
start >= part.locs.Locations[locIdx].EndPC ||
|
||||
end <= part.locs.Locations[locIdx].StartPC {
|
||||
if Debug_locationlist != 0 {
|
||||
Ctxt.Logf("\t%v: missing", slots[part.slot])
|
||||
}
|
||||
dpiece.Missing = true
|
||||
dloc.Pieces = append(dloc.Pieces, dpiece)
|
||||
continue
|
||||
}
|
||||
present++
|
||||
loc := part.locs.Locations[locIdx]
|
||||
if Debug_locationlist != 0 {
|
||||
Ctxt.Logf("\t%v: %v", slots[part.slot], loc)
|
||||
}
|
||||
if loc.OnStack {
|
||||
dpiece.OnStack = true
|
||||
dpiece.StackOffset = int32(offs + slots[part.slot].Off + slots[part.slot].N.(*Node).Xoffset)
|
||||
} else {
|
||||
for reg := 0; reg < len(debugInfo.Registers); reg++ {
|
||||
if loc.Registers&(1<<uint8(reg)) != 0 {
|
||||
dpiece.RegNum = Ctxt.Arch.DWARFRegisters[debugInfo.Registers[reg].ObjNum()]
|
||||
}
|
||||
}
|
||||
}
|
||||
dloc.Pieces = append(dloc.Pieces, dpiece)
|
||||
}
|
||||
if present == 0 {
|
||||
if Debug_locationlist != 0 {
|
||||
Ctxt.Logf(" -> totally missing\n")
|
||||
}
|
||||
continue
|
||||
}
|
||||
// Extend the previous entry if possible.
|
||||
if len(dvar.LocationList) > 0 {
|
||||
prev := &dvar.LocationList[len(dvar.LocationList)-1]
|
||||
if prev.EndPC == dloc.StartPC && len(prev.Pieces) == len(dloc.Pieces) {
|
||||
equal := true
|
||||
for i := range prev.Pieces {
|
||||
if prev.Pieces[i] != dloc.Pieces[i] {
|
||||
equal = false
|
||||
}
|
||||
}
|
||||
if equal {
|
||||
prev.EndPC = end
|
||||
if Debug_locationlist != 0 {
|
||||
Ctxt.Logf("-> merged with previous, now %#v\n", prev)
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
dvar.LocationList = append(dvar.LocationList, dloc)
|
||||
if Debug_locationlist != 0 {
|
||||
Ctxt.Logf("-> added: %#v\n", dloc)
|
||||
}
|
||||
}
|
||||
return dvar
|
||||
return assembleScopes(fnsym, fn, dwarfVars, varScopes)
|
||||
}
|
||||
|
||||
// fieldtrack adds R_USEFIELD relocations to fnsym to record any
|
||||
|
||||
@@ -168,7 +168,7 @@ func (v varsByScopeAndOffset) Less(i, j int) bool {
|
||||
if v.scopes[i] != v.scopes[j] {
|
||||
return v.scopes[i] < v.scopes[j]
|
||||
}
|
||||
return v.vars[i].StackOffset < v.vars[j].StackOffset
|
||||
return v.vars[i].Offset < v.vars[j].Offset
|
||||
}
|
||||
|
||||
func (v varsByScopeAndOffset) Swap(i, j int) {
|
||||
|
||||
@@ -22,7 +22,7 @@ func TestSizeof(t *testing.T) {
|
||||
_32bit uintptr // size on 32bit platforms
|
||||
_64bit uintptr // size on 64bit platforms
|
||||
}{
|
||||
{Func{}, 128, 224},
|
||||
{Func{}, 124, 216},
|
||||
{Name{}, 36, 56},
|
||||
{Param{}, 28, 56},
|
||||
{Node{}, 76, 128},
|
||||
|
||||
@@ -92,6 +92,10 @@ func initssaconfig() {
|
||||
typedmemmove = Sysfunc("typedmemmove")
|
||||
typedmemclr = Sysfunc("typedmemclr")
|
||||
Udiv = Sysfunc("udiv")
|
||||
|
||||
// GO386=387 runtime functions
|
||||
ControlWord64trunc = Sysfunc("controlWord64trunc")
|
||||
ControlWord32 = Sysfunc("controlWord32")
|
||||
}
|
||||
|
||||
// buildssa builds an SSA function for fn.
|
||||
@@ -4382,15 +4386,14 @@ func genssa(f *ssa.Func, pp *Progs) {
|
||||
// Remember where each block starts.
|
||||
s.bstart = make([]*obj.Prog, f.NumBlocks())
|
||||
s.pp = pp
|
||||
var progToValue map[*obj.Prog]*ssa.Value
|
||||
var progToBlock map[*obj.Prog]*ssa.Block
|
||||
var valueToProg []*obj.Prog
|
||||
var valueProgs map[*obj.Prog]*ssa.Value
|
||||
var blockProgs map[*obj.Prog]*ssa.Block
|
||||
var logProgs = e.log
|
||||
if logProgs {
|
||||
progToValue = make(map[*obj.Prog]*ssa.Value, f.NumValues())
|
||||
progToBlock = make(map[*obj.Prog]*ssa.Block, f.NumBlocks())
|
||||
valueProgs = make(map[*obj.Prog]*ssa.Value, f.NumValues())
|
||||
blockProgs = make(map[*obj.Prog]*ssa.Block, f.NumBlocks())
|
||||
f.Logf("genssa %s\n", f.Name)
|
||||
progToBlock[s.pp.next] = f.Blocks[0]
|
||||
blockProgs[s.pp.next] = f.Blocks[0]
|
||||
}
|
||||
|
||||
if thearch.Use387 {
|
||||
@@ -4399,11 +4402,6 @@ func genssa(f *ssa.Func, pp *Progs) {
|
||||
|
||||
s.ScratchFpMem = e.scratchFpMem
|
||||
|
||||
logLocationLists := Debug_locationlist != 0
|
||||
if Ctxt.Flag_locationlists {
|
||||
e.curfn.Func.DebugInfo = ssa.BuildFuncDebug(f, logLocationLists)
|
||||
valueToProg = make([]*obj.Prog, f.NumValues())
|
||||
}
|
||||
// Emit basic blocks
|
||||
for i, b := range f.Blocks {
|
||||
s.bstart[b.ID] = s.pp.next
|
||||
@@ -4444,19 +4442,15 @@ func genssa(f *ssa.Func, pp *Progs) {
|
||||
}
|
||||
case ssa.OpPhi:
|
||||
CheckLoweredPhi(v)
|
||||
case ssa.OpRegKill:
|
||||
// nothing to do
|
||||
|
||||
default:
|
||||
// let the backend handle it
|
||||
thearch.SSAGenValue(&s, v)
|
||||
}
|
||||
|
||||
if Ctxt.Flag_locationlists {
|
||||
valueToProg[v.ID] = x
|
||||
}
|
||||
if logProgs {
|
||||
for ; x != s.pp.next; x = x.Link {
|
||||
progToValue[x] = v
|
||||
valueProgs[x] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4474,23 +4468,7 @@ func genssa(f *ssa.Func, pp *Progs) {
|
||||
thearch.SSAGenBlock(&s, b, next)
|
||||
if logProgs {
|
||||
for ; x != s.pp.next; x = x.Link {
|
||||
progToBlock[x] = b
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if Ctxt.Flag_locationlists {
|
||||
for _, locList := range e.curfn.Func.DebugInfo.Variables {
|
||||
for _, loc := range locList.Locations {
|
||||
loc.StartProg = valueToProg[loc.Start.ID]
|
||||
if loc.End == nil {
|
||||
Fatalf("empty loc %v compiling %v", loc, f.Name)
|
||||
}
|
||||
loc.EndProg = valueToProg[loc.End.ID]
|
||||
if !logLocationLists {
|
||||
loc.Start = nil
|
||||
loc.End = nil
|
||||
}
|
||||
blockProgs[x] = b
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4503,9 +4481,9 @@ func genssa(f *ssa.Func, pp *Progs) {
|
||||
if logProgs {
|
||||
for p := pp.Text; p != nil; p = p.Link {
|
||||
var s string
|
||||
if v, ok := progToValue[p]; ok {
|
||||
if v, ok := valueProgs[p]; ok {
|
||||
s = v.String()
|
||||
} else if b, ok := progToBlock[p]; ok {
|
||||
} else if b, ok := blockProgs[p]; ok {
|
||||
s = b.String()
|
||||
} else {
|
||||
s = " " // most value and branch strings are 2-3 characters long
|
||||
@@ -4523,9 +4501,9 @@ func genssa(f *ssa.Func, pp *Progs) {
|
||||
buf.WriteString("<dl class=\"ssa-gen\">")
|
||||
for p := pp.Text; p != nil; p = p.Link {
|
||||
buf.WriteString("<dt class=\"ssa-prog-src\">")
|
||||
if v, ok := progToValue[p]; ok {
|
||||
if v, ok := valueProgs[p]; ok {
|
||||
buf.WriteString(v.HTML())
|
||||
} else if b, ok := progToBlock[p]; ok {
|
||||
} else if b, ok := blockProgs[p]; ok {
|
||||
buf.WriteString(b.HTML())
|
||||
}
|
||||
buf.WriteString("</dt>")
|
||||
@@ -4902,9 +4880,9 @@ func (e *ssafn) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
|
||||
lenType := types.Types[TINT]
|
||||
if n.Class() == PAUTO && !n.Addrtaken() {
|
||||
// Split this string up into two separate variables.
|
||||
p := e.splitSlot(&name, ".ptr", 0, ptrType)
|
||||
l := e.splitSlot(&name, ".len", ptrType.Size(), lenType)
|
||||
return p, l
|
||||
p := e.namedAuto(n.Sym.Name+".ptr", ptrType, n.Pos)
|
||||
l := e.namedAuto(n.Sym.Name+".len", lenType, n.Pos)
|
||||
return ssa.LocalSlot{N: p, Type: ptrType, Off: 0}, ssa.LocalSlot{N: l, Type: lenType, Off: 0}
|
||||
}
|
||||
// Return the two parts of the larger variable.
|
||||
return ssa.LocalSlot{N: n, Type: ptrType, Off: name.Off}, ssa.LocalSlot{N: n, Type: lenType, Off: name.Off + int64(Widthptr)}
|
||||
@@ -4919,9 +4897,9 @@ func (e *ssafn) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot
|
||||
if n.Type.IsEmptyInterface() {
|
||||
f = ".type"
|
||||
}
|
||||
c := e.splitSlot(&name, f, 0, t)
|
||||
d := e.splitSlot(&name, ".data", t.Size(), t)
|
||||
return c, d
|
||||
c := e.namedAuto(n.Sym.Name+f, t, n.Pos)
|
||||
d := e.namedAuto(n.Sym.Name+".data", t, n.Pos)
|
||||
return ssa.LocalSlot{N: c, Type: t, Off: 0}, ssa.LocalSlot{N: d, Type: t, Off: 0}
|
||||
}
|
||||
// Return the two parts of the larger variable.
|
||||
return ssa.LocalSlot{N: n, Type: t, Off: name.Off}, ssa.LocalSlot{N: n, Type: t, Off: name.Off + int64(Widthptr)}
|
||||
@@ -4933,10 +4911,10 @@ func (e *ssafn) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ss
|
||||
lenType := types.Types[TINT]
|
||||
if n.Class() == PAUTO && !n.Addrtaken() {
|
||||
// Split this slice up into three separate variables.
|
||||
p := e.splitSlot(&name, ".ptr", 0, ptrType)
|
||||
l := e.splitSlot(&name, ".len", ptrType.Size(), lenType)
|
||||
c := e.splitSlot(&name, ".cap", ptrType.Size()+lenType.Size(), lenType)
|
||||
return p, l, c
|
||||
p := e.namedAuto(n.Sym.Name+".ptr", ptrType, n.Pos)
|
||||
l := e.namedAuto(n.Sym.Name+".len", lenType, n.Pos)
|
||||
c := e.namedAuto(n.Sym.Name+".cap", lenType, n.Pos)
|
||||
return ssa.LocalSlot{N: p, Type: ptrType, Off: 0}, ssa.LocalSlot{N: l, Type: lenType, Off: 0}, ssa.LocalSlot{N: c, Type: lenType, Off: 0}
|
||||
}
|
||||
// Return the three parts of the larger variable.
|
||||
return ssa.LocalSlot{N: n, Type: ptrType, Off: name.Off},
|
||||
@@ -4955,9 +4933,9 @@ func (e *ssafn) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot)
|
||||
}
|
||||
if n.Class() == PAUTO && !n.Addrtaken() {
|
||||
// Split this complex up into two separate variables.
|
||||
r := e.splitSlot(&name, ".real", 0, t)
|
||||
i := e.splitSlot(&name, ".imag", t.Size(), t)
|
||||
return r, i
|
||||
c := e.namedAuto(n.Sym.Name+".real", t, n.Pos)
|
||||
d := e.namedAuto(n.Sym.Name+".imag", t, n.Pos)
|
||||
return ssa.LocalSlot{N: c, Type: t, Off: 0}, ssa.LocalSlot{N: d, Type: t, Off: 0}
|
||||
}
|
||||
// Return the two parts of the larger variable.
|
||||
return ssa.LocalSlot{N: n, Type: t, Off: name.Off}, ssa.LocalSlot{N: n, Type: t, Off: name.Off + s}
|
||||
@@ -4973,10 +4951,9 @@ func (e *ssafn) SplitInt64(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
|
||||
}
|
||||
if n.Class() == PAUTO && !n.Addrtaken() {
|
||||
// Split this int64 up into two separate variables.
|
||||
if thearch.LinkArch.ByteOrder == binary.BigEndian {
|
||||
return e.splitSlot(&name, ".hi", 0, t), e.splitSlot(&name, ".lo", t.Size(), types.Types[TUINT32])
|
||||
}
|
||||
return e.splitSlot(&name, ".hi", t.Size(), t), e.splitSlot(&name, ".lo", 0, types.Types[TUINT32])
|
||||
h := e.namedAuto(n.Sym.Name+".hi", t, n.Pos)
|
||||
l := e.namedAuto(n.Sym.Name+".lo", types.Types[TUINT32], n.Pos)
|
||||
return ssa.LocalSlot{N: h, Type: t, Off: 0}, ssa.LocalSlot{N: l, Type: types.Types[TUINT32], Off: 0}
|
||||
}
|
||||
// Return the two parts of the larger variable.
|
||||
if thearch.LinkArch.ByteOrder == binary.BigEndian {
|
||||
@@ -4989,15 +4966,12 @@ func (e *ssafn) SplitStruct(name ssa.LocalSlot, i int) ssa.LocalSlot {
|
||||
n := name.N.(*Node)
|
||||
st := name.Type
|
||||
ft := st.FieldType(i)
|
||||
var offset int64
|
||||
for f := 0; f < i; f++ {
|
||||
offset += st.FieldType(f).Size()
|
||||
}
|
||||
if n.Class() == PAUTO && !n.Addrtaken() {
|
||||
// Note: the _ field may appear several times. But
|
||||
// have no fear, identically-named but distinct Autos are
|
||||
// ok, albeit maybe confusing for a debugger.
|
||||
return e.splitSlot(&name, "."+st.FieldName(i), offset, ft)
|
||||
x := e.namedAuto(n.Sym.Name+"."+st.FieldName(i), ft, n.Pos)
|
||||
return ssa.LocalSlot{N: x, Type: ft, Off: 0}
|
||||
}
|
||||
return ssa.LocalSlot{N: n, Type: ft, Off: name.Off + st.FieldOff(i)}
|
||||
}
|
||||
@@ -5010,7 +4984,8 @@ func (e *ssafn) SplitArray(name ssa.LocalSlot) ssa.LocalSlot {
|
||||
}
|
||||
et := at.ElemType()
|
||||
if n.Class() == PAUTO && !n.Addrtaken() {
|
||||
return e.splitSlot(&name, "[0]", 0, et)
|
||||
x := e.namedAuto(n.Sym.Name+"[0]", et, n.Pos)
|
||||
return ssa.LocalSlot{N: x, Type: et, Off: 0}
|
||||
}
|
||||
return ssa.LocalSlot{N: n, Type: et, Off: name.Off}
|
||||
}
|
||||
@@ -5019,14 +4994,16 @@ func (e *ssafn) DerefItab(it *obj.LSym, offset int64) *obj.LSym {
|
||||
return itabsym(it, offset)
|
||||
}
|
||||
|
||||
// splitSlot returns a slot representing the data of parent starting at offset.
|
||||
func (e *ssafn) splitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t *types.Type) ssa.LocalSlot {
|
||||
s := &types.Sym{Name: parent.N.(*Node).Sym.Name + suffix, Pkg: localpkg}
|
||||
// namedAuto returns a new AUTO variable with the given name and type.
|
||||
// These are exposed to the debugger.
|
||||
func (e *ssafn) namedAuto(name string, typ *types.Type, pos src.XPos) ssa.GCNode {
|
||||
t := typ
|
||||
s := &types.Sym{Name: name, Pkg: localpkg}
|
||||
|
||||
n := new(Node)
|
||||
n.Name = new(Name)
|
||||
n.Op = ONAME
|
||||
n.Pos = parent.N.(*Node).Pos
|
||||
n.Pos = pos
|
||||
n.Orig = n
|
||||
|
||||
s.Def = asTypesNode(n)
|
||||
@@ -5039,7 +5016,7 @@ func (e *ssafn) splitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t
|
||||
n.Name.Curfn = e.curfn
|
||||
e.curfn.Func.Dcl = append(e.curfn.Func.Dcl, n)
|
||||
dowidth(t)
|
||||
return ssa.LocalSlot{N: n, Type: t, Off: 0, SplitOf: parent, SplitOffset: offset}
|
||||
return n
|
||||
}
|
||||
|
||||
func (e *ssafn) CanSSA(t *types.Type) bool {
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
package gc
|
||||
|
||||
import (
|
||||
"cmd/compile/internal/ssa"
|
||||
"cmd/compile/internal/syntax"
|
||||
"cmd/compile/internal/types"
|
||||
"cmd/internal/obj"
|
||||
@@ -370,7 +369,6 @@ type Func struct {
|
||||
Closgen int
|
||||
Outerfunc *Node // outer function (for closure)
|
||||
FieldTrack map[*types.Sym]struct{}
|
||||
DebugInfo *ssa.FuncDebug
|
||||
Ntype *Node // signature
|
||||
Top int // top context (Ecall, Eproc, etc)
|
||||
Closure *Node // OCLOSURE <-> ODCLFUNC
|
||||
|
||||
680
src/cmd/compile/internal/gc/testdata/arithConst.go
vendored
680
src/cmd/compile/internal/gc/testdata/arithConst.go
vendored
@@ -35,6 +35,16 @@ func add_4294967296_uint64_ssa(a uint64) uint64 {
|
||||
return 4294967296 + a
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func add_uint64_9223372036854775808_ssa(a uint64) uint64 {
|
||||
return a + 9223372036854775808
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func add_9223372036854775808_uint64_ssa(a uint64) uint64 {
|
||||
return 9223372036854775808 + a
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func add_uint64_18446744073709551615_ssa(a uint64) uint64 {
|
||||
return a + 18446744073709551615
|
||||
@@ -75,6 +85,16 @@ func sub_4294967296_uint64_ssa(a uint64) uint64 {
|
||||
return 4294967296 - a
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func sub_uint64_9223372036854775808_ssa(a uint64) uint64 {
|
||||
return a - 9223372036854775808
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func sub_9223372036854775808_uint64_ssa(a uint64) uint64 {
|
||||
return 9223372036854775808 - a
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func sub_uint64_18446744073709551615_ssa(a uint64) uint64 {
|
||||
return a - 18446744073709551615
|
||||
@@ -110,6 +130,16 @@ func div_4294967296_uint64_ssa(a uint64) uint64 {
|
||||
return 4294967296 / a
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func div_uint64_9223372036854775808_ssa(a uint64) uint64 {
|
||||
return a / 9223372036854775808
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func div_9223372036854775808_uint64_ssa(a uint64) uint64 {
|
||||
return 9223372036854775808 / a
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func div_uint64_18446744073709551615_ssa(a uint64) uint64 {
|
||||
return a / 18446744073709551615
|
||||
@@ -150,6 +180,16 @@ func mul_4294967296_uint64_ssa(a uint64) uint64 {
|
||||
return 4294967296 * a
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func mul_uint64_9223372036854775808_ssa(a uint64) uint64 {
|
||||
return a * 9223372036854775808
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func mul_9223372036854775808_uint64_ssa(a uint64) uint64 {
|
||||
return 9223372036854775808 * a
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func mul_uint64_18446744073709551615_ssa(a uint64) uint64 {
|
||||
return a * 18446744073709551615
|
||||
@@ -190,6 +230,16 @@ func lsh_4294967296_uint64_ssa(a uint64) uint64 {
|
||||
return 4294967296 << a
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func lsh_uint64_9223372036854775808_ssa(a uint64) uint64 {
|
||||
return a << uint64(9223372036854775808)
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func lsh_9223372036854775808_uint64_ssa(a uint64) uint64 {
|
||||
return 9223372036854775808 << a
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func lsh_uint64_18446744073709551615_ssa(a uint64) uint64 {
|
||||
return a << uint64(18446744073709551615)
|
||||
@@ -230,6 +280,16 @@ func rsh_4294967296_uint64_ssa(a uint64) uint64 {
|
||||
return 4294967296 >> a
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func rsh_uint64_9223372036854775808_ssa(a uint64) uint64 {
|
||||
return a >> uint64(9223372036854775808)
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func rsh_9223372036854775808_uint64_ssa(a uint64) uint64 {
|
||||
return 9223372036854775808 >> a
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func rsh_uint64_18446744073709551615_ssa(a uint64) uint64 {
|
||||
return a >> uint64(18446744073709551615)
|
||||
@@ -265,6 +325,16 @@ func mod_4294967296_uint64_ssa(a uint64) uint64 {
|
||||
return 4294967296 % a
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func mod_uint64_9223372036854775808_ssa(a uint64) uint64 {
|
||||
return a % 9223372036854775808
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func mod_9223372036854775808_uint64_ssa(a uint64) uint64 {
|
||||
return 9223372036854775808 % a
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func mod_uint64_18446744073709551615_ssa(a uint64) uint64 {
|
||||
return a % 18446744073709551615
|
||||
@@ -2319,6 +2389,16 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := add_0_uint64_ssa(9223372036854775808); got != 9223372036854775808 {
|
||||
fmt.Printf("add_uint64 0%s9223372036854775808 = %d, wanted 9223372036854775808\n", `+`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := add_uint64_0_ssa(9223372036854775808); got != 9223372036854775808 {
|
||||
fmt.Printf("add_uint64 9223372036854775808%s0 = %d, wanted 9223372036854775808\n", `+`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := add_0_uint64_ssa(18446744073709551615); got != 18446744073709551615 {
|
||||
fmt.Printf("add_uint64 0%s18446744073709551615 = %d, wanted 18446744073709551615\n", `+`, got)
|
||||
failed = true
|
||||
@@ -2359,6 +2439,16 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := add_1_uint64_ssa(9223372036854775808); got != 9223372036854775809 {
|
||||
fmt.Printf("add_uint64 1%s9223372036854775808 = %d, wanted 9223372036854775809\n", `+`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := add_uint64_1_ssa(9223372036854775808); got != 9223372036854775809 {
|
||||
fmt.Printf("add_uint64 9223372036854775808%s1 = %d, wanted 9223372036854775809\n", `+`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := add_1_uint64_ssa(18446744073709551615); got != 0 {
|
||||
fmt.Printf("add_uint64 1%s18446744073709551615 = %d, wanted 0\n", `+`, got)
|
||||
failed = true
|
||||
@@ -2399,6 +2489,16 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := add_4294967296_uint64_ssa(9223372036854775808); got != 9223372041149743104 {
|
||||
fmt.Printf("add_uint64 4294967296%s9223372036854775808 = %d, wanted 9223372041149743104\n", `+`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := add_uint64_4294967296_ssa(9223372036854775808); got != 9223372041149743104 {
|
||||
fmt.Printf("add_uint64 9223372036854775808%s4294967296 = %d, wanted 9223372041149743104\n", `+`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := add_4294967296_uint64_ssa(18446744073709551615); got != 4294967295 {
|
||||
fmt.Printf("add_uint64 4294967296%s18446744073709551615 = %d, wanted 4294967295\n", `+`, got)
|
||||
failed = true
|
||||
@@ -2409,6 +2509,56 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := add_9223372036854775808_uint64_ssa(0); got != 9223372036854775808 {
|
||||
fmt.Printf("add_uint64 9223372036854775808%s0 = %d, wanted 9223372036854775808\n", `+`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := add_uint64_9223372036854775808_ssa(0); got != 9223372036854775808 {
|
||||
fmt.Printf("add_uint64 0%s9223372036854775808 = %d, wanted 9223372036854775808\n", `+`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := add_9223372036854775808_uint64_ssa(1); got != 9223372036854775809 {
|
||||
fmt.Printf("add_uint64 9223372036854775808%s1 = %d, wanted 9223372036854775809\n", `+`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := add_uint64_9223372036854775808_ssa(1); got != 9223372036854775809 {
|
||||
fmt.Printf("add_uint64 1%s9223372036854775808 = %d, wanted 9223372036854775809\n", `+`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := add_9223372036854775808_uint64_ssa(4294967296); got != 9223372041149743104 {
|
||||
fmt.Printf("add_uint64 9223372036854775808%s4294967296 = %d, wanted 9223372041149743104\n", `+`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := add_uint64_9223372036854775808_ssa(4294967296); got != 9223372041149743104 {
|
||||
fmt.Printf("add_uint64 4294967296%s9223372036854775808 = %d, wanted 9223372041149743104\n", `+`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := add_9223372036854775808_uint64_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("add_uint64 9223372036854775808%s9223372036854775808 = %d, wanted 0\n", `+`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := add_uint64_9223372036854775808_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("add_uint64 9223372036854775808%s9223372036854775808 = %d, wanted 0\n", `+`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := add_9223372036854775808_uint64_ssa(18446744073709551615); got != 9223372036854775807 {
|
||||
fmt.Printf("add_uint64 9223372036854775808%s18446744073709551615 = %d, wanted 9223372036854775807\n", `+`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := add_uint64_9223372036854775808_ssa(18446744073709551615); got != 9223372036854775807 {
|
||||
fmt.Printf("add_uint64 18446744073709551615%s9223372036854775808 = %d, wanted 9223372036854775807\n", `+`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := add_18446744073709551615_uint64_ssa(0); got != 18446744073709551615 {
|
||||
fmt.Printf("add_uint64 18446744073709551615%s0 = %d, wanted 18446744073709551615\n", `+`, got)
|
||||
failed = true
|
||||
@@ -2439,6 +2589,16 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := add_18446744073709551615_uint64_ssa(9223372036854775808); got != 9223372036854775807 {
|
||||
fmt.Printf("add_uint64 18446744073709551615%s9223372036854775808 = %d, wanted 9223372036854775807\n", `+`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := add_uint64_18446744073709551615_ssa(9223372036854775808); got != 9223372036854775807 {
|
||||
fmt.Printf("add_uint64 9223372036854775808%s18446744073709551615 = %d, wanted 9223372036854775807\n", `+`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := add_18446744073709551615_uint64_ssa(18446744073709551615); got != 18446744073709551614 {
|
||||
fmt.Printf("add_uint64 18446744073709551615%s18446744073709551615 = %d, wanted 18446744073709551614\n", `+`, got)
|
||||
failed = true
|
||||
@@ -2479,6 +2639,16 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := sub_0_uint64_ssa(9223372036854775808); got != 9223372036854775808 {
|
||||
fmt.Printf("sub_uint64 0%s9223372036854775808 = %d, wanted 9223372036854775808\n", `-`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := sub_uint64_0_ssa(9223372036854775808); got != 9223372036854775808 {
|
||||
fmt.Printf("sub_uint64 9223372036854775808%s0 = %d, wanted 9223372036854775808\n", `-`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := sub_0_uint64_ssa(18446744073709551615); got != 1 {
|
||||
fmt.Printf("sub_uint64 0%s18446744073709551615 = %d, wanted 1\n", `-`, got)
|
||||
failed = true
|
||||
@@ -2519,6 +2689,16 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := sub_1_uint64_ssa(9223372036854775808); got != 9223372036854775809 {
|
||||
fmt.Printf("sub_uint64 1%s9223372036854775808 = %d, wanted 9223372036854775809\n", `-`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := sub_uint64_1_ssa(9223372036854775808); got != 9223372036854775807 {
|
||||
fmt.Printf("sub_uint64 9223372036854775808%s1 = %d, wanted 9223372036854775807\n", `-`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := sub_1_uint64_ssa(18446744073709551615); got != 2 {
|
||||
fmt.Printf("sub_uint64 1%s18446744073709551615 = %d, wanted 2\n", `-`, got)
|
||||
failed = true
|
||||
@@ -2559,6 +2739,16 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := sub_4294967296_uint64_ssa(9223372036854775808); got != 9223372041149743104 {
|
||||
fmt.Printf("sub_uint64 4294967296%s9223372036854775808 = %d, wanted 9223372041149743104\n", `-`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := sub_uint64_4294967296_ssa(9223372036854775808); got != 9223372032559808512 {
|
||||
fmt.Printf("sub_uint64 9223372036854775808%s4294967296 = %d, wanted 9223372032559808512\n", `-`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := sub_4294967296_uint64_ssa(18446744073709551615); got != 4294967297 {
|
||||
fmt.Printf("sub_uint64 4294967296%s18446744073709551615 = %d, wanted 4294967297\n", `-`, got)
|
||||
failed = true
|
||||
@@ -2569,6 +2759,56 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := sub_9223372036854775808_uint64_ssa(0); got != 9223372036854775808 {
|
||||
fmt.Printf("sub_uint64 9223372036854775808%s0 = %d, wanted 9223372036854775808\n", `-`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := sub_uint64_9223372036854775808_ssa(0); got != 9223372036854775808 {
|
||||
fmt.Printf("sub_uint64 0%s9223372036854775808 = %d, wanted 9223372036854775808\n", `-`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := sub_9223372036854775808_uint64_ssa(1); got != 9223372036854775807 {
|
||||
fmt.Printf("sub_uint64 9223372036854775808%s1 = %d, wanted 9223372036854775807\n", `-`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := sub_uint64_9223372036854775808_ssa(1); got != 9223372036854775809 {
|
||||
fmt.Printf("sub_uint64 1%s9223372036854775808 = %d, wanted 9223372036854775809\n", `-`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := sub_9223372036854775808_uint64_ssa(4294967296); got != 9223372032559808512 {
|
||||
fmt.Printf("sub_uint64 9223372036854775808%s4294967296 = %d, wanted 9223372032559808512\n", `-`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := sub_uint64_9223372036854775808_ssa(4294967296); got != 9223372041149743104 {
|
||||
fmt.Printf("sub_uint64 4294967296%s9223372036854775808 = %d, wanted 9223372041149743104\n", `-`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := sub_9223372036854775808_uint64_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("sub_uint64 9223372036854775808%s9223372036854775808 = %d, wanted 0\n", `-`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := sub_uint64_9223372036854775808_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("sub_uint64 9223372036854775808%s9223372036854775808 = %d, wanted 0\n", `-`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := sub_9223372036854775808_uint64_ssa(18446744073709551615); got != 9223372036854775809 {
|
||||
fmt.Printf("sub_uint64 9223372036854775808%s18446744073709551615 = %d, wanted 9223372036854775809\n", `-`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := sub_uint64_9223372036854775808_ssa(18446744073709551615); got != 9223372036854775807 {
|
||||
fmt.Printf("sub_uint64 18446744073709551615%s9223372036854775808 = %d, wanted 9223372036854775807\n", `-`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := sub_18446744073709551615_uint64_ssa(0); got != 18446744073709551615 {
|
||||
fmt.Printf("sub_uint64 18446744073709551615%s0 = %d, wanted 18446744073709551615\n", `-`, got)
|
||||
failed = true
|
||||
@@ -2599,6 +2839,16 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := sub_18446744073709551615_uint64_ssa(9223372036854775808); got != 9223372036854775807 {
|
||||
fmt.Printf("sub_uint64 18446744073709551615%s9223372036854775808 = %d, wanted 9223372036854775807\n", `-`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := sub_uint64_18446744073709551615_ssa(9223372036854775808); got != 9223372036854775809 {
|
||||
fmt.Printf("sub_uint64 9223372036854775808%s18446744073709551615 = %d, wanted 9223372036854775809\n", `-`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := sub_18446744073709551615_uint64_ssa(18446744073709551615); got != 0 {
|
||||
fmt.Printf("sub_uint64 18446744073709551615%s18446744073709551615 = %d, wanted 0\n", `-`, got)
|
||||
failed = true
|
||||
@@ -2619,6 +2869,11 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := div_0_uint64_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("div_uint64 0%s9223372036854775808 = %d, wanted 0\n", `/`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := div_0_uint64_ssa(18446744073709551615); got != 0 {
|
||||
fmt.Printf("div_uint64 0%s18446744073709551615 = %d, wanted 0\n", `/`, got)
|
||||
failed = true
|
||||
@@ -2649,6 +2904,16 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := div_1_uint64_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("div_uint64 1%s9223372036854775808 = %d, wanted 0\n", `/`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := div_uint64_1_ssa(9223372036854775808); got != 9223372036854775808 {
|
||||
fmt.Printf("div_uint64 9223372036854775808%s1 = %d, wanted 9223372036854775808\n", `/`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := div_1_uint64_ssa(18446744073709551615); got != 0 {
|
||||
fmt.Printf("div_uint64 1%s18446744073709551615 = %d, wanted 0\n", `/`, got)
|
||||
failed = true
|
||||
@@ -2684,6 +2949,16 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := div_4294967296_uint64_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("div_uint64 4294967296%s9223372036854775808 = %d, wanted 0\n", `/`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := div_uint64_4294967296_ssa(9223372036854775808); got != 2147483648 {
|
||||
fmt.Printf("div_uint64 9223372036854775808%s4294967296 = %d, wanted 2147483648\n", `/`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := div_4294967296_uint64_ssa(18446744073709551615); got != 0 {
|
||||
fmt.Printf("div_uint64 4294967296%s18446744073709551615 = %d, wanted 0\n", `/`, got)
|
||||
failed = true
|
||||
@@ -2694,6 +2969,51 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := div_uint64_9223372036854775808_ssa(0); got != 0 {
|
||||
fmt.Printf("div_uint64 0%s9223372036854775808 = %d, wanted 0\n", `/`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := div_9223372036854775808_uint64_ssa(1); got != 9223372036854775808 {
|
||||
fmt.Printf("div_uint64 9223372036854775808%s1 = %d, wanted 9223372036854775808\n", `/`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := div_uint64_9223372036854775808_ssa(1); got != 0 {
|
||||
fmt.Printf("div_uint64 1%s9223372036854775808 = %d, wanted 0\n", `/`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := div_9223372036854775808_uint64_ssa(4294967296); got != 2147483648 {
|
||||
fmt.Printf("div_uint64 9223372036854775808%s4294967296 = %d, wanted 2147483648\n", `/`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := div_uint64_9223372036854775808_ssa(4294967296); got != 0 {
|
||||
fmt.Printf("div_uint64 4294967296%s9223372036854775808 = %d, wanted 0\n", `/`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := div_9223372036854775808_uint64_ssa(9223372036854775808); got != 1 {
|
||||
fmt.Printf("div_uint64 9223372036854775808%s9223372036854775808 = %d, wanted 1\n", `/`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := div_uint64_9223372036854775808_ssa(9223372036854775808); got != 1 {
|
||||
fmt.Printf("div_uint64 9223372036854775808%s9223372036854775808 = %d, wanted 1\n", `/`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := div_9223372036854775808_uint64_ssa(18446744073709551615); got != 0 {
|
||||
fmt.Printf("div_uint64 9223372036854775808%s18446744073709551615 = %d, wanted 0\n", `/`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := div_uint64_9223372036854775808_ssa(18446744073709551615); got != 1 {
|
||||
fmt.Printf("div_uint64 18446744073709551615%s9223372036854775808 = %d, wanted 1\n", `/`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := div_uint64_18446744073709551615_ssa(0); got != 0 {
|
||||
fmt.Printf("div_uint64 0%s18446744073709551615 = %d, wanted 0\n", `/`, got)
|
||||
failed = true
|
||||
@@ -2719,6 +3039,16 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := div_18446744073709551615_uint64_ssa(9223372036854775808); got != 1 {
|
||||
fmt.Printf("div_uint64 18446744073709551615%s9223372036854775808 = %d, wanted 1\n", `/`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := div_uint64_18446744073709551615_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("div_uint64 9223372036854775808%s18446744073709551615 = %d, wanted 0\n", `/`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := div_18446744073709551615_uint64_ssa(18446744073709551615); got != 1 {
|
||||
fmt.Printf("div_uint64 18446744073709551615%s18446744073709551615 = %d, wanted 1\n", `/`, got)
|
||||
failed = true
|
||||
@@ -2759,6 +3089,16 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mul_0_uint64_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("mul_uint64 0%s9223372036854775808 = %d, wanted 0\n", `*`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mul_uint64_0_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("mul_uint64 9223372036854775808%s0 = %d, wanted 0\n", `*`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mul_0_uint64_ssa(18446744073709551615); got != 0 {
|
||||
fmt.Printf("mul_uint64 0%s18446744073709551615 = %d, wanted 0\n", `*`, got)
|
||||
failed = true
|
||||
@@ -2799,6 +3139,16 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mul_1_uint64_ssa(9223372036854775808); got != 9223372036854775808 {
|
||||
fmt.Printf("mul_uint64 1%s9223372036854775808 = %d, wanted 9223372036854775808\n", `*`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mul_uint64_1_ssa(9223372036854775808); got != 9223372036854775808 {
|
||||
fmt.Printf("mul_uint64 9223372036854775808%s1 = %d, wanted 9223372036854775808\n", `*`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mul_1_uint64_ssa(18446744073709551615); got != 18446744073709551615 {
|
||||
fmt.Printf("mul_uint64 1%s18446744073709551615 = %d, wanted 18446744073709551615\n", `*`, got)
|
||||
failed = true
|
||||
@@ -2839,6 +3189,16 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mul_4294967296_uint64_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("mul_uint64 4294967296%s9223372036854775808 = %d, wanted 0\n", `*`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mul_uint64_4294967296_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("mul_uint64 9223372036854775808%s4294967296 = %d, wanted 0\n", `*`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mul_4294967296_uint64_ssa(18446744073709551615); got != 18446744069414584320 {
|
||||
fmt.Printf("mul_uint64 4294967296%s18446744073709551615 = %d, wanted 18446744069414584320\n", `*`, got)
|
||||
failed = true
|
||||
@@ -2849,6 +3209,56 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mul_9223372036854775808_uint64_ssa(0); got != 0 {
|
||||
fmt.Printf("mul_uint64 9223372036854775808%s0 = %d, wanted 0\n", `*`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mul_uint64_9223372036854775808_ssa(0); got != 0 {
|
||||
fmt.Printf("mul_uint64 0%s9223372036854775808 = %d, wanted 0\n", `*`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mul_9223372036854775808_uint64_ssa(1); got != 9223372036854775808 {
|
||||
fmt.Printf("mul_uint64 9223372036854775808%s1 = %d, wanted 9223372036854775808\n", `*`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mul_uint64_9223372036854775808_ssa(1); got != 9223372036854775808 {
|
||||
fmt.Printf("mul_uint64 1%s9223372036854775808 = %d, wanted 9223372036854775808\n", `*`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mul_9223372036854775808_uint64_ssa(4294967296); got != 0 {
|
||||
fmt.Printf("mul_uint64 9223372036854775808%s4294967296 = %d, wanted 0\n", `*`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mul_uint64_9223372036854775808_ssa(4294967296); got != 0 {
|
||||
fmt.Printf("mul_uint64 4294967296%s9223372036854775808 = %d, wanted 0\n", `*`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mul_9223372036854775808_uint64_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("mul_uint64 9223372036854775808%s9223372036854775808 = %d, wanted 0\n", `*`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mul_uint64_9223372036854775808_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("mul_uint64 9223372036854775808%s9223372036854775808 = %d, wanted 0\n", `*`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mul_9223372036854775808_uint64_ssa(18446744073709551615); got != 9223372036854775808 {
|
||||
fmt.Printf("mul_uint64 9223372036854775808%s18446744073709551615 = %d, wanted 9223372036854775808\n", `*`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mul_uint64_9223372036854775808_ssa(18446744073709551615); got != 9223372036854775808 {
|
||||
fmt.Printf("mul_uint64 18446744073709551615%s9223372036854775808 = %d, wanted 9223372036854775808\n", `*`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mul_18446744073709551615_uint64_ssa(0); got != 0 {
|
||||
fmt.Printf("mul_uint64 18446744073709551615%s0 = %d, wanted 0\n", `*`, got)
|
||||
failed = true
|
||||
@@ -2879,6 +3289,16 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mul_18446744073709551615_uint64_ssa(9223372036854775808); got != 9223372036854775808 {
|
||||
fmt.Printf("mul_uint64 18446744073709551615%s9223372036854775808 = %d, wanted 9223372036854775808\n", `*`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mul_uint64_18446744073709551615_ssa(9223372036854775808); got != 9223372036854775808 {
|
||||
fmt.Printf("mul_uint64 9223372036854775808%s18446744073709551615 = %d, wanted 9223372036854775808\n", `*`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mul_18446744073709551615_uint64_ssa(18446744073709551615); got != 1 {
|
||||
fmt.Printf("mul_uint64 18446744073709551615%s18446744073709551615 = %d, wanted 1\n", `*`, got)
|
||||
failed = true
|
||||
@@ -2919,6 +3339,16 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := lsh_0_uint64_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("lsh_uint64 0%s9223372036854775808 = %d, wanted 0\n", `<<`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := lsh_uint64_0_ssa(9223372036854775808); got != 9223372036854775808 {
|
||||
fmt.Printf("lsh_uint64 9223372036854775808%s0 = %d, wanted 9223372036854775808\n", `<<`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := lsh_0_uint64_ssa(18446744073709551615); got != 0 {
|
||||
fmt.Printf("lsh_uint64 0%s18446744073709551615 = %d, wanted 0\n", `<<`, got)
|
||||
failed = true
|
||||
@@ -2959,6 +3389,16 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := lsh_1_uint64_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("lsh_uint64 1%s9223372036854775808 = %d, wanted 0\n", `<<`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := lsh_uint64_1_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("lsh_uint64 9223372036854775808%s1 = %d, wanted 0\n", `<<`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := lsh_1_uint64_ssa(18446744073709551615); got != 0 {
|
||||
fmt.Printf("lsh_uint64 1%s18446744073709551615 = %d, wanted 0\n", `<<`, got)
|
||||
failed = true
|
||||
@@ -2999,6 +3439,16 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := lsh_4294967296_uint64_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("lsh_uint64 4294967296%s9223372036854775808 = %d, wanted 0\n", `<<`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := lsh_uint64_4294967296_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("lsh_uint64 9223372036854775808%s4294967296 = %d, wanted 0\n", `<<`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := lsh_4294967296_uint64_ssa(18446744073709551615); got != 0 {
|
||||
fmt.Printf("lsh_uint64 4294967296%s18446744073709551615 = %d, wanted 0\n", `<<`, got)
|
||||
failed = true
|
||||
@@ -3009,6 +3459,56 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := lsh_9223372036854775808_uint64_ssa(0); got != 9223372036854775808 {
|
||||
fmt.Printf("lsh_uint64 9223372036854775808%s0 = %d, wanted 9223372036854775808\n", `<<`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := lsh_uint64_9223372036854775808_ssa(0); got != 0 {
|
||||
fmt.Printf("lsh_uint64 0%s9223372036854775808 = %d, wanted 0\n", `<<`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := lsh_9223372036854775808_uint64_ssa(1); got != 0 {
|
||||
fmt.Printf("lsh_uint64 9223372036854775808%s1 = %d, wanted 0\n", `<<`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := lsh_uint64_9223372036854775808_ssa(1); got != 0 {
|
||||
fmt.Printf("lsh_uint64 1%s9223372036854775808 = %d, wanted 0\n", `<<`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := lsh_9223372036854775808_uint64_ssa(4294967296); got != 0 {
|
||||
fmt.Printf("lsh_uint64 9223372036854775808%s4294967296 = %d, wanted 0\n", `<<`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := lsh_uint64_9223372036854775808_ssa(4294967296); got != 0 {
|
||||
fmt.Printf("lsh_uint64 4294967296%s9223372036854775808 = %d, wanted 0\n", `<<`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := lsh_9223372036854775808_uint64_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("lsh_uint64 9223372036854775808%s9223372036854775808 = %d, wanted 0\n", `<<`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := lsh_uint64_9223372036854775808_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("lsh_uint64 9223372036854775808%s9223372036854775808 = %d, wanted 0\n", `<<`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := lsh_9223372036854775808_uint64_ssa(18446744073709551615); got != 0 {
|
||||
fmt.Printf("lsh_uint64 9223372036854775808%s18446744073709551615 = %d, wanted 0\n", `<<`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := lsh_uint64_9223372036854775808_ssa(18446744073709551615); got != 0 {
|
||||
fmt.Printf("lsh_uint64 18446744073709551615%s9223372036854775808 = %d, wanted 0\n", `<<`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := lsh_18446744073709551615_uint64_ssa(0); got != 18446744073709551615 {
|
||||
fmt.Printf("lsh_uint64 18446744073709551615%s0 = %d, wanted 18446744073709551615\n", `<<`, got)
|
||||
failed = true
|
||||
@@ -3039,6 +3539,16 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := lsh_18446744073709551615_uint64_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("lsh_uint64 18446744073709551615%s9223372036854775808 = %d, wanted 0\n", `<<`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := lsh_uint64_18446744073709551615_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("lsh_uint64 9223372036854775808%s18446744073709551615 = %d, wanted 0\n", `<<`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := lsh_18446744073709551615_uint64_ssa(18446744073709551615); got != 0 {
|
||||
fmt.Printf("lsh_uint64 18446744073709551615%s18446744073709551615 = %d, wanted 0\n", `<<`, got)
|
||||
failed = true
|
||||
@@ -3079,6 +3589,16 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := rsh_0_uint64_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("rsh_uint64 0%s9223372036854775808 = %d, wanted 0\n", `>>`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := rsh_uint64_0_ssa(9223372036854775808); got != 9223372036854775808 {
|
||||
fmt.Printf("rsh_uint64 9223372036854775808%s0 = %d, wanted 9223372036854775808\n", `>>`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := rsh_0_uint64_ssa(18446744073709551615); got != 0 {
|
||||
fmt.Printf("rsh_uint64 0%s18446744073709551615 = %d, wanted 0\n", `>>`, got)
|
||||
failed = true
|
||||
@@ -3119,6 +3639,16 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := rsh_1_uint64_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("rsh_uint64 1%s9223372036854775808 = %d, wanted 0\n", `>>`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := rsh_uint64_1_ssa(9223372036854775808); got != 4611686018427387904 {
|
||||
fmt.Printf("rsh_uint64 9223372036854775808%s1 = %d, wanted 4611686018427387904\n", `>>`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := rsh_1_uint64_ssa(18446744073709551615); got != 0 {
|
||||
fmt.Printf("rsh_uint64 1%s18446744073709551615 = %d, wanted 0\n", `>>`, got)
|
||||
failed = true
|
||||
@@ -3159,6 +3689,16 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := rsh_4294967296_uint64_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("rsh_uint64 4294967296%s9223372036854775808 = %d, wanted 0\n", `>>`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := rsh_uint64_4294967296_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("rsh_uint64 9223372036854775808%s4294967296 = %d, wanted 0\n", `>>`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := rsh_4294967296_uint64_ssa(18446744073709551615); got != 0 {
|
||||
fmt.Printf("rsh_uint64 4294967296%s18446744073709551615 = %d, wanted 0\n", `>>`, got)
|
||||
failed = true
|
||||
@@ -3169,6 +3709,56 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := rsh_9223372036854775808_uint64_ssa(0); got != 9223372036854775808 {
|
||||
fmt.Printf("rsh_uint64 9223372036854775808%s0 = %d, wanted 9223372036854775808\n", `>>`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := rsh_uint64_9223372036854775808_ssa(0); got != 0 {
|
||||
fmt.Printf("rsh_uint64 0%s9223372036854775808 = %d, wanted 0\n", `>>`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := rsh_9223372036854775808_uint64_ssa(1); got != 4611686018427387904 {
|
||||
fmt.Printf("rsh_uint64 9223372036854775808%s1 = %d, wanted 4611686018427387904\n", `>>`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := rsh_uint64_9223372036854775808_ssa(1); got != 0 {
|
||||
fmt.Printf("rsh_uint64 1%s9223372036854775808 = %d, wanted 0\n", `>>`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := rsh_9223372036854775808_uint64_ssa(4294967296); got != 0 {
|
||||
fmt.Printf("rsh_uint64 9223372036854775808%s4294967296 = %d, wanted 0\n", `>>`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := rsh_uint64_9223372036854775808_ssa(4294967296); got != 0 {
|
||||
fmt.Printf("rsh_uint64 4294967296%s9223372036854775808 = %d, wanted 0\n", `>>`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := rsh_9223372036854775808_uint64_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("rsh_uint64 9223372036854775808%s9223372036854775808 = %d, wanted 0\n", `>>`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := rsh_uint64_9223372036854775808_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("rsh_uint64 9223372036854775808%s9223372036854775808 = %d, wanted 0\n", `>>`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := rsh_9223372036854775808_uint64_ssa(18446744073709551615); got != 0 {
|
||||
fmt.Printf("rsh_uint64 9223372036854775808%s18446744073709551615 = %d, wanted 0\n", `>>`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := rsh_uint64_9223372036854775808_ssa(18446744073709551615); got != 0 {
|
||||
fmt.Printf("rsh_uint64 18446744073709551615%s9223372036854775808 = %d, wanted 0\n", `>>`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := rsh_18446744073709551615_uint64_ssa(0); got != 18446744073709551615 {
|
||||
fmt.Printf("rsh_uint64 18446744073709551615%s0 = %d, wanted 18446744073709551615\n", `>>`, got)
|
||||
failed = true
|
||||
@@ -3199,6 +3789,16 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := rsh_18446744073709551615_uint64_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("rsh_uint64 18446744073709551615%s9223372036854775808 = %d, wanted 0\n", `>>`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := rsh_uint64_18446744073709551615_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("rsh_uint64 9223372036854775808%s18446744073709551615 = %d, wanted 0\n", `>>`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := rsh_18446744073709551615_uint64_ssa(18446744073709551615); got != 0 {
|
||||
fmt.Printf("rsh_uint64 18446744073709551615%s18446744073709551615 = %d, wanted 0\n", `>>`, got)
|
||||
failed = true
|
||||
@@ -3219,6 +3819,11 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mod_0_uint64_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("mod_uint64 0%s9223372036854775808 = %d, wanted 0\n", `%`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mod_0_uint64_ssa(18446744073709551615); got != 0 {
|
||||
fmt.Printf("mod_uint64 0%s18446744073709551615 = %d, wanted 0\n", `%`, got)
|
||||
failed = true
|
||||
@@ -3249,6 +3854,16 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mod_1_uint64_ssa(9223372036854775808); got != 1 {
|
||||
fmt.Printf("mod_uint64 1%s9223372036854775808 = %d, wanted 1\n", `%`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mod_uint64_1_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("mod_uint64 9223372036854775808%s1 = %d, wanted 0\n", `%`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mod_1_uint64_ssa(18446744073709551615); got != 1 {
|
||||
fmt.Printf("mod_uint64 1%s18446744073709551615 = %d, wanted 1\n", `%`, got)
|
||||
failed = true
|
||||
@@ -3284,6 +3899,16 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mod_4294967296_uint64_ssa(9223372036854775808); got != 4294967296 {
|
||||
fmt.Printf("mod_uint64 4294967296%s9223372036854775808 = %d, wanted 4294967296\n", `%`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mod_uint64_4294967296_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("mod_uint64 9223372036854775808%s4294967296 = %d, wanted 0\n", `%`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mod_4294967296_uint64_ssa(18446744073709551615); got != 4294967296 {
|
||||
fmt.Printf("mod_uint64 4294967296%s18446744073709551615 = %d, wanted 4294967296\n", `%`, got)
|
||||
failed = true
|
||||
@@ -3294,6 +3919,51 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mod_uint64_9223372036854775808_ssa(0); got != 0 {
|
||||
fmt.Printf("mod_uint64 0%s9223372036854775808 = %d, wanted 0\n", `%`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mod_9223372036854775808_uint64_ssa(1); got != 0 {
|
||||
fmt.Printf("mod_uint64 9223372036854775808%s1 = %d, wanted 0\n", `%`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mod_uint64_9223372036854775808_ssa(1); got != 1 {
|
||||
fmt.Printf("mod_uint64 1%s9223372036854775808 = %d, wanted 1\n", `%`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mod_9223372036854775808_uint64_ssa(4294967296); got != 0 {
|
||||
fmt.Printf("mod_uint64 9223372036854775808%s4294967296 = %d, wanted 0\n", `%`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mod_uint64_9223372036854775808_ssa(4294967296); got != 4294967296 {
|
||||
fmt.Printf("mod_uint64 4294967296%s9223372036854775808 = %d, wanted 4294967296\n", `%`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mod_9223372036854775808_uint64_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("mod_uint64 9223372036854775808%s9223372036854775808 = %d, wanted 0\n", `%`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mod_uint64_9223372036854775808_ssa(9223372036854775808); got != 0 {
|
||||
fmt.Printf("mod_uint64 9223372036854775808%s9223372036854775808 = %d, wanted 0\n", `%`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mod_9223372036854775808_uint64_ssa(18446744073709551615); got != 9223372036854775808 {
|
||||
fmt.Printf("mod_uint64 9223372036854775808%s18446744073709551615 = %d, wanted 9223372036854775808\n", `%`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mod_uint64_9223372036854775808_ssa(18446744073709551615); got != 9223372036854775807 {
|
||||
fmt.Printf("mod_uint64 18446744073709551615%s9223372036854775808 = %d, wanted 9223372036854775807\n", `%`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mod_uint64_18446744073709551615_ssa(0); got != 0 {
|
||||
fmt.Printf("mod_uint64 0%s18446744073709551615 = %d, wanted 0\n", `%`, got)
|
||||
failed = true
|
||||
@@ -3319,6 +3989,16 @@ func main() {
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mod_18446744073709551615_uint64_ssa(9223372036854775808); got != 9223372036854775807 {
|
||||
fmt.Printf("mod_uint64 18446744073709551615%s9223372036854775808 = %d, wanted 9223372036854775807\n", `%`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mod_uint64_18446744073709551615_ssa(9223372036854775808); got != 9223372036854775808 {
|
||||
fmt.Printf("mod_uint64 9223372036854775808%s18446744073709551615 = %d, wanted 9223372036854775808\n", `%`, got)
|
||||
failed = true
|
||||
}
|
||||
|
||||
if got := mod_18446744073709551615_uint64_ssa(18446744073709551615); got != 0 {
|
||||
fmt.Printf("mod_uint64 18446744073709551615%s18446744073709551615 = %d, wanted 0\n", `%`, got)
|
||||
failed = true
|
||||
|
||||
@@ -31,7 +31,7 @@ type szD struct {
|
||||
}
|
||||
|
||||
var szs = []szD{
|
||||
{name: "uint64", sn: "64", u: []uint64{0, 1, 4294967296, 0xffffFFFFffffFFFF}},
|
||||
{name: "uint64", sn: "64", u: []uint64{0, 1, 4294967296, 0x8000000000000000, 0xffffFFFFffffFFFF}},
|
||||
{name: "int64", sn: "64", i: []int64{-0x8000000000000000, -0x7FFFFFFFFFFFFFFF,
|
||||
-4294967296, -1, 0, 1, 4294967296, 0x7FFFFFFFFFFFFFFE, 0x7FFFFFFFFFFFFFFF}},
|
||||
|
||||
|
||||
@@ -273,6 +273,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
case ssa.OpMIPSMOVWaddr:
|
||||
p := s.Prog(mips.AMOVW)
|
||||
p.From.Type = obj.TYPE_ADDR
|
||||
p.From.Reg = v.Args[0].Reg()
|
||||
var wantreg string
|
||||
// MOVW $sym+off(base), R
|
||||
// the assembler expands it as the following:
|
||||
@@ -291,7 +292,6 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
case nil:
|
||||
// No sym, just MOVW $off(SP), R
|
||||
wantreg = "SP"
|
||||
p.From.Reg = mips.REGSP
|
||||
p.From.Offset = v.AuxInt
|
||||
}
|
||||
if reg := v.Args[0].RegName(); reg != wantreg {
|
||||
|
||||
@@ -247,6 +247,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
case ssa.OpMIPS64MOVVaddr:
|
||||
p := s.Prog(mips.AMOVV)
|
||||
p.From.Type = obj.TYPE_ADDR
|
||||
p.From.Reg = v.Args[0].Reg()
|
||||
var wantreg string
|
||||
// MOVV $sym+off(base), R
|
||||
// the assembler expands it as the following:
|
||||
@@ -265,7 +266,6 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
case nil:
|
||||
// No sym, just MOVV $off(SP), R
|
||||
wantreg = "SP"
|
||||
p.From.Reg = mips.REGSP
|
||||
p.From.Offset = v.AuxInt
|
||||
}
|
||||
if reg := v.Args[0].RegName(); reg != wantreg {
|
||||
|
||||
@@ -638,6 +638,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
case ssa.OpPPC64MOVDaddr:
|
||||
p := s.Prog(ppc64.AMOVD)
|
||||
p.From.Type = obj.TYPE_ADDR
|
||||
p.From.Reg = v.Args[0].Reg()
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = v.Reg()
|
||||
|
||||
@@ -660,7 +661,6 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
case nil:
|
||||
// No sym, just MOVD $off(SP), R
|
||||
wantreg = "SP"
|
||||
p.From.Reg = ppc64.REGSP
|
||||
p.From.Offset = v.AuxInt
|
||||
}
|
||||
if reg := v.Args[0].RegName(); reg != wantreg {
|
||||
|
||||
@@ -14,11 +14,6 @@ type Cache struct {
|
||||
blocks [200]Block
|
||||
locs [2000]Location
|
||||
|
||||
// Storage for DWARF variable locations. Lazily allocated
|
||||
// since location lists are off by default.
|
||||
varLocs []VarLoc
|
||||
curVarLoc int
|
||||
|
||||
// Reusable stackAllocState.
|
||||
// See stackalloc.go's {new,put}StackAllocState.
|
||||
stackAllocState *stackAllocState
|
||||
@@ -43,21 +38,4 @@ func (c *Cache) Reset() {
|
||||
for i := range xl {
|
||||
xl[i] = nil
|
||||
}
|
||||
xvl := c.varLocs[:c.curVarLoc]
|
||||
for i := range xvl {
|
||||
xvl[i] = VarLoc{}
|
||||
}
|
||||
c.curVarLoc = 0
|
||||
}
|
||||
|
||||
func (c *Cache) NewVarLoc() *VarLoc {
|
||||
if c.varLocs == nil {
|
||||
c.varLocs = make([]VarLoc, 4000)
|
||||
}
|
||||
if c.curVarLoc == len(c.varLocs) {
|
||||
return &VarLoc{}
|
||||
}
|
||||
vl := &c.varLocs[c.curVarLoc]
|
||||
c.curVarLoc++
|
||||
return vl
|
||||
}
|
||||
|
||||
@@ -1,559 +0,0 @@
|
||||
// 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 (
|
||||
"cmd/internal/obj"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type SlotID int32
|
||||
|
||||
// A FuncDebug contains all the debug information for the variables in a
|
||||
// function. Variables are identified by their LocalSlot, which may be the
|
||||
// result of decomposing a larger variable.
|
||||
type FuncDebug struct {
|
||||
Slots []*LocalSlot
|
||||
Variables []VarLocList
|
||||
Registers []Register
|
||||
}
|
||||
|
||||
// append adds a location to the location list for slot.
|
||||
func (f *FuncDebug) append(slot SlotID, loc *VarLoc) {
|
||||
f.Variables[slot].append(loc)
|
||||
}
|
||||
|
||||
// lastLoc returns the last VarLoc for slot, or nil if it has none.
|
||||
func (f *FuncDebug) lastLoc(slot SlotID) *VarLoc {
|
||||
return f.Variables[slot].last()
|
||||
}
|
||||
|
||||
func (f *FuncDebug) String() string {
|
||||
var vars []string
|
||||
for slot, list := range f.Variables {
|
||||
if len(list.Locations) == 0 {
|
||||
continue
|
||||
}
|
||||
vars = append(vars, fmt.Sprintf("%v = %v", f.Slots[slot], list))
|
||||
}
|
||||
return fmt.Sprintf("{%v}", strings.Join(vars, ", "))
|
||||
}
|
||||
|
||||
// A VarLocList contains the locations for a variable, in program text order.
|
||||
// It will often have gaps.
|
||||
type VarLocList struct {
|
||||
Locations []*VarLoc
|
||||
}
|
||||
|
||||
func (l *VarLocList) append(loc *VarLoc) {
|
||||
l.Locations = append(l.Locations, loc)
|
||||
}
|
||||
|
||||
// last returns the last location in the list.
|
||||
func (l *VarLocList) last() *VarLoc {
|
||||
if l == nil || len(l.Locations) == 0 {
|
||||
return nil
|
||||
}
|
||||
return l.Locations[len(l.Locations)-1]
|
||||
}
|
||||
|
||||
// A VarLoc describes a variable's location in a single contiguous range
|
||||
// of program text. It is generated from the SSA representation, but it
|
||||
// refers to the generated machine code, so the Values referenced are better
|
||||
// understood as PCs than actual Values, and the ranges can cross blocks.
|
||||
// The range is defined first by Values, which are then mapped to Progs
|
||||
// during genssa and finally to function PCs after assembly.
|
||||
// A variable can be on the stack and in any number of registers.
|
||||
type VarLoc struct {
|
||||
// Inclusive -- the first SSA value that the range covers. The value
|
||||
// doesn't necessarily have anything to do with the variable; it just
|
||||
// identifies a point in the program text.
|
||||
Start *Value
|
||||
// Exclusive -- the first SSA value after start that the range doesn't
|
||||
// cover. A location with start == end is empty.
|
||||
End *Value
|
||||
// The prog/PCs corresponding to Start and End above. These are for the
|
||||
// convenience of later passes, since code generation isn't done when
|
||||
// BuildFuncDebug runs.
|
||||
StartProg, EndProg *obj.Prog
|
||||
StartPC, EndPC int64
|
||||
|
||||
// The registers this variable is available in. There can be more than
|
||||
// one in various situations, e.g. it's being moved between registers.
|
||||
Registers RegisterSet
|
||||
// Indicates whether the variable is on the stack. The stack position is
|
||||
// stored in the associated gc.Node.
|
||||
OnStack bool
|
||||
|
||||
// Used only during generation. Indicates whether this location lasts
|
||||
// past the block's end. Without this, there would be no way to distinguish
|
||||
// between a range that ended on the last Value of a block and one that
|
||||
// didn't end at all.
|
||||
survivedBlock bool
|
||||
}
|
||||
|
||||
// RegisterSet is a bitmap of registers, indexed by Register.num.
|
||||
type RegisterSet uint64
|
||||
|
||||
func (v *VarLoc) String() string {
|
||||
var registers []Register
|
||||
if v.Start != nil {
|
||||
registers = v.Start.Block.Func.Config.registers
|
||||
}
|
||||
loc := ""
|
||||
if !v.OnStack && v.Registers == 0 {
|
||||
loc = "!!!no location!!!"
|
||||
}
|
||||
if v.OnStack {
|
||||
loc += "stack,"
|
||||
}
|
||||
var regnames []string
|
||||
for reg := 0; reg < 64; reg++ {
|
||||
if v.Registers&(1<<uint8(reg)) == 0 {
|
||||
continue
|
||||
}
|
||||
if registers != nil {
|
||||
regnames = append(regnames, registers[reg].Name())
|
||||
} else {
|
||||
regnames = append(regnames, fmt.Sprintf("reg%v", reg))
|
||||
}
|
||||
}
|
||||
loc += strings.Join(regnames, ",")
|
||||
pos := func(v *Value, p *obj.Prog, pc int64) string {
|
||||
if v == nil {
|
||||
return "?"
|
||||
}
|
||||
if p == nil {
|
||||
return fmt.Sprintf("v%v", v.ID)
|
||||
}
|
||||
return fmt.Sprintf("v%v/%x", v.ID, pc)
|
||||
}
|
||||
surv := ""
|
||||
if v.survivedBlock {
|
||||
surv = "+"
|
||||
}
|
||||
return fmt.Sprintf("%v-%v%s@%s", pos(v.Start, v.StartProg, v.StartPC), pos(v.End, v.EndProg, v.EndPC), surv, loc)
|
||||
}
|
||||
|
||||
// unexpected is used to indicate an inconsistency or bug in the debug info
|
||||
// generation process. These are not fixable by users. At time of writing,
|
||||
// changing this to a Fprintf(os.Stderr) and running make.bash generates
|
||||
// thousands of warnings.
|
||||
func (s *debugState) unexpected(v *Value, msg string, args ...interface{}) {
|
||||
s.f.Logf("unexpected at "+fmt.Sprint(v.ID)+":"+msg, args...)
|
||||
}
|
||||
|
||||
func (s *debugState) logf(msg string, args ...interface{}) {
|
||||
s.f.Logf(msg, args...)
|
||||
}
|
||||
|
||||
type debugState struct {
|
||||
loggingEnabled bool
|
||||
slots []*LocalSlot
|
||||
f *Func
|
||||
cache *Cache
|
||||
numRegisters int
|
||||
|
||||
// working storage for BuildFuncDebug, reused between blocks.
|
||||
registerContents [][]SlotID
|
||||
}
|
||||
|
||||
// BuildFuncDebug returns debug information for f.
|
||||
// f must be fully processed, so that each Value is where it will be when
|
||||
// machine code is emitted.
|
||||
func BuildFuncDebug(f *Func, loggingEnabled bool) *FuncDebug {
|
||||
if f.RegAlloc == nil {
|
||||
f.Fatalf("BuildFuncDebug on func %v that has not been fully processed", f)
|
||||
}
|
||||
state := &debugState{
|
||||
loggingEnabled: loggingEnabled,
|
||||
slots: make([]*LocalSlot, len(f.Names)),
|
||||
cache: f.Cache,
|
||||
f: f,
|
||||
numRegisters: len(f.Config.registers),
|
||||
registerContents: make([][]SlotID, len(f.Config.registers)),
|
||||
}
|
||||
// TODO: consider storing this in Cache and reusing across functions.
|
||||
valueNames := make([][]SlotID, f.NumValues())
|
||||
|
||||
for i, slot := range f.Names {
|
||||
slot := slot
|
||||
state.slots[i] = &slot
|
||||
|
||||
if isSynthetic(&slot) {
|
||||
continue
|
||||
}
|
||||
for _, value := range f.NamedValues[slot] {
|
||||
valueNames[value.ID] = append(valueNames[value.ID], SlotID(i))
|
||||
}
|
||||
}
|
||||
|
||||
if state.loggingEnabled {
|
||||
var names []string
|
||||
for i, name := range f.Names {
|
||||
names = append(names, fmt.Sprintf("%v = %v", i, name))
|
||||
}
|
||||
state.logf("Name table: %v\n", strings.Join(names, ", "))
|
||||
}
|
||||
|
||||
// Build up block states, starting with the first block, then
|
||||
// processing blocks once their predecessors have been processed.
|
||||
|
||||
// TODO: use a reverse post-order traversal instead of the work queue.
|
||||
|
||||
// Location list entries for each block.
|
||||
blockLocs := make([]*FuncDebug, f.NumBlocks())
|
||||
|
||||
// Work queue of blocks to visit. Some of them may already be processed.
|
||||
work := []*Block{f.Entry}
|
||||
|
||||
for len(work) > 0 {
|
||||
b := work[0]
|
||||
work = work[1:]
|
||||
if blockLocs[b.ID] != nil {
|
||||
continue // already processed
|
||||
}
|
||||
if !state.predecessorsDone(b, blockLocs) {
|
||||
continue // not ready yet
|
||||
}
|
||||
|
||||
for _, edge := range b.Succs {
|
||||
if blockLocs[edge.Block().ID] != nil {
|
||||
continue
|
||||
}
|
||||
work = append(work, edge.Block())
|
||||
}
|
||||
|
||||
// Build the starting state for the block from the final
|
||||
// state of its predecessors.
|
||||
locs := state.mergePredecessors(b, blockLocs)
|
||||
if state.loggingEnabled {
|
||||
state.logf("Processing %v, initial locs %v, regs %v\n", b, locs, state.registerContents)
|
||||
}
|
||||
// Update locs/registers with the effects of each Value.
|
||||
for _, v := range b.Values {
|
||||
slots := valueNames[v.ID]
|
||||
|
||||
// Loads and stores inherit the names of their sources.
|
||||
var source *Value
|
||||
switch v.Op {
|
||||
case OpStoreReg:
|
||||
source = v.Args[0]
|
||||
case OpLoadReg:
|
||||
switch a := v.Args[0]; a.Op {
|
||||
case OpArg:
|
||||
source = a
|
||||
case OpStoreReg:
|
||||
source = a.Args[0]
|
||||
default:
|
||||
state.unexpected(v, "load with unexpected source op %v", a)
|
||||
}
|
||||
}
|
||||
if source != nil {
|
||||
slots = append(slots, valueNames[source.ID]...)
|
||||
// As of writing, the compiler never uses a load/store as a
|
||||
// source of another load/store, so there's no reason this should
|
||||
// ever be consulted. Update just in case, and so that when
|
||||
// valueNames is cached, we can reuse the memory.
|
||||
valueNames[v.ID] = slots
|
||||
}
|
||||
|
||||
if len(slots) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
reg, _ := f.getHome(v.ID).(*Register)
|
||||
state.processValue(locs, v, slots, reg)
|
||||
|
||||
}
|
||||
|
||||
// The block is done; end the locations for all its slots.
|
||||
for _, locList := range locs.Variables {
|
||||
last := locList.last()
|
||||
if last == nil || last.End != nil {
|
||||
continue
|
||||
}
|
||||
if len(b.Values) != 0 {
|
||||
last.End = b.Values[len(b.Values)-1]
|
||||
} else {
|
||||
// This happens when a value survives into an empty block from its predecessor.
|
||||
// Just carry it forward for liveness's sake.
|
||||
last.End = last.Start
|
||||
}
|
||||
last.survivedBlock = true
|
||||
}
|
||||
if state.loggingEnabled {
|
||||
f.Logf("Block done: locs %v, regs %v. work = %+v\n", locs, state.registerContents, work)
|
||||
}
|
||||
blockLocs[b.ID] = locs
|
||||
}
|
||||
|
||||
// Build the complete debug info by concatenating each of the blocks'
|
||||
// locations together.
|
||||
info := &FuncDebug{
|
||||
Variables: make([]VarLocList, len(state.slots)),
|
||||
Slots: state.slots,
|
||||
Registers: f.Config.registers,
|
||||
}
|
||||
for _, b := range f.Blocks {
|
||||
// Ignore empty blocks; there will be some records for liveness
|
||||
// but they're all useless.
|
||||
if len(b.Values) == 0 {
|
||||
continue
|
||||
}
|
||||
if blockLocs[b.ID] == nil {
|
||||
state.unexpected(b.Values[0], "Never processed block %v\n", b)
|
||||
continue
|
||||
}
|
||||
for slot, blockLocList := range blockLocs[b.ID].Variables {
|
||||
for _, loc := range blockLocList.Locations {
|
||||
if !loc.OnStack && loc.Registers == 0 {
|
||||
state.unexpected(loc.Start, "Location for %v with no storage: %+v\n", state.slots[slot], loc)
|
||||
continue // don't confuse downstream with our bugs
|
||||
}
|
||||
if loc.Start == nil || loc.End == nil {
|
||||
state.unexpected(b.Values[0], "Location for %v missing start or end: %v\n", state.slots[slot], loc)
|
||||
continue
|
||||
}
|
||||
info.append(SlotID(slot), loc)
|
||||
}
|
||||
}
|
||||
}
|
||||
if state.loggingEnabled {
|
||||
f.Logf("Final result:\n")
|
||||
for slot, locList := range info.Variables {
|
||||
f.Logf("\t%v => %v\n", state.slots[slot], locList)
|
||||
}
|
||||
}
|
||||
return info
|
||||
}
|
||||
|
||||
// isSynthetic reports whether if slot represents a compiler-inserted variable,
|
||||
// e.g. an autotmp or an anonymous return value that needed a stack slot.
|
||||
func isSynthetic(slot *LocalSlot) bool {
|
||||
c := slot.Name()[0]
|
||||
return c == '.' || c == '~'
|
||||
}
|
||||
|
||||
// predecessorsDone reports whether block is ready to be processed.
|
||||
func (state *debugState) predecessorsDone(b *Block, blockLocs []*FuncDebug) bool {
|
||||
f := b.Func
|
||||
for _, edge := range b.Preds {
|
||||
// Ignore back branches, e.g. the continuation of a for loop.
|
||||
// This may not work for functions with mutual gotos, which are not
|
||||
// reducible, in which case debug information will be missing for any
|
||||
// code after that point in the control flow.
|
||||
if f.sdom().isAncestorEq(b, edge.b) {
|
||||
if state.loggingEnabled {
|
||||
f.Logf("ignoring back branch from %v to %v\n", edge.b, b)
|
||||
}
|
||||
continue // back branch
|
||||
}
|
||||
if blockLocs[edge.b.ID] == nil {
|
||||
if state.loggingEnabled {
|
||||
f.Logf("%v is not ready because %v isn't done\n", b, edge.b)
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// mergePredecessors takes the end state of each of b's predecessors and
|
||||
// intersects them to form the starting state for b.
|
||||
// The registers slice (the second return value) will be reused for each call to mergePredecessors.
|
||||
func (state *debugState) mergePredecessors(b *Block, blockLocs []*FuncDebug) *FuncDebug {
|
||||
live := make([]VarLocList, len(state.slots))
|
||||
|
||||
// Filter out back branches.
|
||||
var preds []*Block
|
||||
for _, pred := range b.Preds {
|
||||
if blockLocs[pred.b.ID] != nil {
|
||||
preds = append(preds, pred.b)
|
||||
}
|
||||
}
|
||||
|
||||
if len(preds) > 0 {
|
||||
p := preds[0]
|
||||
for slot, locList := range blockLocs[p.ID].Variables {
|
||||
last := locList.last()
|
||||
if last == nil || !last.survivedBlock {
|
||||
continue
|
||||
}
|
||||
// If this block is empty, carry forward the end value for liveness.
|
||||
// It'll be ignored later.
|
||||
start := last.End
|
||||
if len(b.Values) != 0 {
|
||||
start = b.Values[0]
|
||||
}
|
||||
loc := state.cache.NewVarLoc()
|
||||
loc.Start = start
|
||||
loc.OnStack = last.OnStack
|
||||
loc.Registers = last.Registers
|
||||
live[slot].append(loc)
|
||||
}
|
||||
}
|
||||
if state.loggingEnabled && len(b.Preds) > 1 {
|
||||
state.logf("Starting merge with state from %v: %v\n", b.Preds[0].b, blockLocs[b.Preds[0].b.ID])
|
||||
}
|
||||
for i := 1; i < len(preds); i++ {
|
||||
p := preds[i]
|
||||
if state.loggingEnabled {
|
||||
state.logf("Merging in state from %v: %v &= %v\n", p, live, blockLocs[p.ID])
|
||||
}
|
||||
|
||||
for slot, liveVar := range live {
|
||||
liveLoc := liveVar.last()
|
||||
if liveLoc == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
predLoc := blockLocs[p.ID].lastLoc(SlotID(slot))
|
||||
// Clear out slots missing/dead in p.
|
||||
if predLoc == nil || !predLoc.survivedBlock {
|
||||
live[slot].Locations = nil
|
||||
continue
|
||||
}
|
||||
|
||||
// Unify storage locations.
|
||||
liveLoc.OnStack = liveLoc.OnStack && predLoc.OnStack
|
||||
liveLoc.Registers &= predLoc.Registers
|
||||
}
|
||||
}
|
||||
|
||||
// Create final result.
|
||||
locs := &FuncDebug{Variables: live, Slots: state.slots}
|
||||
for reg := range state.registerContents {
|
||||
state.registerContents[reg] = state.registerContents[reg][:0]
|
||||
}
|
||||
for slot, locList := range live {
|
||||
loc := locList.last()
|
||||
if loc == nil {
|
||||
continue
|
||||
}
|
||||
for reg := 0; reg < state.numRegisters; reg++ {
|
||||
if loc.Registers&(1<<uint8(reg)) != 0 {
|
||||
state.registerContents[reg] = append(state.registerContents[reg], SlotID(slot))
|
||||
}
|
||||
}
|
||||
}
|
||||
return locs
|
||||
}
|
||||
|
||||
// processValue updates locs and state.registerContents to reflect v, a value with
|
||||
// the names in vSlots and homed in vReg.
|
||||
func (state *debugState) processValue(locs *FuncDebug, v *Value, vSlots []SlotID, vReg *Register) {
|
||||
switch {
|
||||
case v.Op == OpRegKill:
|
||||
if state.loggingEnabled {
|
||||
existingSlots := make([]bool, len(state.slots))
|
||||
for _, slot := range state.registerContents[vReg.num] {
|
||||
existingSlots[slot] = true
|
||||
}
|
||||
for _, slot := range vSlots {
|
||||
if existingSlots[slot] {
|
||||
existingSlots[slot] = false
|
||||
} else {
|
||||
state.unexpected(v, "regkill of unassociated name %v\n", state.slots[slot])
|
||||
}
|
||||
}
|
||||
for slot, live := range existingSlots {
|
||||
if live {
|
||||
state.unexpected(v, "leftover register name: %v\n", state.slots[slot])
|
||||
}
|
||||
}
|
||||
}
|
||||
state.registerContents[vReg.num] = nil
|
||||
|
||||
for _, slot := range vSlots {
|
||||
last := locs.lastLoc(slot)
|
||||
if last == nil {
|
||||
state.unexpected(v, "regkill of already dead %v, %+v\n", vReg, state.slots[slot])
|
||||
continue
|
||||
}
|
||||
if state.loggingEnabled {
|
||||
state.logf("at %v: %v regkilled out of %v\n", v.ID, state.slots[slot], vReg.Name())
|
||||
}
|
||||
if last.End != nil {
|
||||
state.unexpected(v, "regkill of dead slot, died at %v\n", last.End)
|
||||
}
|
||||
last.End = v
|
||||
|
||||
regs := last.Registers &^ (1 << uint8(vReg.num))
|
||||
if !last.OnStack && regs == 0 {
|
||||
continue
|
||||
}
|
||||
loc := state.cache.NewVarLoc()
|
||||
loc.Start = v
|
||||
loc.OnStack = last.OnStack
|
||||
loc.Registers = regs
|
||||
locs.append(slot, loc)
|
||||
}
|
||||
case v.Op == OpArg:
|
||||
for _, slot := range vSlots {
|
||||
if state.loggingEnabled {
|
||||
state.logf("at %v: %v now on stack from arg\n", v.ID, state.slots[slot])
|
||||
}
|
||||
loc := state.cache.NewVarLoc()
|
||||
loc.Start = v
|
||||
loc.OnStack = true
|
||||
locs.append(slot, loc)
|
||||
}
|
||||
|
||||
case v.Op == OpStoreReg:
|
||||
for _, slot := range vSlots {
|
||||
if state.loggingEnabled {
|
||||
state.logf("at %v: %v spilled to stack\n", v.ID, state.slots[slot])
|
||||
}
|
||||
last := locs.lastLoc(slot)
|
||||
if last == nil {
|
||||
state.unexpected(v, "spill of unnamed register %v\n", vReg)
|
||||
break
|
||||
}
|
||||
last.End = v
|
||||
loc := state.cache.NewVarLoc()
|
||||
loc.Start = v
|
||||
loc.OnStack = true
|
||||
loc.Registers = last.Registers
|
||||
locs.append(slot, loc)
|
||||
}
|
||||
|
||||
case vReg != nil:
|
||||
if state.loggingEnabled {
|
||||
newSlots := make([]bool, len(state.slots))
|
||||
for _, slot := range vSlots {
|
||||
newSlots[slot] = true
|
||||
}
|
||||
|
||||
for _, slot := range state.registerContents[vReg.num] {
|
||||
if !newSlots[slot] {
|
||||
state.unexpected(v, "%v clobbered\n", state.slots[slot])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, slot := range vSlots {
|
||||
if state.loggingEnabled {
|
||||
state.logf("at %v: %v now in %v\n", v.ID, state.slots[slot], vReg.Name())
|
||||
}
|
||||
last := locs.lastLoc(slot)
|
||||
if last != nil && last.End == nil {
|
||||
last.End = v
|
||||
}
|
||||
state.registerContents[vReg.num] = append(state.registerContents[vReg.num], slot)
|
||||
loc := state.cache.NewVarLoc()
|
||||
loc.Start = v
|
||||
if last != nil {
|
||||
loc.OnStack = last.OnStack
|
||||
loc.Registers = last.Registers
|
||||
}
|
||||
loc.Registers |= 1 << uint8(vReg.num)
|
||||
locs.append(slot, loc)
|
||||
}
|
||||
default:
|
||||
state.unexpected(v, "named value with no reg\n")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -98,7 +98,6 @@ func decomposeBuiltIn(f *Func) {
|
||||
delete(f.NamedValues, name)
|
||||
case t.IsFloat():
|
||||
// floats are never decomposed, even ones bigger than RegSize
|
||||
newNames = append(newNames, name)
|
||||
case t.Size() > f.Config.RegSize:
|
||||
f.Fatalf("undecomposed named type %v %v", name, t)
|
||||
default:
|
||||
|
||||
@@ -82,33 +82,33 @@ func (DummyFrontend) Auto(pos src.XPos, t *types.Type) GCNode {
|
||||
return &DummyAuto{t: t, s: "aDummyAuto"}
|
||||
}
|
||||
func (d DummyFrontend) SplitString(s LocalSlot) (LocalSlot, LocalSlot) {
|
||||
return LocalSlot{N: s.N, Type: dummyTypes.BytePtr, Off: s.Off}, LocalSlot{N: s.N, Type: dummyTypes.Int, Off: s.Off + 8}
|
||||
return LocalSlot{s.N, dummyTypes.BytePtr, s.Off}, LocalSlot{s.N, dummyTypes.Int, s.Off + 8}
|
||||
}
|
||||
func (d DummyFrontend) SplitInterface(s LocalSlot) (LocalSlot, LocalSlot) {
|
||||
return LocalSlot{N: s.N, Type: dummyTypes.BytePtr, Off: s.Off}, LocalSlot{N: s.N, Type: dummyTypes.BytePtr, Off: s.Off + 8}
|
||||
return LocalSlot{s.N, dummyTypes.BytePtr, s.Off}, LocalSlot{s.N, dummyTypes.BytePtr, s.Off + 8}
|
||||
}
|
||||
func (d DummyFrontend) SplitSlice(s LocalSlot) (LocalSlot, LocalSlot, LocalSlot) {
|
||||
return LocalSlot{N: s.N, Type: s.Type.ElemType().PtrTo(), Off: s.Off},
|
||||
LocalSlot{N: s.N, Type: dummyTypes.Int, Off: s.Off + 8},
|
||||
LocalSlot{N: s.N, Type: dummyTypes.Int, Off: s.Off + 16}
|
||||
return LocalSlot{s.N, s.Type.ElemType().PtrTo(), s.Off},
|
||||
LocalSlot{s.N, dummyTypes.Int, s.Off + 8},
|
||||
LocalSlot{s.N, dummyTypes.Int, s.Off + 16}
|
||||
}
|
||||
func (d DummyFrontend) SplitComplex(s LocalSlot) (LocalSlot, LocalSlot) {
|
||||
if s.Type.Size() == 16 {
|
||||
return LocalSlot{N: s.N, Type: dummyTypes.Float64, Off: s.Off}, LocalSlot{N: s.N, Type: dummyTypes.Float64, Off: s.Off + 8}
|
||||
return LocalSlot{s.N, dummyTypes.Float64, s.Off}, LocalSlot{s.N, dummyTypes.Float64, s.Off + 8}
|
||||
}
|
||||
return LocalSlot{N: s.N, Type: dummyTypes.Float32, Off: s.Off}, LocalSlot{N: s.N, Type: dummyTypes.Float32, Off: s.Off + 4}
|
||||
return LocalSlot{s.N, dummyTypes.Float32, s.Off}, LocalSlot{s.N, dummyTypes.Float32, s.Off + 4}
|
||||
}
|
||||
func (d DummyFrontend) SplitInt64(s LocalSlot) (LocalSlot, LocalSlot) {
|
||||
if s.Type.IsSigned() {
|
||||
return LocalSlot{N: s.N, Type: dummyTypes.Int32, Off: s.Off + 4}, LocalSlot{N: s.N, Type: dummyTypes.UInt32, Off: s.Off}
|
||||
return LocalSlot{s.N, dummyTypes.Int32, s.Off + 4}, LocalSlot{s.N, dummyTypes.UInt32, s.Off}
|
||||
}
|
||||
return LocalSlot{N: s.N, Type: dummyTypes.UInt32, Off: s.Off + 4}, LocalSlot{N: s.N, Type: dummyTypes.UInt32, Off: s.Off}
|
||||
return LocalSlot{s.N, dummyTypes.UInt32, s.Off + 4}, LocalSlot{s.N, dummyTypes.UInt32, s.Off}
|
||||
}
|
||||
func (d DummyFrontend) SplitStruct(s LocalSlot, i int) LocalSlot {
|
||||
return LocalSlot{N: s.N, Type: s.Type.FieldType(i), Off: s.Off + s.Type.FieldOff(i)}
|
||||
return LocalSlot{s.N, s.Type.FieldType(i), s.Off + s.Type.FieldOff(i)}
|
||||
}
|
||||
func (d DummyFrontend) SplitArray(s LocalSlot) LocalSlot {
|
||||
return LocalSlot{N: s.N, Type: s.Type.ElemType(), Off: s.Off}
|
||||
return LocalSlot{s.N, s.Type.ElemType(), s.Off}
|
||||
}
|
||||
func (DummyFrontend) Line(_ src.XPos) string {
|
||||
return "unknown.go:0"
|
||||
|
||||
@@ -945,6 +945,7 @@
|
||||
(Div16u n (Const16 [c])) && isPowerOfTwo(c&0xffff) -> (Rsh16Ux64 n (Const64 <typ.UInt64> [log2(c&0xffff)]))
|
||||
(Div32u n (Const32 [c])) && isPowerOfTwo(c&0xffffffff) -> (Rsh32Ux64 n (Const64 <typ.UInt64> [log2(c&0xffffffff)]))
|
||||
(Div64u n (Const64 [c])) && isPowerOfTwo(c) -> (Rsh64Ux64 n (Const64 <typ.UInt64> [log2(c)]))
|
||||
(Div64u n (Const64 [-1<<63])) -> (Rsh64Ux64 n (Const64 <typ.UInt64> [63]))
|
||||
|
||||
// Unsigned divide, not a power of 2. Strength reduce to a multiply.
|
||||
// For 8-bit divides, we just do a direct 9-bit by 8-bit multiply.
|
||||
@@ -1177,6 +1178,7 @@
|
||||
(Mod16u <t> n (Const16 [c])) && isPowerOfTwo(c&0xffff) -> (And16 n (Const16 <t> [(c&0xffff)-1]))
|
||||
(Mod32u <t> n (Const32 [c])) && isPowerOfTwo(c&0xffffffff) -> (And32 n (Const32 <t> [(c&0xffffffff)-1]))
|
||||
(Mod64u <t> n (Const64 [c])) && isPowerOfTwo(c) -> (And64 n (Const64 <t> [c-1]))
|
||||
(Mod64u <t> n (Const64 [-1<<63])) -> (And64 n (Const64 <t> [1<<63-1]))
|
||||
|
||||
// Signed mod by negative constant.
|
||||
(Mod8 <t> n (Const8 [c])) && c < 0 && c != -1<<7 -> (Mod8 <t> n (Const8 <t> [-c]))
|
||||
|
||||
@@ -417,7 +417,6 @@ var genericOps = []opData{
|
||||
{name: "VarKill", argLength: 1, aux: "Sym", symEffect: "None"}, // aux is a *gc.Node of a variable that is known to be dead. arg0=mem, returns mem
|
||||
{name: "VarLive", argLength: 1, aux: "Sym", symEffect: "None"}, // aux is a *gc.Node of a variable that must be kept live. arg0=mem, returns mem
|
||||
{name: "KeepAlive", argLength: 2, typ: "Mem"}, // arg[0] is a value that must be kept alive until this mark. arg[1]=mem, returns mem
|
||||
{name: "RegKill"}, // regalloc has determined that the value in this register is dead
|
||||
|
||||
// Ops for breaking 64-bit operations on 32-bit architectures
|
||||
{name: "Int64Make", argLength: 2, typ: "UInt64"}, // arg0=hi, arg1=lo
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"html"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type HTMLWriter struct {
|
||||
@@ -363,18 +362,6 @@ func (v *Value) LongHTML() string {
|
||||
if int(v.ID) < len(r) && r[v.ID] != nil {
|
||||
s += " : " + html.EscapeString(r[v.ID].Name())
|
||||
}
|
||||
var names []string
|
||||
for name, values := range v.Block.Func.NamedValues {
|
||||
for _, value := range values {
|
||||
if value == v {
|
||||
names = append(names, name.Name())
|
||||
break // drop duplicates.
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(names) != 0 {
|
||||
s += " (" + strings.Join(names, ", ") + ")"
|
||||
}
|
||||
s += "</span>"
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -26,38 +26,12 @@ func (r *Register) Name() string {
|
||||
return r.name
|
||||
}
|
||||
|
||||
// ObjNum returns the register number from cmd/internal/obj/$ARCH that
|
||||
// corresponds to this register.
|
||||
func (r *Register) ObjNum() int16 {
|
||||
return r.objNum
|
||||
}
|
||||
|
||||
// A LocalSlot is a location in the stack frame, which identifies and stores
|
||||
// part or all of a PPARAM, PPARAMOUT, or PAUTO ONAME node.
|
||||
// It can represent a whole variable, part of a larger stack slot, or part of a
|
||||
// variable that has been decomposed into multiple stack slots.
|
||||
// As an example, a string could have the following configurations:
|
||||
//
|
||||
// stack layout LocalSlots
|
||||
//
|
||||
// Optimizations are disabled. s is on the stack and represented in its entirety.
|
||||
// [ ------- s string ---- ] { N: s, Type: string, Off: 0 }
|
||||
//
|
||||
// s was not decomposed, but the SSA operates on its parts individually, so
|
||||
// there is a LocalSlot for each of its fields that points into the single stack slot.
|
||||
// [ ------- s string ---- ] { N: s, Type: *uint8, Off: 0 }, {N: s, Type: int, Off: 8}
|
||||
//
|
||||
// s was decomposed. Each of its fields is in its own stack slot and has its own LocalSLot.
|
||||
// [ ptr *uint8 ] [ len int] { N: ptr, Type: *uint8, Off: 0, SplitOf: parent, SplitOffset: 0},
|
||||
// { N: len, Type: int, Off: 0, SplitOf: parent, SplitOffset: 8}
|
||||
// parent = &{N: s, Type: string}
|
||||
// A LocalSlot is a location in the stack frame.
|
||||
// It is (possibly a subpiece of) a PPARAM, PPARAMOUT, or PAUTO ONAME node.
|
||||
type LocalSlot struct {
|
||||
N GCNode // an ONAME *gc.Node representing a stack location.
|
||||
N GCNode // an ONAME *gc.Node representing a variable on the stack
|
||||
Type *types.Type // type of slot
|
||||
Off int64 // offset of slot in N
|
||||
|
||||
SplitOf *LocalSlot // slot is a decomposition of SplitOf
|
||||
SplitOffset int64 // .. at this offset.
|
||||
}
|
||||
|
||||
func (s LocalSlot) Name() string {
|
||||
|
||||
@@ -1897,7 +1897,6 @@ const (
|
||||
OpVarKill
|
||||
OpVarLive
|
||||
OpKeepAlive
|
||||
OpRegKill
|
||||
OpInt64Make
|
||||
OpInt64Hi
|
||||
OpInt64Lo
|
||||
@@ -22498,11 +22497,6 @@ var opcodeTable = [...]opInfo{
|
||||
argLen: 2,
|
||||
generic: true,
|
||||
},
|
||||
{
|
||||
name: "RegKill",
|
||||
argLen: 0,
|
||||
generic: true,
|
||||
},
|
||||
{
|
||||
name: "Int64Make",
|
||||
argLen: 2,
|
||||
|
||||
@@ -242,9 +242,6 @@ type regAllocState struct {
|
||||
// current state of each (preregalloc) Value
|
||||
values []valState
|
||||
|
||||
// names associated with each Value
|
||||
valueNames [][]LocalSlot
|
||||
|
||||
// ID of SP, SB values
|
||||
sp, sb ID
|
||||
|
||||
@@ -303,13 +300,6 @@ type startReg struct {
|
||||
|
||||
// freeReg frees up register r. Any current user of r is kicked out.
|
||||
func (s *regAllocState) freeReg(r register) {
|
||||
s.freeOrResetReg(r, false)
|
||||
}
|
||||
|
||||
// freeOrResetReg frees up register r. Any current user of r is kicked out.
|
||||
// resetting indicates that the operation is only for bookkeeping,
|
||||
// e.g. when clearing out state upon entry to a new block.
|
||||
func (s *regAllocState) freeOrResetReg(r register, resetting bool) {
|
||||
v := s.regs[r].v
|
||||
if v == nil {
|
||||
s.f.Fatalf("tried to free an already free register %d\n", r)
|
||||
@@ -319,16 +309,6 @@ func (s *regAllocState) freeOrResetReg(r register, resetting bool) {
|
||||
if s.f.pass.debug > regDebug {
|
||||
fmt.Printf("freeReg %s (dump %s/%s)\n", s.registers[r].Name(), v, s.regs[r].c)
|
||||
}
|
||||
if !resetting && s.f.Config.ctxt.Flag_locationlists && len(s.valueNames[v.ID]) != 0 {
|
||||
kill := s.curBlock.NewValue0(src.NoXPos, OpRegKill, types.TypeVoid)
|
||||
for int(kill.ID) >= len(s.orig) {
|
||||
s.orig = append(s.orig, nil)
|
||||
}
|
||||
for _, name := range s.valueNames[v.ID] {
|
||||
s.f.NamedValues[name] = append(s.f.NamedValues[name], kill)
|
||||
}
|
||||
s.f.setHome(kill, &s.registers[r])
|
||||
}
|
||||
s.regs[r] = regState{}
|
||||
s.values[v.ID].regs &^= regMask(1) << r
|
||||
s.used &^= regMask(1) << r
|
||||
@@ -619,17 +599,6 @@ func (s *regAllocState) init(f *Func) {
|
||||
s.values = make([]valState, f.NumValues())
|
||||
s.orig = make([]*Value, f.NumValues())
|
||||
s.copies = make(map[*Value]bool)
|
||||
if s.f.Config.ctxt.Flag_locationlists {
|
||||
s.valueNames = make([][]LocalSlot, f.NumValues())
|
||||
for slot, values := range f.NamedValues {
|
||||
if isSynthetic(&slot) {
|
||||
continue
|
||||
}
|
||||
for _, value := range values {
|
||||
s.valueNames[value.ID] = append(s.valueNames[value.ID], slot)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, b := range f.Blocks {
|
||||
for _, v := range b.Values {
|
||||
if !v.Type.IsMemory() && !v.Type.IsVoid() && !v.Type.IsFlags() && !v.Type.IsTuple() {
|
||||
@@ -723,9 +692,7 @@ func (s *regAllocState) liveAfterCurrentInstruction(v *Value) bool {
|
||||
|
||||
// Sets the state of the registers to that encoded in regs.
|
||||
func (s *regAllocState) setState(regs []endReg) {
|
||||
for s.used != 0 {
|
||||
s.freeOrResetReg(pickReg(s.used), true)
|
||||
}
|
||||
s.freeRegs(s.used)
|
||||
for _, x := range regs {
|
||||
s.assignReg(x.r, x.v, x.c)
|
||||
}
|
||||
@@ -768,9 +735,6 @@ func (s *regAllocState) regalloc(f *Func) {
|
||||
}
|
||||
|
||||
for _, b := range f.Blocks {
|
||||
if s.f.pass.debug > regDebug {
|
||||
fmt.Printf("Begin processing block %v\n", b)
|
||||
}
|
||||
s.curBlock = b
|
||||
|
||||
// Initialize regValLiveSet and uses fields for this block.
|
||||
@@ -866,6 +830,9 @@ func (s *regAllocState) regalloc(f *Func) {
|
||||
// This is the complicated case. We have more than one predecessor,
|
||||
// which means we may have Phi ops.
|
||||
|
||||
// Copy phi ops into new schedule.
|
||||
b.Values = append(b.Values, phis...)
|
||||
|
||||
// Start with the final register state of the primary predecessor
|
||||
idx := s.primary[b.ID]
|
||||
if idx < 0 {
|
||||
@@ -943,9 +910,6 @@ func (s *regAllocState) regalloc(f *Func) {
|
||||
}
|
||||
}
|
||||
|
||||
// Copy phi ops into new schedule.
|
||||
b.Values = append(b.Values, phis...)
|
||||
|
||||
// Third pass - pick registers for phis whose inputs
|
||||
// were not in a register.
|
||||
for i, v := range phis {
|
||||
@@ -1041,7 +1005,7 @@ func (s *regAllocState) regalloc(f *Func) {
|
||||
pidx := e.i
|
||||
for _, v := range succ.Values {
|
||||
if v.Op != OpPhi {
|
||||
continue
|
||||
break
|
||||
}
|
||||
if !s.values[v.ID].needReg {
|
||||
continue
|
||||
@@ -1601,9 +1565,6 @@ func (s *regAllocState) placeSpills() {
|
||||
for _, b := range f.Blocks {
|
||||
var m regMask
|
||||
for _, v := range b.Values {
|
||||
if v.Op == OpRegKill {
|
||||
continue
|
||||
}
|
||||
if v.Op != OpPhi {
|
||||
break
|
||||
}
|
||||
@@ -1714,7 +1675,7 @@ func (s *regAllocState) placeSpills() {
|
||||
for _, b := range f.Blocks {
|
||||
nphi := 0
|
||||
for _, v := range b.Values {
|
||||
if v.Op != OpRegKill && v.Op != OpPhi {
|
||||
if v.Op != OpPhi {
|
||||
break
|
||||
}
|
||||
nphi++
|
||||
@@ -1839,9 +1800,6 @@ func (e *edgeState) setup(idx int, srcReg []endReg, dstReg []startReg, stacklive
|
||||
}
|
||||
// Phis need their args to end up in a specific location.
|
||||
for _, v := range e.b.Values {
|
||||
if v.Op == OpRegKill {
|
||||
continue
|
||||
}
|
||||
if v.Op != OpPhi {
|
||||
break
|
||||
}
|
||||
@@ -1920,7 +1878,6 @@ func (e *edgeState) process() {
|
||||
if e.s.f.pass.debug > regDebug {
|
||||
fmt.Printf("breaking cycle with v%d in %s:%s\n", vid, loc.Name(), c)
|
||||
}
|
||||
e.erase(r)
|
||||
if _, isReg := loc.(*Register); isReg {
|
||||
c = e.p.NewValue1(d.pos, OpCopy, c.Type, c)
|
||||
} else {
|
||||
@@ -1986,18 +1943,6 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, pos src.XP
|
||||
}
|
||||
}
|
||||
_, dstReg := loc.(*Register)
|
||||
|
||||
// Pre-clobber destination. This avoids the
|
||||
// following situation:
|
||||
// - v is currently held in R0 and stacktmp0.
|
||||
// - We want to copy stacktmp1 to stacktmp0.
|
||||
// - We choose R0 as the temporary register.
|
||||
// During the copy, both R0 and stacktmp0 are
|
||||
// clobbered, losing both copies of v. Oops!
|
||||
// Erasing the destination early means R0 will not
|
||||
// be chosen as the temp register, as it will then
|
||||
// be the last copy of v.
|
||||
e.erase(loc)
|
||||
var x *Value
|
||||
if c == nil {
|
||||
if !e.s.values[vid].rematerializeable {
|
||||
@@ -2008,8 +1953,8 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, pos src.XP
|
||||
} else {
|
||||
// Rematerialize into stack slot. Need a free
|
||||
// register to accomplish this.
|
||||
e.erase(loc) // see pre-clobber comment below
|
||||
r := e.findRegFor(v.Type)
|
||||
e.erase(r)
|
||||
x = v.copyIntoNoXPos(e.p)
|
||||
e.set(r, vid, x, false, pos)
|
||||
// Make sure we spill with the size of the slot, not the
|
||||
@@ -2031,8 +1976,20 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, pos src.XP
|
||||
x = e.p.NewValue1(pos, OpLoadReg, c.Type, c)
|
||||
} else {
|
||||
// mem->mem. Use temp register.
|
||||
|
||||
// Pre-clobber destination. This avoids the
|
||||
// following situation:
|
||||
// - v is currently held in R0 and stacktmp0.
|
||||
// - We want to copy stacktmp1 to stacktmp0.
|
||||
// - We choose R0 as the temporary register.
|
||||
// During the copy, both R0 and stacktmp0 are
|
||||
// clobbered, losing both copies of v. Oops!
|
||||
// Erasing the destination early means R0 will not
|
||||
// be chosen as the temp register, as it will then
|
||||
// be the last copy of v.
|
||||
e.erase(loc)
|
||||
|
||||
r := e.findRegFor(c.Type)
|
||||
e.erase(r)
|
||||
t := e.p.NewValue1(pos, OpLoadReg, c.Type, c)
|
||||
e.set(r, vid, t, false, pos)
|
||||
x = e.p.NewValue1(pos, OpStoreReg, loc.(LocalSlot).Type, t)
|
||||
@@ -2051,6 +2008,7 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, pos src.XP
|
||||
// set changes the contents of location loc to hold the given value and its cached representative.
|
||||
func (e *edgeState) set(loc Location, vid ID, c *Value, final bool, pos src.XPos) {
|
||||
e.s.f.setHome(c, loc)
|
||||
e.erase(loc)
|
||||
e.contents[loc] = contentRecord{vid, c, final, pos}
|
||||
a := e.cache[vid]
|
||||
if len(a) == 0 {
|
||||
@@ -2101,16 +2059,6 @@ func (e *edgeState) erase(loc Location) {
|
||||
fmt.Printf("v%d no longer available in %s:%s\n", vid, loc.Name(), c)
|
||||
}
|
||||
a[i], a = a[len(a)-1], a[:len(a)-1]
|
||||
if e.s.f.Config.ctxt.Flag_locationlists {
|
||||
if _, isReg := loc.(*Register); isReg && int(c.ID) < len(e.s.valueNames) && len(e.s.valueNames[c.ID]) != 0 {
|
||||
kill := e.p.NewValue0(src.NoXPos, OpRegKill, types.TypeVoid)
|
||||
e.s.f.setHome(kill, loc)
|
||||
for _, name := range e.s.valueNames[c.ID] {
|
||||
e.s.f.NamedValues[name] = append(e.s.f.NamedValues[name], kill)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -2170,8 +2118,8 @@ func (e *edgeState) findRegFor(typ *types.Type) Location {
|
||||
// Allocate a temp location to spill a register to.
|
||||
// The type of the slot is immaterial - it will not be live across
|
||||
// any safepoint. Just use a type big enough to hold any register.
|
||||
t := LocalSlot{N: e.s.f.fe.Auto(c.Pos, types.Int64), Type: types.Int64}
|
||||
// TODO: reuse these slots. They'll need to be erased first.
|
||||
t := LocalSlot{e.s.f.fe.Auto(c.Pos, types.Int64), types.Int64, 0}
|
||||
// TODO: reuse these slots.
|
||||
e.set(t, vid, x, false, c.Pos)
|
||||
if e.s.f.pass.debug > regDebug {
|
||||
fmt.Printf(" SPILL %s->%s %s\n", r.Name(), t.Name(), x.LongString())
|
||||
|
||||
@@ -7240,6 +7240,26 @@ func rewriteValuegeneric_OpDiv64u_0(v *Value) bool {
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
// match: (Div64u n (Const64 [-1<<63]))
|
||||
// cond:
|
||||
// result: (Rsh64Ux64 n (Const64 <typ.UInt64> [63]))
|
||||
for {
|
||||
_ = v.Args[1]
|
||||
n := v.Args[0]
|
||||
v_1 := v.Args[1]
|
||||
if v_1.Op != OpConst64 {
|
||||
break
|
||||
}
|
||||
if v_1.AuxInt != -1<<63 {
|
||||
break
|
||||
}
|
||||
v.reset(OpRsh64Ux64)
|
||||
v.AddArg(n)
|
||||
v0 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
|
||||
v0.AuxInt = 63
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
// match: (Div64u x (Const64 [c]))
|
||||
// cond: umagicOK(64, c) && config.RegSize == 8 && umagic(64,c).m&1 == 0
|
||||
// result: (Rsh64Ux64 <typ.UInt64> (Hmul64u <typ.UInt64> (Const64 <typ.UInt64> [int64(1<<63+umagic(64,c).m/2)]) x) (Const64 <typ.UInt64> [umagic(64,c).s-1]))
|
||||
@@ -12061,6 +12081,27 @@ func rewriteValuegeneric_OpMod64u_0(v *Value) bool {
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
// match: (Mod64u <t> n (Const64 [-1<<63]))
|
||||
// cond:
|
||||
// result: (And64 n (Const64 <t> [1<<63-1]))
|
||||
for {
|
||||
t := v.Type
|
||||
_ = v.Args[1]
|
||||
n := v.Args[0]
|
||||
v_1 := v.Args[1]
|
||||
if v_1.Op != OpConst64 {
|
||||
break
|
||||
}
|
||||
if v_1.AuxInt != -1<<63 {
|
||||
break
|
||||
}
|
||||
v.reset(OpAnd64)
|
||||
v.AddArg(n)
|
||||
v0 := b.NewValue0(v.Pos, OpConst64, t)
|
||||
v0.AuxInt = 1<<63 - 1
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
// match: (Mod64u <t> x (Const64 [c]))
|
||||
// cond: x.Op != OpConst64 && c > 0 && umagicOK(64,c)
|
||||
// result: (Sub64 x (Mul64 <t> (Div64u <t> x (Const64 <t> [c])) (Const64 <t> [c])))
|
||||
|
||||
@@ -24,7 +24,6 @@ func TestSizeof(t *testing.T) {
|
||||
}{
|
||||
{Value{}, 68, 112},
|
||||
{Block{}, 152, 288},
|
||||
{LocalSlot{}, 32, 48},
|
||||
{valState{}, 28, 40},
|
||||
}
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ func (s *stackAllocState) stackalloc() {
|
||||
if v.Op != OpArg {
|
||||
continue
|
||||
}
|
||||
loc := LocalSlot{N: v.Aux.(GCNode), Type: v.Type, Off: v.AuxInt}
|
||||
loc := LocalSlot{v.Aux.(GCNode), v.Type, v.AuxInt}
|
||||
if f.pass.debug > stackDebug {
|
||||
fmt.Printf("stackalloc %s to %s\n", v, loc.Name())
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"cmd/internal/src"
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// A Value represents a value in the SSA representation of the program.
|
||||
@@ -99,7 +98,7 @@ func (v *Value) AuxValAndOff() ValAndOff {
|
||||
return ValAndOff(v.AuxInt)
|
||||
}
|
||||
|
||||
// long form print. v# = opcode <type> [aux] args [: reg] (names)
|
||||
// long form print. v# = opcode <type> [aux] args [: reg]
|
||||
func (v *Value) LongString() string {
|
||||
s := fmt.Sprintf("v%d = %s", v.ID, v.Op)
|
||||
s += " <" + v.Type.String() + ">"
|
||||
@@ -111,18 +110,6 @@ func (v *Value) LongString() string {
|
||||
if int(v.ID) < len(r) && r[v.ID] != nil {
|
||||
s += " : " + r[v.ID].Name()
|
||||
}
|
||||
var names []string
|
||||
for name, values := range v.Block.Func.NamedValues {
|
||||
for _, value := range values {
|
||||
if value == v {
|
||||
names = append(names, name.Name())
|
||||
break // drop duplicates.
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(names) != 0 {
|
||||
s += " (" + strings.Join(names, ", ") + ")"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) {
|
||||
p = s.Prog(x86.AFLDCW)
|
||||
p.From.Type = obj.TYPE_MEM
|
||||
p.From.Name = obj.NAME_EXTERN
|
||||
p.From.Sym = gc.Sysfunc("controlWord32")
|
||||
p.From.Sym = gc.ControlWord32
|
||||
}
|
||||
|
||||
var op obj.As
|
||||
@@ -210,7 +210,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) {
|
||||
p = s.Prog(x86.AFLDCW)
|
||||
p.From.Type = obj.TYPE_MEM
|
||||
p.From.Name = obj.NAME_EXTERN
|
||||
p.From.Sym = gc.Sysfunc("controlWord64trunc")
|
||||
p.From.Sym = gc.ControlWord64trunc
|
||||
|
||||
// Now do the conversion.
|
||||
p = s.Prog(x86.AFMOVLP)
|
||||
|
||||
18
src/cmd/dist/deps.go
vendored
18
src/cmd/dist/deps.go
vendored
@@ -31,8 +31,8 @@ var builddeps = map[string][]string{
|
||||
"cmd/internal/objabi": {"errors", "flag", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "log", "math", "os", "path/filepath", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
|
||||
"compress/flate": {"bufio", "bytes", "errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "math/bits", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
|
||||
"compress/zlib": {"bufio", "bytes", "compress/flate", "errors", "fmt", "hash", "hash/adler32", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "math/bits", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
|
||||
"container/heap": {"errors", "internal/cpu", "internal/race", "math", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "unicode/utf8"},
|
||||
"context": {"errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
|
||||
"container/heap": {"errors", "internal/cpu", "internal/race", "math", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "unicode", "unicode/utf8"},
|
||||
"context": {"errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
|
||||
"crypto": {"errors", "hash", "internal/cpu", "internal/race", "io", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
|
||||
"crypto/sha1": {"crypto", "errors", "hash", "internal/cpu", "internal/race", "io", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
|
||||
"debug/dwarf": {"encoding/binary", "errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "path", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
|
||||
@@ -40,18 +40,18 @@ var builddeps = map[string][]string{
|
||||
"debug/macho": {"bytes", "debug/dwarf", "encoding/binary", "errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "path", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
|
||||
"encoding": {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
|
||||
"encoding/base64": {"errors", "internal/cpu", "internal/race", "io", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
|
||||
"encoding/binary": {"errors", "internal/cpu", "internal/race", "io", "math", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
|
||||
"encoding/binary": {"errors", "internal/cpu", "internal/race", "io", "math", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode", "unicode/utf8"},
|
||||
"encoding/json": {"bytes", "encoding", "encoding/base64", "errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
|
||||
"encoding/xml": {"bufio", "bytes", "encoding", "errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
|
||||
"errors": {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
|
||||
"flag": {"errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
|
||||
"fmt": {"errors", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
|
||||
"flag": {"errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
|
||||
"fmt": {"errors", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
|
||||
"go/ast": {"bytes", "errors", "fmt", "go/scanner", "go/token", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "path/filepath", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
|
||||
"go/build": {"bufio", "bytes", "errors", "fmt", "go/ast", "go/doc", "go/parser", "go/scanner", "go/token", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "log", "math", "net/url", "os", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
|
||||
"go/doc": {"bytes", "errors", "fmt", "go/ast", "go/scanner", "go/token", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "math", "net/url", "os", "path", "path/filepath", "reflect", "regexp", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "text/template", "text/template/parse", "time", "unicode", "unicode/utf16", "unicode/utf8"},
|
||||
"go/parser": {"bytes", "errors", "fmt", "go/ast", "go/scanner", "go/token", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "io/ioutil", "math", "os", "path/filepath", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
|
||||
"go/scanner": {"bytes", "errors", "fmt", "go/token", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "path/filepath", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
|
||||
"go/token": {"errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
|
||||
"go/token": {"errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
|
||||
"hash": {"errors", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic"},
|
||||
"hash/adler32": {"errors", "hash", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic"},
|
||||
"internal/cpu": {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
|
||||
@@ -63,7 +63,7 @@ var builddeps = map[string][]string{
|
||||
"internal/syscall/windows/sysdll": {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
|
||||
"io": {"errors", "internal/race", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic"},
|
||||
"io/ioutil": {"bytes", "errors", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "path/filepath", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
|
||||
"log": {"errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
|
||||
"log": {"errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
|
||||
"math": {"internal/cpu", "runtime", "runtime/internal/atomic", "runtime/internal/sys"},
|
||||
"math/bits": {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
|
||||
"net/url": {"bytes", "errors", "fmt", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
|
||||
@@ -72,13 +72,13 @@ var builddeps = map[string][]string{
|
||||
"os/signal": {"errors", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "os", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
|
||||
"path": {"errors", "internal/cpu", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strings", "sync", "sync/atomic", "unicode", "unicode/utf8"},
|
||||
"path/filepath": {"errors", "internal/cpu", "internal/poll", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
|
||||
"reflect": {"errors", "internal/cpu", "internal/race", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
|
||||
"reflect": {"errors", "internal/cpu", "internal/race", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode", "unicode/utf8"},
|
||||
"regexp": {"bytes", "errors", "internal/cpu", "internal/race", "io", "math", "reflect", "regexp/syntax", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "unicode", "unicode/utf8"},
|
||||
"regexp/syntax": {"bytes", "errors", "internal/cpu", "internal/race", "io", "math", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "unicode", "unicode/utf8"},
|
||||
"runtime": {"runtime/internal/atomic", "runtime/internal/sys"},
|
||||
"runtime/internal/atomic": {"runtime/internal/sys"},
|
||||
"runtime/internal/sys": {},
|
||||
"sort": {"errors", "internal/cpu", "internal/race", "math", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
|
||||
"sort": {"errors", "internal/cpu", "internal/race", "math", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode", "unicode/utf8"},
|
||||
"strconv": {"errors", "internal/cpu", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "unicode/utf8"},
|
||||
"strings": {"errors", "internal/cpu", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "unicode", "unicode/utf8"},
|
||||
"sync": {"internal/race", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync/atomic"},
|
||||
|
||||
11
src/cmd/dist/test.go
vendored
11
src/cmd/dist/test.go
vendored
@@ -447,6 +447,17 @@ func (t *tester) registerTests() {
|
||||
t.runPending(dt)
|
||||
moved := t.goroot + "-moved"
|
||||
if err := os.Rename(t.goroot, moved); err != nil {
|
||||
if t.goos == "windows" {
|
||||
// Fails on Windows (with "Access is denied") if a process
|
||||
// or binary is in this directory. For instance, using all.bat
|
||||
// when run from c:\workdir\go\src fails here
|
||||
// if GO_BUILDER_NAME is set. Our builders invoke tests
|
||||
// a different way which happens to work when sharding
|
||||
// tests, but we should be tolerant of the non-sharded
|
||||
// all.bat case.
|
||||
log.Printf("skipping test on Windows")
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -1317,6 +1317,25 @@ func TestGetGitDefaultBranch(t *testing.T) {
|
||||
tg.grepStdout(`\* another-branch`, "not on correct default branch")
|
||||
}
|
||||
|
||||
func TestAccidentalGitCheckout(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()
|
||||
tg.parallel()
|
||||
tg.tempDir("src")
|
||||
tg.setenv("GOPATH", tg.path("."))
|
||||
|
||||
tg.runFail("get", "-u", "vcs-test.golang.org/go/test1-svn-git")
|
||||
tg.grepStderr("src[\\\\/]vcs-test.* uses git, but parent .*src[\\\\/]vcs-test.* uses svn", "get did not fail for right reason")
|
||||
|
||||
tg.runFail("get", "-u", "vcs-test.golang.org/go/test2-svn-git/test2main")
|
||||
tg.grepStderr("src[\\\\/]vcs-test.* uses git, but parent .*src[\\\\/]vcs-test.* uses svn", "get did not fail for right reason")
|
||||
}
|
||||
|
||||
func TestErrorMessageForSyntaxErrorInTestGoFileSaysFAIL(t *testing.T) {
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
@@ -4314,3 +4333,20 @@ func TestTestRegexps(t *testing.T) {
|
||||
t.Errorf("reduced output:<<<\n%s>>> want:<<<\n%s>>>", have, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListTests(t *testing.T) {
|
||||
var tg *testgoData
|
||||
testWith := func(listName, expected string) func(*testing.T) {
|
||||
return func(t *testing.T) {
|
||||
tg = testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.run("test", "./testdata/src/testlist/...", fmt.Sprintf("-list=%s", listName))
|
||||
tg.grepStdout(expected, fmt.Sprintf("-test.list=%s returned %q, expected %s", listName, tg.getStdout(), expected))
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("Test", testWith("Test", "TestSimple"))
|
||||
t.Run("Bench", testWith("Benchmark", "BenchmarkSimple"))
|
||||
t.Run("Example1", testWith("Example", "ExampleSimple"))
|
||||
t.Run("Example2", testWith("Example", "ExampleWithEmptyOutput"))
|
||||
}
|
||||
|
||||
@@ -439,6 +439,11 @@ func downloadPackage(p *load.Package) error {
|
||||
p.Internal.Build.PkgRoot = filepath.Join(list[0], "pkg")
|
||||
}
|
||||
root := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath))
|
||||
|
||||
if err := checkNestedVCS(vcs, root, p.Internal.Build.SrcRoot); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If we've considered this repository already, don't do it again.
|
||||
if downloadRootCache[root] {
|
||||
return nil
|
||||
|
||||
@@ -506,11 +506,28 @@ func vcsFromDir(dir, srcRoot string) (vcs *vcsCmd, root string, err error) {
|
||||
return nil, "", fmt.Errorf("directory %q is outside source root %q", dir, srcRoot)
|
||||
}
|
||||
|
||||
var vcsRet *vcsCmd
|
||||
var rootRet string
|
||||
|
||||
origDir := dir
|
||||
for len(dir) > len(srcRoot) {
|
||||
for _, vcs := range vcsList {
|
||||
if _, err := os.Stat(filepath.Join(dir, "."+vcs.cmd)); err == nil {
|
||||
return vcs, filepath.ToSlash(dir[len(srcRoot)+1:]), nil
|
||||
root := filepath.ToSlash(dir[len(srcRoot)+1:])
|
||||
// Record first VCS we find, but keep looking,
|
||||
// to detect mistakes like one kind of VCS inside another.
|
||||
if vcsRet == nil {
|
||||
vcsRet = vcs
|
||||
rootRet = root
|
||||
continue
|
||||
}
|
||||
// Allow .git inside .git, which can arise due to submodules.
|
||||
if vcsRet == vcs && vcs.cmd == "git" {
|
||||
continue
|
||||
}
|
||||
// Otherwise, we have one VCS inside a different VCS.
|
||||
return nil, "", fmt.Errorf("directory %q uses %s, but parent %q uses %s",
|
||||
filepath.Join(srcRoot, rootRet), vcsRet.cmd, filepath.Join(srcRoot, root), vcs.cmd)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -523,9 +540,48 @@ func vcsFromDir(dir, srcRoot string) (vcs *vcsCmd, root string, err error) {
|
||||
dir = ndir
|
||||
}
|
||||
|
||||
if vcsRet != nil {
|
||||
return vcsRet, rootRet, nil
|
||||
}
|
||||
|
||||
return nil, "", fmt.Errorf("directory %q is not using a known version control system", origDir)
|
||||
}
|
||||
|
||||
// checkNestedVCS checks for an incorrectly-nested VCS-inside-VCS
|
||||
// situation for dir, checking parents up until srcRoot.
|
||||
func checkNestedVCS(vcs *vcsCmd, dir, srcRoot string) error {
|
||||
if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator {
|
||||
return fmt.Errorf("directory %q is outside source root %q", dir, srcRoot)
|
||||
}
|
||||
|
||||
otherDir := dir
|
||||
for len(otherDir) > len(srcRoot) {
|
||||
for _, otherVCS := range vcsList {
|
||||
if _, err := os.Stat(filepath.Join(dir, "."+otherVCS.cmd)); err == nil {
|
||||
// Allow expected vcs in original dir.
|
||||
if otherDir == dir && otherVCS == vcs {
|
||||
continue
|
||||
}
|
||||
// Allow .git inside .git, which can arise due to submodules.
|
||||
if otherVCS == vcs && vcs.cmd == "git" {
|
||||
continue
|
||||
}
|
||||
// Otherwise, we have one VCS inside a different VCS.
|
||||
return fmt.Errorf("directory %q uses %s, but parent %q uses %s", dir, vcs.cmd, otherDir, otherVCS.cmd)
|
||||
}
|
||||
}
|
||||
// Move to parent.
|
||||
newDir := filepath.Dir(otherDir)
|
||||
if len(newDir) >= len(otherDir) {
|
||||
// Shouldn't happen, but just in case, stop.
|
||||
break
|
||||
}
|
||||
otherDir = newDir
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// repoRoot represents a version control system, a repo, and a root of
|
||||
// where to put it on disk.
|
||||
type repoRoot struct {
|
||||
|
||||
14
src/cmd/go/testdata/src/testlist/bench_test.go
vendored
Normal file
14
src/cmd/go/testdata/src/testlist/bench_test.go
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
package testlist
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func BenchmarkSimplefunc(b *testing.B) {
|
||||
b.StopTimer()
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = fmt.Sprint("Test for bench")
|
||||
}
|
||||
}
|
||||
21
src/cmd/go/testdata/src/testlist/example_test.go
vendored
Normal file
21
src/cmd/go/testdata/src/testlist/example_test.go
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
package testlist
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func ExampleSimple() {
|
||||
fmt.Println("Test with Output.")
|
||||
|
||||
// Output: Test with Output.
|
||||
}
|
||||
|
||||
func ExampleWithEmptyOutput() {
|
||||
fmt.Println("")
|
||||
|
||||
// Output:
|
||||
}
|
||||
|
||||
func ExampleNoOutput() {
|
||||
_ = fmt.Sprint("Test with no output")
|
||||
}
|
||||
10
src/cmd/go/testdata/src/testlist/test_test.go
vendored
Normal file
10
src/cmd/go/testdata/src/testlist/test_test.go
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
package testlist
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSimple(t *testing.T) {
|
||||
_ = fmt.Sprint("Test simple")
|
||||
}
|
||||
@@ -15,9 +15,6 @@ import (
|
||||
// InfoPrefix is the prefix for all the symbols containing DWARF info entries.
|
||||
const InfoPrefix = "go.info."
|
||||
|
||||
// RangePrefix is the prefix for all the symbols containing DWARF location lists.
|
||||
const LocPrefix = "go.loc."
|
||||
|
||||
// RangePrefix is the prefix for all the symbols containing DWARF range lists.
|
||||
const RangePrefix = "go.range."
|
||||
|
||||
@@ -26,31 +23,13 @@ type Sym interface {
|
||||
Len() int64
|
||||
}
|
||||
|
||||
// A Location represents a variable's location at a particular PC range.
|
||||
// It becomes a location list entry in the DWARF.
|
||||
type Location struct {
|
||||
StartPC, EndPC int64
|
||||
Pieces []Piece
|
||||
}
|
||||
|
||||
// A Piece represents the location of a particular part of a variable.
|
||||
// It becomes part of a location list entry (a DW_OP_piece) in the DWARF.
|
||||
type Piece struct {
|
||||
Length int64
|
||||
StackOffset int32
|
||||
RegNum int16
|
||||
Missing bool
|
||||
OnStack bool // if true, RegNum is unset.
|
||||
}
|
||||
|
||||
// A Var represents a local variable or a function parameter.
|
||||
type Var struct {
|
||||
Name string
|
||||
Abbrev int // Either DW_ABRV_AUTO or DW_ABRV_PARAM
|
||||
StackOffset int32
|
||||
LocationList []Location
|
||||
Scope int32
|
||||
Type Sym
|
||||
Name string
|
||||
Abbrev int // Either DW_ABRV_AUTO or DW_ABRV_PARAM
|
||||
Offset int32
|
||||
Scope int32
|
||||
Type Sym
|
||||
}
|
||||
|
||||
// A Scope represents a lexical scope. All variables declared within a
|
||||
@@ -226,7 +205,7 @@ const (
|
||||
)
|
||||
|
||||
// Index into the abbrevs table below.
|
||||
// Keep in sync with ispubname() and ispubtype() in ld/dwarf.go.
|
||||
// Keep in sync with ispubname() and ispubtype() below.
|
||||
// ispubtype considers >= NULLTYPE public
|
||||
const (
|
||||
DW_ABRV_NULL = iota
|
||||
@@ -234,9 +213,7 @@ const (
|
||||
DW_ABRV_FUNCTION
|
||||
DW_ABRV_VARIABLE
|
||||
DW_ABRV_AUTO
|
||||
DW_ABRV_AUTO_LOCLIST
|
||||
DW_ABRV_PARAM
|
||||
DW_ABRV_PARAM_LOCLIST
|
||||
DW_ABRV_LEXICAL_BLOCK_RANGES
|
||||
DW_ABRV_LEXICAL_BLOCK_SIMPLE
|
||||
DW_ABRV_STRUCTFIELD
|
||||
@@ -320,17 +297,6 @@ var abbrevs = [DW_NABRV]dwAbbrev{
|
||||
},
|
||||
},
|
||||
|
||||
/* AUTO_LOCLIST */
|
||||
{
|
||||
DW_TAG_variable,
|
||||
DW_CHILDREN_no,
|
||||
[]dwAttrForm{
|
||||
{DW_AT_name, DW_FORM_string},
|
||||
{DW_AT_location, DW_FORM_sec_offset},
|
||||
{DW_AT_type, DW_FORM_ref_addr},
|
||||
},
|
||||
},
|
||||
|
||||
/* PARAM */
|
||||
{
|
||||
DW_TAG_formal_parameter,
|
||||
@@ -341,18 +307,6 @@ var abbrevs = [DW_NABRV]dwAbbrev{
|
||||
{DW_AT_type, DW_FORM_ref_addr},
|
||||
},
|
||||
},
|
||||
|
||||
/* PARAM_LOCLIST */
|
||||
{
|
||||
DW_TAG_formal_parameter,
|
||||
DW_CHILDREN_no,
|
||||
[]dwAttrForm{
|
||||
{DW_AT_name, DW_FORM_string},
|
||||
{DW_AT_location, DW_FORM_sec_offset},
|
||||
{DW_AT_type, DW_FORM_ref_addr},
|
||||
},
|
||||
},
|
||||
|
||||
/* LEXICAL_BLOCK_RANGES */
|
||||
{
|
||||
DW_TAG_lexical_block,
|
||||
@@ -730,30 +684,31 @@ func HasChildren(die *DWDie) bool {
|
||||
|
||||
// PutFunc writes a DIE for a function to s.
|
||||
// It also writes child DIEs for each variable in vars.
|
||||
func PutFunc(ctxt Context, info, loc, ranges Sym, name string, external bool, startPC Sym, size int64, scopes []Scope) error {
|
||||
Uleb128put(ctxt, info, DW_ABRV_FUNCTION)
|
||||
putattr(ctxt, info, DW_ABRV_FUNCTION, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name)
|
||||
putattr(ctxt, info, DW_ABRV_FUNCTION, DW_FORM_addr, DW_CLS_ADDRESS, 0, startPC)
|
||||
putattr(ctxt, info, DW_ABRV_FUNCTION, DW_FORM_addr, DW_CLS_ADDRESS, size, startPC)
|
||||
putattr(ctxt, info, DW_ABRV_FUNCTION, DW_FORM_block1, DW_CLS_BLOCK, 1, []byte{DW_OP_call_frame_cfa})
|
||||
func PutFunc(ctxt Context, s, ranges Sym, name string, external bool, startPC Sym, size int64, scopes []Scope) error {
|
||||
Uleb128put(ctxt, s, DW_ABRV_FUNCTION)
|
||||
putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name)
|
||||
putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_addr, DW_CLS_ADDRESS, 0, startPC)
|
||||
putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_addr, DW_CLS_ADDRESS, size, startPC)
|
||||
putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_block1, DW_CLS_BLOCK, 1, []byte{DW_OP_call_frame_cfa})
|
||||
var ev int64
|
||||
if external {
|
||||
ev = 1
|
||||
}
|
||||
putattr(ctxt, info, DW_ABRV_FUNCTION, DW_FORM_flag, DW_CLS_FLAG, ev, 0)
|
||||
putattr(ctxt, s, DW_ABRV_FUNCTION, DW_FORM_flag, DW_CLS_FLAG, ev, 0)
|
||||
if len(scopes) > 0 {
|
||||
var encbuf [20]byte
|
||||
if putscope(ctxt, info, loc, ranges, startPC, 0, scopes, encbuf[:0]) < int32(len(scopes)) {
|
||||
if putscope(ctxt, s, ranges, startPC, 0, scopes, encbuf[:0]) < int32(len(scopes)) {
|
||||
return errors.New("multiple toplevel scopes")
|
||||
}
|
||||
}
|
||||
Uleb128put(ctxt, info, 0)
|
||||
|
||||
Uleb128put(ctxt, s, 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
func putscope(ctxt Context, info, loc, ranges, startPC Sym, curscope int32, scopes []Scope, encbuf []byte) int32 {
|
||||
func putscope(ctxt Context, s, ranges Sym, startPC Sym, curscope int32, scopes []Scope, encbuf []byte) int32 {
|
||||
for _, v := range scopes[curscope].Vars {
|
||||
putvar(ctxt, info, loc, v, startPC, encbuf)
|
||||
putvar(ctxt, s, v, encbuf)
|
||||
}
|
||||
this := curscope
|
||||
curscope++
|
||||
@@ -764,12 +719,12 @@ func putscope(ctxt Context, info, loc, ranges, startPC Sym, curscope int32, scop
|
||||
}
|
||||
|
||||
if len(scope.Ranges) == 1 {
|
||||
Uleb128put(ctxt, info, DW_ABRV_LEXICAL_BLOCK_SIMPLE)
|
||||
putattr(ctxt, info, DW_ABRV_LEXICAL_BLOCK_SIMPLE, DW_FORM_addr, DW_CLS_ADDRESS, scope.Ranges[0].Start, startPC)
|
||||
putattr(ctxt, info, DW_ABRV_LEXICAL_BLOCK_SIMPLE, DW_FORM_addr, DW_CLS_ADDRESS, scope.Ranges[0].End, startPC)
|
||||
Uleb128put(ctxt, s, DW_ABRV_LEXICAL_BLOCK_SIMPLE)
|
||||
putattr(ctxt, s, DW_ABRV_LEXICAL_BLOCK_SIMPLE, DW_FORM_addr, DW_CLS_ADDRESS, scope.Ranges[0].Start, startPC)
|
||||
putattr(ctxt, s, DW_ABRV_LEXICAL_BLOCK_SIMPLE, DW_FORM_addr, DW_CLS_ADDRESS, scope.Ranges[0].End, startPC)
|
||||
} else {
|
||||
Uleb128put(ctxt, info, DW_ABRV_LEXICAL_BLOCK_RANGES)
|
||||
putattr(ctxt, info, DW_ABRV_LEXICAL_BLOCK_RANGES, DW_FORM_sec_offset, DW_CLS_PTR, ranges.Len(), ranges)
|
||||
Uleb128put(ctxt, s, DW_ABRV_LEXICAL_BLOCK_RANGES)
|
||||
putattr(ctxt, s, DW_ABRV_LEXICAL_BLOCK_RANGES, DW_FORM_sec_offset, DW_CLS_PTR, ranges.Len(), ranges)
|
||||
|
||||
ctxt.AddAddress(ranges, nil, -1)
|
||||
ctxt.AddAddress(ranges, startPC, 0)
|
||||
@@ -781,72 +736,32 @@ func putscope(ctxt Context, info, loc, ranges, startPC Sym, curscope int32, scop
|
||||
ctxt.AddAddress(ranges, nil, 0)
|
||||
}
|
||||
|
||||
curscope = putscope(ctxt, info, loc, ranges, startPC, curscope, scopes, encbuf)
|
||||
curscope = putscope(ctxt, s, ranges, startPC, curscope, scopes, encbuf)
|
||||
|
||||
Uleb128put(ctxt, info, 0)
|
||||
Uleb128put(ctxt, s, 0)
|
||||
}
|
||||
return curscope
|
||||
}
|
||||
|
||||
func putvar(ctxt Context, info, loc Sym, v *Var, startPC Sym, encbuf []byte) {
|
||||
func putvar(ctxt Context, s Sym, v *Var, encbuf []byte) {
|
||||
n := v.Name
|
||||
|
||||
Uleb128put(ctxt, info, int64(v.Abbrev))
|
||||
putattr(ctxt, info, v.Abbrev, DW_FORM_string, DW_CLS_STRING, int64(len(n)), n)
|
||||
if v.Abbrev == DW_ABRV_AUTO_LOCLIST || v.Abbrev == DW_ABRV_PARAM_LOCLIST {
|
||||
putattr(ctxt, info, v.Abbrev, DW_FORM_sec_offset, DW_CLS_PTR, int64(loc.Len()), loc)
|
||||
addLocList(ctxt, loc, startPC, v, encbuf)
|
||||
} else {
|
||||
loc := append(encbuf[:0], DW_OP_call_frame_cfa)
|
||||
if v.StackOffset != 0 {
|
||||
loc = append(loc, DW_OP_consts)
|
||||
loc = AppendSleb128(loc, int64(v.StackOffset))
|
||||
loc = append(loc, DW_OP_plus)
|
||||
}
|
||||
putattr(ctxt, info, v.Abbrev, DW_FORM_block1, DW_CLS_BLOCK, int64(len(loc)), loc)
|
||||
Uleb128put(ctxt, s, int64(v.Abbrev))
|
||||
putattr(ctxt, s, v.Abbrev, DW_FORM_string, DW_CLS_STRING, int64(len(n)), n)
|
||||
loc := append(encbuf[:0], DW_OP_call_frame_cfa)
|
||||
if v.Offset != 0 {
|
||||
loc = append(loc, DW_OP_consts)
|
||||
loc = AppendSleb128(loc, int64(v.Offset))
|
||||
loc = append(loc, DW_OP_plus)
|
||||
}
|
||||
putattr(ctxt, info, v.Abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, v.Type)
|
||||
}
|
||||
|
||||
func addLocList(ctxt Context, listSym, startPC Sym, v *Var, encbuf []byte) {
|
||||
// Base address entry: max ptr followed by the base address.
|
||||
ctxt.AddInt(listSym, ctxt.PtrSize(), ^0)
|
||||
ctxt.AddAddress(listSym, startPC, 0)
|
||||
for _, entry := range v.LocationList {
|
||||
ctxt.AddInt(listSym, ctxt.PtrSize(), entry.StartPC)
|
||||
ctxt.AddInt(listSym, ctxt.PtrSize(), entry.EndPC)
|
||||
locBuf := encbuf[:0]
|
||||
for _, piece := range entry.Pieces {
|
||||
if !piece.Missing {
|
||||
if piece.OnStack {
|
||||
locBuf = append(locBuf, DW_OP_fbreg)
|
||||
locBuf = AppendSleb128(locBuf, int64(piece.StackOffset))
|
||||
} else {
|
||||
if piece.RegNum < 32 {
|
||||
locBuf = append(locBuf, DW_OP_reg0+byte(piece.RegNum))
|
||||
} else {
|
||||
locBuf = append(locBuf, DW_OP_regx)
|
||||
locBuf = AppendUleb128(locBuf, uint64(piece.RegNum))
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(entry.Pieces) > 1 {
|
||||
locBuf = append(locBuf, DW_OP_piece)
|
||||
locBuf = AppendUleb128(locBuf, uint64(piece.Length))
|
||||
}
|
||||
}
|
||||
ctxt.AddInt(listSym, 2, int64(len(locBuf)))
|
||||
ctxt.AddBytes(listSym, locBuf)
|
||||
}
|
||||
// End list
|
||||
ctxt.AddInt(listSym, ctxt.PtrSize(), 0)
|
||||
ctxt.AddInt(listSym, ctxt.PtrSize(), 0)
|
||||
putattr(ctxt, s, v.Abbrev, DW_FORM_block1, DW_CLS_BLOCK, int64(len(loc)), loc)
|
||||
putattr(ctxt, s, v.Abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, v.Type)
|
||||
}
|
||||
|
||||
// VarsByOffset attaches the methods of sort.Interface to []*Var,
|
||||
// sorting in increasing StackOffset.
|
||||
// sorting in increasing Offset.
|
||||
type VarsByOffset []*Var
|
||||
|
||||
func (s VarsByOffset) Len() int { return len(s) }
|
||||
func (s VarsByOffset) Less(i, j int) bool { return s[i].StackOffset < s[j].StackOffset }
|
||||
func (s VarsByOffset) Less(i, j int) bool { return s[i].Offset < s[j].Offset }
|
||||
func (s VarsByOffset) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
@@ -1167,6 +1167,11 @@ func (c *ctxt5) aclass(a *obj.Addr) int {
|
||||
return C_ADDR
|
||||
|
||||
case obj.NAME_AUTO:
|
||||
if a.Reg == REGSP {
|
||||
// unset base register for better printing, since
|
||||
// a.Offset is still relative to pseudo-SP.
|
||||
a.Reg = obj.REG_NONE
|
||||
}
|
||||
c.instoffset = c.autosize + a.Offset
|
||||
if t := immaddr(int32(c.instoffset)); t != 0 {
|
||||
if immhalf(int32(c.instoffset)) {
|
||||
@@ -1185,6 +1190,11 @@ func (c *ctxt5) aclass(a *obj.Addr) int {
|
||||
return C_LAUTO
|
||||
|
||||
case obj.NAME_PARAM:
|
||||
if a.Reg == REGSP {
|
||||
// unset base register for better printing, since
|
||||
// a.Offset is still relative to pseudo-FP.
|
||||
a.Reg = obj.REG_NONE
|
||||
}
|
||||
c.instoffset = c.autosize + a.Offset + 4
|
||||
if t := immaddr(int32(c.instoffset)); t != 0 {
|
||||
if immhalf(int32(c.instoffset)) {
|
||||
@@ -1285,10 +1295,20 @@ func (c *ctxt5) aclass(a *obj.Addr) int {
|
||||
return C_LCONADDR
|
||||
|
||||
case obj.NAME_AUTO:
|
||||
if a.Reg == REGSP {
|
||||
// unset base register for better printing, since
|
||||
// a.Offset is still relative to pseudo-SP.
|
||||
a.Reg = obj.REG_NONE
|
||||
}
|
||||
c.instoffset = c.autosize + a.Offset
|
||||
return c.aconsize()
|
||||
|
||||
case obj.NAME_PARAM:
|
||||
if a.Reg == REGSP {
|
||||
// unset base register for better printing, since
|
||||
// a.Offset is still relative to pseudo-FP.
|
||||
a.Reg = obj.REG_NONE
|
||||
}
|
||||
c.instoffset = c.autosize + a.Offset + 4
|
||||
return c.aconsize()
|
||||
}
|
||||
|
||||
@@ -1149,10 +1149,20 @@ func (c *ctxt7) aclass(a *obj.Addr) int {
|
||||
return C_GOTADDR
|
||||
|
||||
case obj.NAME_AUTO:
|
||||
if a.Reg == REGSP {
|
||||
// unset base register for better printing, since
|
||||
// a.Offset is still relative to pseudo-SP.
|
||||
a.Reg = obj.REG_NONE
|
||||
}
|
||||
c.instoffset = int64(c.autosize) + a.Offset
|
||||
return autoclass(c.instoffset)
|
||||
|
||||
case obj.NAME_PARAM:
|
||||
if a.Reg == REGSP {
|
||||
// unset base register for better printing, since
|
||||
// a.Offset is still relative to pseudo-FP.
|
||||
a.Reg = obj.REG_NONE
|
||||
}
|
||||
c.instoffset = int64(c.autosize) + a.Offset + 8
|
||||
return autoclass(c.instoffset)
|
||||
|
||||
@@ -1228,10 +1238,20 @@ func (c *ctxt7) aclass(a *obj.Addr) int {
|
||||
return C_VCONADDR
|
||||
|
||||
case obj.NAME_AUTO:
|
||||
if a.Reg == REGSP {
|
||||
// unset base register for better printing, since
|
||||
// a.Offset is still relative to pseudo-SP.
|
||||
a.Reg = obj.REG_NONE
|
||||
}
|
||||
c.instoffset = int64(c.autosize) + a.Offset
|
||||
goto aconsize
|
||||
|
||||
case obj.NAME_PARAM:
|
||||
if a.Reg == REGSP {
|
||||
// unset base register for better printing, since
|
||||
// a.Offset is still relative to pseudo-FP.
|
||||
a.Reg = obj.REG_NONE
|
||||
}
|
||||
c.instoffset = int64(c.autosize) + a.Offset + 8
|
||||
goto aconsize
|
||||
}
|
||||
|
||||
@@ -330,8 +330,7 @@ type FuncInfo struct {
|
||||
Autom []*Auto
|
||||
Pcln Pcln
|
||||
|
||||
dwarfInfoSym *LSym
|
||||
dwarfLocSym *LSym
|
||||
dwarfSym *LSym
|
||||
dwarfRangesSym *LSym
|
||||
|
||||
GCArgs LSym
|
||||
@@ -477,26 +476,25 @@ type Pcdata struct {
|
||||
// Link holds the context for writing object code from a compiler
|
||||
// to be linker input or for reading that input into the linker.
|
||||
type Link struct {
|
||||
Headtype objabi.HeadType
|
||||
Arch *LinkArch
|
||||
Debugasm bool
|
||||
Debugvlog bool
|
||||
Debugpcln string
|
||||
Flag_shared bool
|
||||
Flag_dynlink bool
|
||||
Flag_optimize bool
|
||||
Flag_locationlists bool
|
||||
Bso *bufio.Writer
|
||||
Pathname string
|
||||
hashmu sync.Mutex // protects hash
|
||||
hash map[string]*LSym // name -> sym mapping
|
||||
statichash map[string]*LSym // name -> sym mapping for static syms
|
||||
PosTable src.PosTable
|
||||
InlTree InlTree // global inlining tree used by gc/inl.go
|
||||
Imports []string
|
||||
DiagFunc func(string, ...interface{})
|
||||
DebugInfo func(fn *LSym, curfn interface{}) []dwarf.Scope // if non-nil, curfn is a *gc.Node
|
||||
Errors int
|
||||
Headtype objabi.HeadType
|
||||
Arch *LinkArch
|
||||
Debugasm bool
|
||||
Debugvlog bool
|
||||
Debugpcln string
|
||||
Flag_shared bool
|
||||
Flag_dynlink bool
|
||||
Flag_optimize bool
|
||||
Bso *bufio.Writer
|
||||
Pathname string
|
||||
hashmu sync.Mutex // protects hash
|
||||
hash map[string]*LSym // name -> sym mapping
|
||||
statichash map[string]*LSym // name -> sym mapping for static syms
|
||||
PosTable src.PosTable
|
||||
InlTree InlTree // global inlining tree used by gc/inl.go
|
||||
Imports []string
|
||||
DiagFunc func(string, ...interface{})
|
||||
DebugInfo func(fn *LSym, curfn interface{}) []dwarf.Scope // if non-nil, curfn is a *gc.Node
|
||||
Errors int
|
||||
|
||||
Framepointer_enabled bool
|
||||
|
||||
@@ -535,10 +533,9 @@ func (ctxt *Link) FixedFrameSize() int64 {
|
||||
// LinkArch is the definition of a single architecture.
|
||||
type LinkArch struct {
|
||||
*sys.Arch
|
||||
Init func(*Link)
|
||||
Preprocess func(*Link, *LSym, ProgAlloc)
|
||||
Assemble func(*Link, *LSym, ProgAlloc)
|
||||
Progedit func(*Link, *Prog, ProgAlloc)
|
||||
UnaryDst map[As]bool // Instruction takes one operand, a destination.
|
||||
DWARFRegisters map[int16]int16
|
||||
Init func(*Link)
|
||||
Preprocess func(*Link, *LSym, ProgAlloc)
|
||||
Assemble func(*Link, *LSym, ProgAlloc)
|
||||
Progedit func(*Link, *Prog, ProgAlloc)
|
||||
UnaryDst map[As]bool // Instruction takes one operand, a destination.
|
||||
}
|
||||
|
||||
@@ -556,6 +556,11 @@ func (c *ctxt0) aclass(a *obj.Addr) int {
|
||||
return C_LEXT
|
||||
|
||||
case obj.NAME_AUTO:
|
||||
if a.Reg == REGSP {
|
||||
// unset base register for better printing, since
|
||||
// a.Offset is still relative to pseudo-SP.
|
||||
a.Reg = obj.REG_NONE
|
||||
}
|
||||
c.instoffset = int64(c.autosize) + a.Offset
|
||||
if c.instoffset >= -BIG && c.instoffset < BIG {
|
||||
return C_SAUTO
|
||||
@@ -563,6 +568,11 @@ func (c *ctxt0) aclass(a *obj.Addr) int {
|
||||
return C_LAUTO
|
||||
|
||||
case obj.NAME_PARAM:
|
||||
if a.Reg == REGSP {
|
||||
// unset base register for better printing, since
|
||||
// a.Offset is still relative to pseudo-FP.
|
||||
a.Reg = obj.REG_NONE
|
||||
}
|
||||
c.instoffset = int64(c.autosize) + a.Offset + c.ctxt.FixedFrameSize()
|
||||
if c.instoffset >= -BIG && c.instoffset < BIG {
|
||||
return C_SAUTO
|
||||
@@ -616,6 +626,11 @@ func (c *ctxt0) aclass(a *obj.Addr) int {
|
||||
return C_LECON
|
||||
|
||||
case obj.NAME_AUTO:
|
||||
if a.Reg == REGSP {
|
||||
// unset base register for better printing, since
|
||||
// a.Offset is still relative to pseudo-SP.
|
||||
a.Reg = obj.REG_NONE
|
||||
}
|
||||
c.instoffset = int64(c.autosize) + a.Offset
|
||||
if c.instoffset >= -BIG && c.instoffset < BIG {
|
||||
return C_SACON
|
||||
@@ -623,6 +638,11 @@ func (c *ctxt0) aclass(a *obj.Addr) int {
|
||||
return C_LACON
|
||||
|
||||
case obj.NAME_PARAM:
|
||||
if a.Reg == REGSP {
|
||||
// unset base register for better printing, since
|
||||
// a.Offset is still relative to pseudo-FP.
|
||||
a.Reg = obj.REG_NONE
|
||||
}
|
||||
c.instoffset = int64(c.autosize) + a.Offset + c.ctxt.FixedFrameSize()
|
||||
if c.instoffset >= -BIG && c.instoffset < BIG {
|
||||
return C_SACON
|
||||
|
||||
@@ -465,18 +465,15 @@ func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64
|
||||
}
|
||||
|
||||
// dwarfSym returns the DWARF symbols for TEXT symbol.
|
||||
func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym *LSym) {
|
||||
func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfRangesSym *LSym) {
|
||||
if s.Type != objabi.STEXT {
|
||||
ctxt.Diag("dwarfSym of non-TEXT %v", s)
|
||||
}
|
||||
if s.Func.dwarfInfoSym == nil {
|
||||
s.Func.dwarfInfoSym = ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name)
|
||||
if ctxt.Flag_locationlists {
|
||||
s.Func.dwarfLocSym = ctxt.LookupDerived(s, dwarf.LocPrefix+s.Name)
|
||||
}
|
||||
if s.Func.dwarfSym == nil {
|
||||
s.Func.dwarfSym = ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name)
|
||||
s.Func.dwarfRangesSym = ctxt.LookupDerived(s, dwarf.RangePrefix+s.Name)
|
||||
}
|
||||
return s.Func.dwarfInfoSym, s.Func.dwarfLocSym, s.Func.dwarfRangesSym
|
||||
return s.Func.dwarfSym, s.Func.dwarfRangesSym
|
||||
}
|
||||
|
||||
func (s *LSym) Len() int64 {
|
||||
@@ -486,15 +483,15 @@ func (s *LSym) Len() int64 {
|
||||
// populateDWARF fills in the DWARF Debugging Information Entries for TEXT symbol s.
|
||||
// The DWARFs symbol must already have been initialized in InitTextSym.
|
||||
func (ctxt *Link) populateDWARF(curfn interface{}, s *LSym) {
|
||||
info, loc, ranges := ctxt.dwarfSym(s)
|
||||
if info.Size != 0 {
|
||||
dsym, drsym := ctxt.dwarfSym(s)
|
||||
if dsym.Size != 0 {
|
||||
ctxt.Diag("makeFuncDebugEntry double process %v", s)
|
||||
}
|
||||
var scopes []dwarf.Scope
|
||||
if ctxt.DebugInfo != nil {
|
||||
scopes = ctxt.DebugInfo(s, curfn)
|
||||
}
|
||||
err := dwarf.PutFunc(dwCtxt{ctxt}, info, loc, ranges, s.Name, !s.Static(), s, s.Size, scopes)
|
||||
err := dwarf.PutFunc(dwCtxt{ctxt}, dsym, drsym, s.Name, !s.Static(), s, s.Size, scopes)
|
||||
if err != nil {
|
||||
ctxt.Diag("emitting DWARF for %s failed: %v", s.Name, err)
|
||||
}
|
||||
|
||||
@@ -136,17 +136,13 @@ func (ctxt *Link) InitTextSym(s *LSym, flag int) {
|
||||
ctxt.Text = append(ctxt.Text, s)
|
||||
|
||||
// Set up DWARF entries for s.
|
||||
info, loc, ranges := ctxt.dwarfSym(s)
|
||||
info.Type = objabi.SDWARFINFO
|
||||
info.Set(AttrDuplicateOK, s.DuplicateOK())
|
||||
if loc != nil {
|
||||
loc.Type = objabi.SDWARFLOC
|
||||
loc.Set(AttrDuplicateOK, s.DuplicateOK())
|
||||
ctxt.Data = append(ctxt.Data, loc)
|
||||
}
|
||||
ranges.Type = objabi.SDWARFRANGE
|
||||
ranges.Set(AttrDuplicateOK, s.DuplicateOK())
|
||||
ctxt.Data = append(ctxt.Data, info, ranges)
|
||||
dsym, drsym := ctxt.dwarfSym(s)
|
||||
dsym.Type = objabi.SDWARFINFO
|
||||
dsym.Set(AttrDuplicateOK, s.DuplicateOK())
|
||||
drsym.Type = objabi.SDWARFRANGE
|
||||
drsym.Set(AttrDuplicateOK, s.DuplicateOK())
|
||||
ctxt.Data = append(ctxt.Data, dsym)
|
||||
ctxt.Data = append(ctxt.Data, drsym)
|
||||
|
||||
// Set up the function's gcargs and gclocals.
|
||||
// They will be filled in later if needed.
|
||||
|
||||
@@ -758,6 +758,11 @@ func (c *ctxt9) aclass(a *obj.Addr) int {
|
||||
return C_GOTADDR
|
||||
|
||||
case obj.NAME_AUTO:
|
||||
if a.Reg == REGSP {
|
||||
// unset base register for better printing, since
|
||||
// a.Offset is still relative to pseudo-SP.
|
||||
a.Reg = obj.REG_NONE
|
||||
}
|
||||
c.instoffset = int64(c.autosize) + a.Offset
|
||||
if c.instoffset >= -BIG && c.instoffset < BIG {
|
||||
return C_SAUTO
|
||||
@@ -765,6 +770,11 @@ func (c *ctxt9) aclass(a *obj.Addr) int {
|
||||
return C_LAUTO
|
||||
|
||||
case obj.NAME_PARAM:
|
||||
if a.Reg == REGSP {
|
||||
// unset base register for better printing, since
|
||||
// a.Offset is still relative to pseudo-FP.
|
||||
a.Reg = obj.REG_NONE
|
||||
}
|
||||
c.instoffset = int64(c.autosize) + a.Offset + c.ctxt.FixedFrameSize()
|
||||
if c.instoffset >= -BIG && c.instoffset < BIG {
|
||||
return C_SAUTO
|
||||
@@ -817,6 +827,11 @@ func (c *ctxt9) aclass(a *obj.Addr) int {
|
||||
return C_LCON
|
||||
|
||||
case obj.NAME_AUTO:
|
||||
if a.Reg == REGSP {
|
||||
// unset base register for better printing, since
|
||||
// a.Offset is still relative to pseudo-SP.
|
||||
a.Reg = obj.REG_NONE
|
||||
}
|
||||
c.instoffset = int64(c.autosize) + a.Offset
|
||||
if c.instoffset >= -BIG && c.instoffset < BIG {
|
||||
return C_SACON
|
||||
@@ -824,6 +839,11 @@ func (c *ctxt9) aclass(a *obj.Addr) int {
|
||||
return C_LACON
|
||||
|
||||
case obj.NAME_PARAM:
|
||||
if a.Reg == REGSP {
|
||||
// unset base register for better printing, since
|
||||
// a.Offset is still relative to pseudo-FP.
|
||||
a.Reg = obj.REG_NONE
|
||||
}
|
||||
c.instoffset = int64(c.autosize) + a.Offset + c.ctxt.FixedFrameSize()
|
||||
if c.instoffset >= -BIG && c.instoffset < BIG {
|
||||
return C_SACON
|
||||
|
||||
@@ -505,6 +505,11 @@ func (c *ctxtz) aclass(a *obj.Addr) int {
|
||||
return C_GOTADDR
|
||||
|
||||
case obj.NAME_AUTO:
|
||||
if a.Reg == REGSP {
|
||||
// unset base register for better printing, since
|
||||
// a.Offset is still relative to pseudo-SP.
|
||||
a.Reg = obj.REG_NONE
|
||||
}
|
||||
c.instoffset = int64(c.autosize) + a.Offset
|
||||
if c.instoffset >= -BIG && c.instoffset < BIG {
|
||||
return C_SAUTO
|
||||
@@ -512,6 +517,11 @@ func (c *ctxtz) aclass(a *obj.Addr) int {
|
||||
return C_LAUTO
|
||||
|
||||
case obj.NAME_PARAM:
|
||||
if a.Reg == REGSP {
|
||||
// unset base register for better printing, since
|
||||
// a.Offset is still relative to pseudo-FP.
|
||||
a.Reg = obj.REG_NONE
|
||||
}
|
||||
c.instoffset = int64(c.autosize) + a.Offset + c.ctxt.FixedFrameSize()
|
||||
if c.instoffset >= -BIG && c.instoffset < BIG {
|
||||
return C_SAUTO
|
||||
@@ -567,6 +577,11 @@ func (c *ctxtz) aclass(a *obj.Addr) int {
|
||||
return C_SYMADDR
|
||||
|
||||
case obj.NAME_AUTO:
|
||||
if a.Reg == REGSP {
|
||||
// unset base register for better printing, since
|
||||
// a.Offset is still relative to pseudo-SP.
|
||||
a.Reg = obj.REG_NONE
|
||||
}
|
||||
c.instoffset = int64(c.autosize) + a.Offset
|
||||
if c.instoffset >= -BIG && c.instoffset < BIG {
|
||||
return C_SACON
|
||||
@@ -574,6 +589,11 @@ func (c *ctxtz) aclass(a *obj.Addr) int {
|
||||
return C_LACON
|
||||
|
||||
case obj.NAME_PARAM:
|
||||
if a.Reg == REGSP {
|
||||
// unset base register for better printing, since
|
||||
// a.Offset is still relative to pseudo-FP.
|
||||
a.Reg = obj.REG_NONE
|
||||
}
|
||||
c.instoffset = int64(c.autosize) + a.Offset + c.ctxt.FixedFrameSize()
|
||||
if c.instoffset >= -BIG && c.instoffset < BIG {
|
||||
return C_SACON
|
||||
|
||||
@@ -1006,120 +1006,3 @@ const (
|
||||
T_64 = 1 << 6
|
||||
T_GOTYPE = 1 << 7
|
||||
)
|
||||
|
||||
// https://www.uclibc.org/docs/psABI-x86_64.pdf, figure 3.36
|
||||
var AMD64DWARFRegisters = map[int16]int16{
|
||||
REG_AX: 0,
|
||||
REG_DX: 1,
|
||||
REG_CX: 2,
|
||||
REG_BX: 3,
|
||||
REG_SI: 4,
|
||||
REG_DI: 5,
|
||||
REG_BP: 6,
|
||||
REG_SP: 7,
|
||||
REG_R8: 8,
|
||||
REG_R9: 9,
|
||||
REG_R10: 10,
|
||||
REG_R11: 11,
|
||||
REG_R12: 12,
|
||||
REG_R13: 13,
|
||||
REG_R14: 14,
|
||||
REG_R15: 15,
|
||||
// 16 is "Return Address RA", whatever that is.
|
||||
// XMM registers. %xmmN => XN.
|
||||
REG_X0: 17,
|
||||
REG_X1: 18,
|
||||
REG_X2: 19,
|
||||
REG_X3: 20,
|
||||
REG_X4: 21,
|
||||
REG_X5: 22,
|
||||
REG_X6: 23,
|
||||
REG_X7: 24,
|
||||
REG_X8: 25,
|
||||
REG_X9: 26,
|
||||
REG_X10: 27,
|
||||
REG_X11: 28,
|
||||
REG_X12: 29,
|
||||
REG_X13: 30,
|
||||
REG_X14: 31,
|
||||
REG_X15: 32,
|
||||
// ST registers. %stN => FN.
|
||||
REG_F0: 33,
|
||||
REG_F1: 34,
|
||||
REG_F2: 35,
|
||||
REG_F3: 36,
|
||||
REG_F4: 37,
|
||||
REG_F5: 38,
|
||||
REG_F6: 39,
|
||||
REG_F7: 40,
|
||||
// MMX registers. %mmN => MN.
|
||||
REG_M0: 41,
|
||||
REG_M1: 42,
|
||||
REG_M2: 43,
|
||||
REG_M3: 44,
|
||||
REG_M4: 45,
|
||||
REG_M5: 46,
|
||||
REG_M6: 47,
|
||||
REG_M7: 48,
|
||||
// 48 is flags, which doesn't have a name.
|
||||
REG_ES: 50,
|
||||
REG_CS: 51,
|
||||
REG_SS: 52,
|
||||
REG_DS: 53,
|
||||
REG_FS: 54,
|
||||
REG_GS: 55,
|
||||
// 58 and 59 are {fs,gs}base, which don't have names.
|
||||
REG_TR: 62,
|
||||
REG_LDTR: 63,
|
||||
// 64-66 are mxcsr, fcw, fsw, which don't have names.
|
||||
}
|
||||
|
||||
// https://www.uclibc.org/docs/psABI-i386.pdf, table 2.14
|
||||
var X86DWARFRegisters = map[int16]int16{
|
||||
REG_AX: 0,
|
||||
REG_CX: 1,
|
||||
REG_DX: 2,
|
||||
REG_BX: 3,
|
||||
REG_SP: 4,
|
||||
REG_BP: 5,
|
||||
REG_SI: 6,
|
||||
REG_DI: 7,
|
||||
// 8 is "Return Address RA", whatever that is.
|
||||
// 9 is flags, which doesn't have a name.
|
||||
// ST registers. %stN => FN.
|
||||
REG_F0: 11,
|
||||
REG_F1: 12,
|
||||
REG_F2: 13,
|
||||
REG_F3: 14,
|
||||
REG_F4: 15,
|
||||
REG_F5: 16,
|
||||
REG_F6: 17,
|
||||
REG_F7: 18,
|
||||
// XMM registers. %xmmN => XN.
|
||||
REG_X0: 21,
|
||||
REG_X1: 22,
|
||||
REG_X2: 23,
|
||||
REG_X3: 24,
|
||||
REG_X4: 25,
|
||||
REG_X5: 26,
|
||||
REG_X6: 27,
|
||||
REG_X7: 28,
|
||||
// MMX registers. %mmN => MN.
|
||||
REG_M0: 29,
|
||||
REG_M1: 30,
|
||||
REG_M2: 31,
|
||||
REG_M3: 32,
|
||||
REG_M4: 33,
|
||||
REG_M5: 34,
|
||||
REG_M6: 35,
|
||||
REG_M7: 36,
|
||||
// 39 is mxcsr, which doesn't have a name.
|
||||
REG_ES: 40,
|
||||
REG_CS: 41,
|
||||
REG_SS: 42,
|
||||
REG_DS: 43,
|
||||
REG_FS: 44,
|
||||
REG_GS: 45,
|
||||
REG_TR: 48,
|
||||
REG_LDTR: 49,
|
||||
}
|
||||
|
||||
@@ -1231,31 +1231,28 @@ var unaryDst = map[obj.As]bool{
|
||||
}
|
||||
|
||||
var Linkamd64 = obj.LinkArch{
|
||||
Arch: sys.ArchAMD64,
|
||||
Init: instinit,
|
||||
Preprocess: preprocess,
|
||||
Assemble: span6,
|
||||
Progedit: progedit,
|
||||
UnaryDst: unaryDst,
|
||||
DWARFRegisters: AMD64DWARFRegisters,
|
||||
Arch: sys.ArchAMD64,
|
||||
Init: instinit,
|
||||
Preprocess: preprocess,
|
||||
Assemble: span6,
|
||||
Progedit: progedit,
|
||||
UnaryDst: unaryDst,
|
||||
}
|
||||
|
||||
var Linkamd64p32 = obj.LinkArch{
|
||||
Arch: sys.ArchAMD64P32,
|
||||
Init: instinit,
|
||||
Preprocess: preprocess,
|
||||
Assemble: span6,
|
||||
Progedit: progedit,
|
||||
UnaryDst: unaryDst,
|
||||
DWARFRegisters: AMD64DWARFRegisters,
|
||||
Arch: sys.ArchAMD64P32,
|
||||
Init: instinit,
|
||||
Preprocess: preprocess,
|
||||
Assemble: span6,
|
||||
Progedit: progedit,
|
||||
UnaryDst: unaryDst,
|
||||
}
|
||||
|
||||
var Link386 = obj.LinkArch{
|
||||
Arch: sys.Arch386,
|
||||
Init: instinit,
|
||||
Preprocess: preprocess,
|
||||
Assemble: span6,
|
||||
Progedit: progedit,
|
||||
UnaryDst: unaryDst,
|
||||
DWARFRegisters: AMD64DWARFRegisters,
|
||||
Arch: sys.Arch386,
|
||||
Init: instinit,
|
||||
Preprocess: preprocess,
|
||||
Assemble: span6,
|
||||
Progedit: progedit,
|
||||
UnaryDst: unaryDst,
|
||||
}
|
||||
|
||||
@@ -57,5 +57,4 @@ const (
|
||||
// Debugging data
|
||||
SDWARFINFO
|
||||
SDWARFRANGE
|
||||
SDWARFLOC
|
||||
)
|
||||
|
||||
@@ -4,9 +4,9 @@ package objabi
|
||||
|
||||
import "fmt"
|
||||
|
||||
const _SymKind_name = "SxxxSTEXTSRODATASNOPTRDATASDATASBSSSNOPTRBSSSTLSBSSSDWARFINFOSDWARFRANGESDWARFLOC"
|
||||
const _SymKind_name = "SxxxSTEXTSRODATASNOPTRDATASDATASBSSSNOPTRBSSSTLSBSSSDWARFINFOSDWARFRANGE"
|
||||
|
||||
var _SymKind_index = [...]uint8{0, 4, 9, 16, 26, 31, 35, 44, 51, 61, 72, 81}
|
||||
var _SymKind_index = [...]uint8{0, 4, 9, 16, 26, 31, 35, 44, 51, 61, 72}
|
||||
|
||||
func (i SymKind) String() string {
|
||||
if i >= SymKind(len(_SymKind_index)-1) {
|
||||
|
||||
@@ -592,7 +592,15 @@ func relocsym(ctxt *Link, s *Symbol) {
|
||||
}
|
||||
|
||||
case objabi.R_DWARFREF:
|
||||
if r.Sym.Sect == nil {
|
||||
var sectName string
|
||||
var vaddr int64
|
||||
switch {
|
||||
case r.Sym.Sect != nil:
|
||||
sectName = r.Sym.Sect.Name
|
||||
vaddr = int64(r.Sym.Sect.Vaddr)
|
||||
case r.Sym.Type == SDWARFRANGE:
|
||||
sectName = ".debug_ranges"
|
||||
default:
|
||||
Errorf(s, "missing DWARF section for relocation target %s", r.Sym.Name)
|
||||
}
|
||||
|
||||
@@ -607,8 +615,8 @@ func relocsym(ctxt *Link, s *Symbol) {
|
||||
r.Type = objabi.R_ADDR
|
||||
}
|
||||
|
||||
r.Xsym = ctxt.Syms.ROLookup(r.Sym.Sect.Name, 0)
|
||||
r.Xadd = r.Add + Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr)
|
||||
r.Xsym = ctxt.Syms.ROLookup(sectName, 0)
|
||||
r.Xadd = r.Add + Symaddr(r.Sym) - vaddr
|
||||
|
||||
o = r.Xadd
|
||||
rs = r.Xsym
|
||||
@@ -617,7 +625,7 @@ func relocsym(ctxt *Link, s *Symbol) {
|
||||
}
|
||||
break
|
||||
}
|
||||
o = Symaddr(r.Sym) + r.Add - int64(r.Sym.Sect.Vaddr)
|
||||
o = Symaddr(r.Sym) + r.Add - vaddr
|
||||
|
||||
case objabi.R_WEAKADDROFF:
|
||||
if !r.Sym.Attr.Reachable() {
|
||||
@@ -1835,9 +1843,9 @@ func (ctxt *Link) dodata() {
|
||||
|
||||
dwarfgeneratedebugsyms(ctxt)
|
||||
|
||||
var s *Symbol
|
||||
var i int
|
||||
for ; i < len(dwarfp); i++ {
|
||||
s := dwarfp[i]
|
||||
for i, s = range dwarfp {
|
||||
if s.Type != SDWARFSECT {
|
||||
break
|
||||
}
|
||||
@@ -1854,26 +1862,13 @@ func (ctxt *Link) dodata() {
|
||||
}
|
||||
checkdatsize(ctxt, datsize, SDWARFSECT)
|
||||
|
||||
for i < len(dwarfp) {
|
||||
curType := dwarfp[i].Type
|
||||
var sect *Section
|
||||
switch curType {
|
||||
case SDWARFINFO:
|
||||
sect = addsection(&Segdwarf, ".debug_info", 04)
|
||||
case SDWARFRANGE:
|
||||
sect = addsection(&Segdwarf, ".debug_ranges", 04)
|
||||
case SDWARFLOC:
|
||||
sect = addsection(&Segdwarf, ".debug_loc", 04)
|
||||
default:
|
||||
Errorf(dwarfp[i], "unknown DWARF section %v", curType)
|
||||
}
|
||||
|
||||
if i < len(dwarfp) {
|
||||
sect = addsection(&Segdwarf, ".debug_info", 04)
|
||||
sect.Align = 1
|
||||
datsize = Rnd(datsize, int64(sect.Align))
|
||||
sect.Vaddr = uint64(datsize)
|
||||
for ; i < len(dwarfp); i++ {
|
||||
s := dwarfp[i]
|
||||
if s.Type != curType {
|
||||
for _, s := range dwarfp[i:] {
|
||||
if s.Type != SDWARFINFO {
|
||||
break
|
||||
}
|
||||
s.Sect = sect
|
||||
@@ -1883,7 +1878,7 @@ func (ctxt *Link) dodata() {
|
||||
datsize += s.Size
|
||||
}
|
||||
sect.Length = uint64(datsize) - sect.Vaddr
|
||||
checkdatsize(ctxt, datsize, curType)
|
||||
checkdatsize(ctxt, datsize, SDWARFINFO)
|
||||
}
|
||||
|
||||
/* number the sections */
|
||||
|
||||
@@ -67,15 +67,26 @@ func (c dwctxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64
|
||||
r.Add = ofs
|
||||
}
|
||||
|
||||
/*
|
||||
* Offsets and sizes of the debug_* sections in the cout file.
|
||||
*/
|
||||
var abbrevsym *Symbol
|
||||
var arangessec *Symbol
|
||||
var framesec *Symbol
|
||||
var infosec *Symbol
|
||||
var linesec *Symbol
|
||||
var rangesec *Symbol
|
||||
|
||||
var gdbscript string
|
||||
|
||||
var dwarfp []*Symbol
|
||||
|
||||
func writeabbrev(ctxt *Link) *Symbol {
|
||||
func writeabbrev(ctxt *Link, syms []*Symbol) []*Symbol {
|
||||
s := ctxt.Syms.Lookup(".debug_abbrev", 0)
|
||||
s.Type = SDWARFSECT
|
||||
abbrevsym = s
|
||||
Addbytes(s, dwarf.GetAbbrev())
|
||||
return s
|
||||
return append(syms, s)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -982,10 +993,13 @@ func getCompilationDir() string {
|
||||
|
||||
func writelines(ctxt *Link, syms []*Symbol) ([]*Symbol, []*Symbol) {
|
||||
var dwarfctxt dwarf.Context = dwctxt{ctxt}
|
||||
ls := ctxt.Syms.Lookup(".debug_line", 0)
|
||||
ls.Type = SDWARFSECT
|
||||
ls.R = ls.R[:0]
|
||||
if linesec == nil {
|
||||
linesec = ctxt.Syms.Lookup(".debug_line", 0)
|
||||
}
|
||||
linesec.Type = SDWARFSECT
|
||||
linesec.R = linesec.R[:0]
|
||||
|
||||
ls := linesec
|
||||
syms = append(syms, ls)
|
||||
var funcs []*Symbol
|
||||
|
||||
@@ -1005,7 +1019,7 @@ func writelines(ctxt *Link, syms []*Symbol) ([]*Symbol, []*Symbol) {
|
||||
|
||||
dwinfo = newdie(ctxt, &dwroot, dwarf.DW_ABRV_COMPUNIT, "go", 0)
|
||||
newattr(dwinfo, dwarf.DW_AT_language, dwarf.DW_CLS_CONSTANT, int64(lang), 0)
|
||||
newattr(dwinfo, dwarf.DW_AT_stmt_list, dwarf.DW_CLS_PTR, 0, ls)
|
||||
newattr(dwinfo, dwarf.DW_AT_stmt_list, dwarf.DW_CLS_PTR, 0, linesec)
|
||||
newattr(dwinfo, dwarf.DW_AT_low_pc, dwarf.DW_CLS_ADDRESS, s.Value, s)
|
||||
// OS X linker requires compilation dir or absolute path in comp unit name to output debug info.
|
||||
compDir := getCompilationDir()
|
||||
@@ -1164,9 +1178,12 @@ func appendPCDeltaCFA(b []byte, deltapc, cfa int64) []byte {
|
||||
|
||||
func writeframes(ctxt *Link, syms []*Symbol) []*Symbol {
|
||||
var dwarfctxt dwarf.Context = dwctxt{ctxt}
|
||||
fs := ctxt.Syms.Lookup(".debug_frame", 0)
|
||||
fs.Type = SDWARFSECT
|
||||
fs.R = fs.R[:0]
|
||||
if framesec == nil {
|
||||
framesec = ctxt.Syms.Lookup(".debug_frame", 0)
|
||||
}
|
||||
framesec.Type = SDWARFSECT
|
||||
framesec.R = framesec.R[:0]
|
||||
fs := framesec
|
||||
syms = append(syms, fs)
|
||||
|
||||
// Emit the CIE, Section 6.4.1
|
||||
@@ -1263,7 +1280,7 @@ func writeframes(ctxt *Link, syms []*Symbol) []*Symbol {
|
||||
// ptrsize: address range
|
||||
Adduint32(ctxt, fs, uint32(4+2*SysArch.PtrSize+len(deltaBuf))) // length (excludes itself)
|
||||
if Linkmode == LinkExternal {
|
||||
adddwarfref(ctxt, fs, fs, 4)
|
||||
adddwarfref(ctxt, fs, framesec, 4)
|
||||
} else {
|
||||
Adduint32(ctxt, fs, 0) // CIE offset
|
||||
}
|
||||
@@ -1275,24 +1292,27 @@ func writeframes(ctxt *Link, syms []*Symbol) []*Symbol {
|
||||
}
|
||||
|
||||
func writeranges(ctxt *Link, syms []*Symbol) []*Symbol {
|
||||
empty := true
|
||||
if rangesec == nil {
|
||||
rangesec = ctxt.Syms.Lookup(".debug_ranges", 0)
|
||||
}
|
||||
rangesec.Type = SDWARFSECT
|
||||
rangesec.Attr |= AttrReachable
|
||||
rangesec.R = rangesec.R[:0]
|
||||
|
||||
for _, s := range ctxt.Textp {
|
||||
rangeSym := ctxt.Syms.Lookup(dwarf.RangePrefix+s.Name, int(s.Version))
|
||||
if rangeSym.Size == 0 {
|
||||
continue
|
||||
}
|
||||
rangeSym.Attr |= AttrReachable | AttrNotInSymbolTable
|
||||
rangeSym.Attr |= AttrReachable
|
||||
rangeSym.Type = SDWARFRANGE
|
||||
syms = append(syms, rangeSym)
|
||||
empty = false
|
||||
rangeSym.Value = rangesec.Size
|
||||
rangesec.P = append(rangesec.P, rangeSym.P...)
|
||||
for _, r := range rangeSym.R {
|
||||
r.Off += int32(rangesec.Size)
|
||||
rangesec.R = append(rangesec.R, r)
|
||||
}
|
||||
rangesec.Size += rangeSym.Size
|
||||
}
|
||||
if !empty {
|
||||
if rangesec.Size > 0 {
|
||||
// PE does not like empty sections
|
||||
rangesec := ctxt.Syms.Lookup(".debug_ranges", 0)
|
||||
rangesec.Type = SDWARFRANGE
|
||||
rangesec.Attr |= AttrReachable
|
||||
rangesec.R = rangesec.R[:0]
|
||||
|
||||
syms = append(syms, rangesec)
|
||||
}
|
||||
return syms
|
||||
@@ -1305,14 +1325,18 @@ const (
|
||||
COMPUNITHEADERSIZE = 4 + 2 + 4 + 1
|
||||
)
|
||||
|
||||
func writeinfo(ctxt *Link, syms []*Symbol, funcs []*Symbol, abbrevsym *Symbol) []*Symbol {
|
||||
infosec := ctxt.Syms.Lookup(".debug_info", 0)
|
||||
func writeinfo(ctxt *Link, syms []*Symbol, funcs []*Symbol) []*Symbol {
|
||||
if infosec == nil {
|
||||
infosec = ctxt.Syms.Lookup(".debug_info", 0)
|
||||
}
|
||||
infosec.R = infosec.R[:0]
|
||||
infosec.Type = SDWARFINFO
|
||||
infosec.Attr |= AttrReachable
|
||||
syms = append(syms, infosec)
|
||||
|
||||
arangessec := ctxt.Syms.Lookup(".dwarfaranges", 0)
|
||||
if arangessec == nil {
|
||||
arangessec = ctxt.Syms.Lookup(".dwarfaranges", 0)
|
||||
}
|
||||
arangessec.R = arangessec.R[:0]
|
||||
|
||||
var dwarfctxt dwarf.Context = dwctxt{ctxt}
|
||||
@@ -1553,10 +1577,10 @@ func dwarfgeneratedebugsyms(ctxt *Link) {
|
||||
|
||||
genasmsym(ctxt, defdwsymb)
|
||||
|
||||
abbrev := writeabbrev(ctxt)
|
||||
syms := []*Symbol{abbrev}
|
||||
syms := writeabbrev(ctxt, nil)
|
||||
syms, funcs := writelines(ctxt, syms)
|
||||
syms = writeframes(ctxt, syms)
|
||||
syms = writeranges(ctxt, syms)
|
||||
|
||||
synthesizestringtypes(ctxt, dwtypes.Child)
|
||||
synthesizeslicetypes(ctxt, dwtypes.Child)
|
||||
@@ -1572,42 +1596,16 @@ func dwarfgeneratedebugsyms(ctxt *Link) {
|
||||
|
||||
// Need to reorder symbols so SDWARFINFO is after all SDWARFSECT
|
||||
// (but we need to generate dies before writepub)
|
||||
infosyms := writeinfo(ctxt, nil, funcs, abbrev)
|
||||
infosyms := writeinfo(ctxt, nil, funcs)
|
||||
|
||||
syms = writepub(ctxt, ".debug_pubnames", ispubname, syms)
|
||||
syms = writepub(ctxt, ".debug_pubtypes", ispubtype, syms)
|
||||
syms = writearanges(ctxt, syms)
|
||||
syms = writegdbscript(ctxt, syms)
|
||||
syms = append(syms, infosyms...)
|
||||
syms = collectlocs(ctxt, syms, funcs)
|
||||
syms = writeranges(ctxt, syms)
|
||||
dwarfp = syms
|
||||
}
|
||||
|
||||
func collectlocs(ctxt *Link, syms []*Symbol, funcs []*Symbol) []*Symbol {
|
||||
empty := true
|
||||
for _, fn := range funcs {
|
||||
for _, reloc := range fn.R {
|
||||
if reloc.Type == objabi.R_DWARFREF && strings.HasPrefix(reloc.Sym.Name, dwarf.LocPrefix) {
|
||||
reloc.Sym.Attr |= AttrReachable | AttrNotInSymbolTable
|
||||
syms = append(syms, reloc.Sym)
|
||||
empty = false
|
||||
// One location list entry per function, but many relocations to it. Don't duplicate.
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// Don't emit .debug_loc if it's empty -- it makes the ARM linker mad.
|
||||
if !empty {
|
||||
locsym := ctxt.Syms.Lookup(".debug_loc", 0)
|
||||
locsym.R = locsym.R[:0]
|
||||
locsym.Type = SDWARFLOC
|
||||
locsym.Attr |= AttrReachable
|
||||
syms = append(syms, locsym)
|
||||
}
|
||||
return syms
|
||||
}
|
||||
|
||||
/*
|
||||
* Elf.
|
||||
*/
|
||||
@@ -1620,7 +1618,6 @@ func dwarfaddshstrings(ctxt *Link, shstrtab *Symbol) {
|
||||
Addstring(shstrtab, ".debug_aranges")
|
||||
Addstring(shstrtab, ".debug_frame")
|
||||
Addstring(shstrtab, ".debug_info")
|
||||
Addstring(shstrtab, ".debug_loc")
|
||||
Addstring(shstrtab, ".debug_line")
|
||||
Addstring(shstrtab, ".debug_pubnames")
|
||||
Addstring(shstrtab, ".debug_pubtypes")
|
||||
@@ -1628,7 +1625,6 @@ func dwarfaddshstrings(ctxt *Link, shstrtab *Symbol) {
|
||||
Addstring(shstrtab, ".debug_ranges")
|
||||
if Linkmode == LinkExternal {
|
||||
Addstring(shstrtab, elfRelType+".debug_info")
|
||||
Addstring(shstrtab, elfRelType+".debug_loc")
|
||||
Addstring(shstrtab, elfRelType+".debug_aranges")
|
||||
Addstring(shstrtab, elfRelType+".debug_line")
|
||||
Addstring(shstrtab, elfRelType+".debug_frame")
|
||||
@@ -1655,10 +1651,6 @@ func dwarfaddelfsectionsyms(ctxt *Link) {
|
||||
putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
|
||||
sym = ctxt.Syms.Lookup(".debug_frame", 0)
|
||||
putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
|
||||
sym = ctxt.Syms.Lookup(".debug_loc", 0)
|
||||
if sym.Sect != nil {
|
||||
putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
|
||||
}
|
||||
sym = ctxt.Syms.Lookup(".debug_ranges", 0)
|
||||
if sym.Sect != nil {
|
||||
putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
|
||||
|
||||
@@ -1808,7 +1808,7 @@ func elfrelocsect(ctxt *Link, sect *Section, syms []*Symbol) {
|
||||
continue
|
||||
}
|
||||
if r.Xsym == nil {
|
||||
Errorf(sym, "missing xsym in relocation %#v %#v", r.Sym.Name, sym)
|
||||
Errorf(sym, "missing xsym in relocation")
|
||||
continue
|
||||
}
|
||||
if r.Xsym.ElfsymForReloc() == 0 {
|
||||
@@ -2596,9 +2596,12 @@ elfobj:
|
||||
elfshreloc(sect)
|
||||
}
|
||||
for _, s := range dwarfp {
|
||||
if len(s.R) > 0 || s.Type == SDWARFINFO || s.Type == SDWARFLOC {
|
||||
if len(s.R) > 0 || s.Type == SDWARFINFO {
|
||||
elfshreloc(s.Sect)
|
||||
}
|
||||
if s.Type == SDWARFINFO {
|
||||
break
|
||||
}
|
||||
}
|
||||
// add a .note.GNU-stack section to mark the stack as non-executable
|
||||
sh := elfshname(".note.GNU-stack")
|
||||
|
||||
@@ -105,7 +105,6 @@ const (
|
||||
SDWARFSECT
|
||||
SDWARFINFO
|
||||
SDWARFRANGE
|
||||
SDWARFLOC
|
||||
SSUB = SymKind(1 << 8)
|
||||
SMASK = SymKind(SSUB - 1)
|
||||
SHIDDEN = SymKind(1 << 9)
|
||||
@@ -125,7 +124,6 @@ var abiSymKindToSymKind = [...]SymKind{
|
||||
STLSBSS,
|
||||
SDWARFINFO,
|
||||
SDWARFRANGE,
|
||||
SDWARFLOC,
|
||||
}
|
||||
|
||||
// readOnly are the symbol kinds that form read-only sections. In some
|
||||
|
||||
@@ -4,9 +4,9 @@ package ld
|
||||
|
||||
import "fmt"
|
||||
|
||||
const _SymKind_name = "SxxxSTEXTSELFRXSECTSTYPESSTRINGSGOSTRINGSGOFUNCSGCBITSSRODATASFUNCTABSELFROSECTSMACHOPLTSTYPERELROSSTRINGRELROSGOSTRINGRELROSGOFUNCRELROSGCBITSRELROSRODATARELROSFUNCTABRELROSTYPELINKSITABLINKSSYMTABSPCLNTABSELFSECTSMACHOSMACHOGOTSWINDOWSSELFGOTSNOPTRDATASINITARRSDATASBSSSNOPTRBSSSTLSBSSSXREFSMACHOSYMSTRSMACHOSYMTABSMACHOINDIRECTPLTSMACHOINDIRECTGOTSFILESFILEPATHSCONSTSDYNIMPORTSHOSTOBJSDWARFSECTSDWARFINFOSDWARFRANGESDWARFLOC"
|
||||
const _SymKind_name = "SxxxSTEXTSELFRXSECTSTYPESSTRINGSGOSTRINGSGOFUNCSGCBITSSRODATASFUNCTABSELFROSECTSMACHOPLTSTYPERELROSSTRINGRELROSGOSTRINGRELROSGOFUNCRELROSGCBITSRELROSRODATARELROSFUNCTABRELROSTYPELINKSITABLINKSSYMTABSPCLNTABSELFSECTSMACHOSMACHOGOTSWINDOWSSELFGOTSNOPTRDATASINITARRSDATASBSSSNOPTRBSSSTLSBSSSXREFSMACHOSYMSTRSMACHOSYMTABSMACHOINDIRECTPLTSMACHOINDIRECTGOTSFILESFILEPATHSCONSTSDYNIMPORTSHOSTOBJSDWARFSECTSDWARFINFOSDWARFRANGE"
|
||||
|
||||
var _SymKind_index = [...]uint16{0, 4, 9, 19, 24, 31, 40, 47, 54, 61, 69, 79, 88, 98, 110, 124, 136, 148, 160, 173, 182, 191, 198, 206, 214, 220, 229, 237, 244, 254, 262, 267, 271, 280, 287, 292, 304, 316, 333, 350, 355, 364, 370, 380, 388, 398, 408, 419, 428}
|
||||
var _SymKind_index = [...]uint16{0, 4, 9, 19, 24, 31, 40, 47, 54, 61, 69, 79, 88, 98, 110, 124, 136, 148, 160, 173, 182, 191, 198, 206, 214, 220, 229, 237, 244, 254, 262, 267, 271, 280, 287, 292, 304, 316, 333, 350, 355, 364, 370, 380, 388, 398, 408, 419}
|
||||
|
||||
func (i SymKind) String() string {
|
||||
if i < 0 || i >= SymKind(len(_SymKind_index)-1) {
|
||||
|
||||
@@ -349,8 +349,9 @@ func doPackage(directory string, names []string, basePkg *Package) *Package {
|
||||
pkg.files = files
|
||||
// Type check the package.
|
||||
err := pkg.check(fs, astFiles)
|
||||
if err != nil && *verbose {
|
||||
warnf("%s", err)
|
||||
if err != nil {
|
||||
// Note that we only report this error when *verbose.
|
||||
Println(err)
|
||||
}
|
||||
|
||||
// Check.
|
||||
|
||||
13
src/cmd/vet/testdata/cgo/cgo3.go
vendored
Normal file
13
src/cmd/vet/testdata/cgo/cgo3.go
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Used by TestVetVerbose to test that vet -v doesn't fail because it
|
||||
// can't find "C".
|
||||
|
||||
package testdata
|
||||
|
||||
import "C"
|
||||
|
||||
func F() {
|
||||
}
|
||||
@@ -205,3 +205,15 @@ func TestTags(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Issue #21188.
|
||||
func TestVetVerbose(t *testing.T) {
|
||||
t.Parallel()
|
||||
Build(t)
|
||||
cmd := exec.Command("./"+binary, "-v", "-all", "testdata/cgo/cgo3.go")
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Logf("%s", out)
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,3 +68,94 @@ func ExampleByteOrder_get() {
|
||||
// Output:
|
||||
// 0x03e8 0x07d0
|
||||
}
|
||||
|
||||
func ExamplePutUvarint() {
|
||||
buf := make([]byte, binary.MaxVarintLen64)
|
||||
|
||||
for _, x := range []uint64{1, 2, 127, 128, 255, 256} {
|
||||
n := binary.PutUvarint(buf, x)
|
||||
fmt.Printf("%x\n", buf[:n])
|
||||
}
|
||||
// Output:
|
||||
// 01
|
||||
// 02
|
||||
// 7f
|
||||
// 8001
|
||||
// ff01
|
||||
// 8002
|
||||
}
|
||||
|
||||
func ExamplePutVarint() {
|
||||
buf := make([]byte, binary.MaxVarintLen64)
|
||||
|
||||
for _, x := range []int64{-65, -64, -2, -1, 0, 1, 2, 63, 64} {
|
||||
n := binary.PutVarint(buf, x)
|
||||
fmt.Printf("%x\n", buf[:n])
|
||||
}
|
||||
// Output:
|
||||
// 8101
|
||||
// 7f
|
||||
// 03
|
||||
// 01
|
||||
// 00
|
||||
// 02
|
||||
// 04
|
||||
// 7e
|
||||
// 8001
|
||||
}
|
||||
|
||||
func ExampleUvarint() {
|
||||
inputs := [][]byte{
|
||||
[]byte{0x01},
|
||||
[]byte{0x02},
|
||||
[]byte{0x7f},
|
||||
[]byte{0x80, 0x01},
|
||||
[]byte{0xff, 0x01},
|
||||
[]byte{0x80, 0x02},
|
||||
}
|
||||
for _, b := range inputs {
|
||||
x, n := binary.Uvarint(b)
|
||||
if n != len(b) {
|
||||
fmt.Println("Uvarint did not consume all of in")
|
||||
}
|
||||
fmt.Println(x)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 127
|
||||
// 128
|
||||
// 255
|
||||
// 256
|
||||
}
|
||||
|
||||
func ExampleVarint() {
|
||||
inputs := [][]byte{
|
||||
[]byte{0x81, 0x01},
|
||||
[]byte{0x7f},
|
||||
[]byte{0x03},
|
||||
[]byte{0x01},
|
||||
[]byte{0x00},
|
||||
[]byte{0x02},
|
||||
[]byte{0x04},
|
||||
[]byte{0x7e},
|
||||
[]byte{0x80, 0x01},
|
||||
}
|
||||
for _, b := range inputs {
|
||||
x, n := binary.Varint(b)
|
||||
if n != len(b) {
|
||||
fmt.Println("Varint did not consume all of in")
|
||||
}
|
||||
fmt.Println(x)
|
||||
}
|
||||
// Output:
|
||||
// -65
|
||||
// -64
|
||||
// -2
|
||||
// -1
|
||||
// 0
|
||||
// 1
|
||||
// 2
|
||||
// 63
|
||||
// 64
|
||||
}
|
||||
|
||||
@@ -969,14 +969,14 @@ func (*FuncDecl) declNode() {}
|
||||
//
|
||||
// For correct printing of source code containing comments (using packages
|
||||
// go/format and go/printer), special care must be taken to update comments
|
||||
// when a File's syntax tree is modified: For printing, comments are inter-
|
||||
// spersed between tokens based on their position. If syntax tree nodes are
|
||||
// when a File's syntax tree is modified: For printing, comments are interspersed
|
||||
// between tokens based on their position. If syntax tree nodes are
|
||||
// removed or moved, relevant comments in their vicinity must also be removed
|
||||
// (from the File.Comments list) or moved accordingly (by updating their
|
||||
// positions). A CommentMap may be used to facilitate some of these operations.
|
||||
//
|
||||
// Whether and how a comment is associated with a node depends on the inter-
|
||||
// pretation of the syntax tree by the manipulating program: Except for Doc
|
||||
// Whether and how a comment is associated with a node depends on the
|
||||
// interpretation of the syntax tree by the manipulating program: Except for Doc
|
||||
// and Comment comments directly associated with nodes, the remaining comments
|
||||
// are "free-floating" (see also issues #18593, #20744).
|
||||
//
|
||||
|
||||
@@ -1707,8 +1707,8 @@ func (p *parser) parseSimpleStmt(mode int) (ast.Stmt, bool) {
|
||||
}
|
||||
// The label declaration typically starts at x[0].Pos(), but the label
|
||||
// declaration may be erroneous due to a token after that position (and
|
||||
// before the ':'). If SpuriousErrors is not set, the (only) error re-
|
||||
// ported for the line is the illegal label error instead of the token
|
||||
// before the ':'). If SpuriousErrors is not set, the (only) error
|
||||
// reported for the line is the illegal label error instead of the token
|
||||
// before the ':' that caused the problem. Thus, use the (latest) colon
|
||||
// position for error reporting.
|
||||
p.error(colon, "illegal label declaration")
|
||||
|
||||
@@ -154,6 +154,10 @@ func (s *ioSrv) ProcessRemoteIO() {
|
||||
// is available. Alternatively, it passes the request onto
|
||||
// runtime netpoll and waits for completion or cancels request.
|
||||
func (s *ioSrv) ExecIO(o *operation, submit func(o *operation) error) (int, error) {
|
||||
if o.fd.pd.runtimeCtx == 0 {
|
||||
return 0, errors.New("internal error: polling on unsupported descriptor type")
|
||||
}
|
||||
|
||||
if !canCancelIO {
|
||||
onceStartServer.Do(startServer)
|
||||
}
|
||||
@@ -315,8 +319,21 @@ func (fd *FD) Init(net string) (string, error) {
|
||||
return "", errors.New("internal error: unknown network type " + net)
|
||||
}
|
||||
|
||||
if err := fd.pd.init(fd); err != nil {
|
||||
return "", err
|
||||
if !fd.isFile && !fd.isConsole && !fd.isDir {
|
||||
// Only call init for a network socket.
|
||||
// This means that we don't add files to the runtime poller.
|
||||
// Adding files to the runtime poller can confuse matters
|
||||
// if the user is doing their own overlapped I/O.
|
||||
// See issue #21172.
|
||||
//
|
||||
// In general the code below avoids calling the ExecIO
|
||||
// method for non-network sockets. If some method does
|
||||
// somehow call ExecIO, then ExecIO, and therefore the
|
||||
// calling method, will return an error, because
|
||||
// fd.pd.runtimeCtx will be 0.
|
||||
if err := fd.pd.init(fd); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
if hasLoadSetFileCompletionNotificationModes {
|
||||
// We do not use events, so we can skip them always.
|
||||
|
||||
@@ -40,8 +40,8 @@ func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
|
||||
// SetString sets z to the value of s and returns z and a boolean indicating
|
||||
// success. s can be given as a fraction "a/b" or as a floating-point number
|
||||
// optionally followed by an exponent. The entire string (not just a prefix)
|
||||
// must be valid for success. If the operation failed, the value of z is un-
|
||||
// defined but the returned value is nil.
|
||||
// must be valid for success. If the operation failed, the value of z is
|
||||
// undefined but the returned value is nil.
|
||||
func (z *Rat) SetString(s string) (*Rat, bool) {
|
||||
if len(s) == 0 {
|
||||
return nil, false
|
||||
|
||||
@@ -36,3 +36,43 @@ func ExampleLeadingZeros64() {
|
||||
// 64
|
||||
// 63
|
||||
}
|
||||
|
||||
func ExampleOnesCount() {
|
||||
fmt.Printf("%b\n", 14)
|
||||
fmt.Println(bits.OnesCount(14))
|
||||
// Output:
|
||||
// 1110
|
||||
// 3
|
||||
}
|
||||
|
||||
func ExampleOnesCount8() {
|
||||
fmt.Printf("%b\n", 14)
|
||||
fmt.Println(bits.OnesCount8(14))
|
||||
// Output:
|
||||
// 1110
|
||||
// 3
|
||||
}
|
||||
|
||||
func ExampleOnesCount16() {
|
||||
fmt.Printf("%b\n", 14)
|
||||
fmt.Println(bits.OnesCount16(14))
|
||||
// Output:
|
||||
// 1110
|
||||
// 3
|
||||
}
|
||||
|
||||
func ExampleOnesCount32() {
|
||||
fmt.Printf("%b\n", 14)
|
||||
fmt.Println(bits.OnesCount32(14))
|
||||
// Output:
|
||||
// 1110
|
||||
// 3
|
||||
}
|
||||
|
||||
func ExampleOnesCount64() {
|
||||
fmt.Printf("%b\n", 14)
|
||||
fmt.Println(bits.OnesCount64(14))
|
||||
// Output:
|
||||
// 1110
|
||||
// 3
|
||||
}
|
||||
|
||||
@@ -44,26 +44,29 @@ type plainAuth struct {
|
||||
}
|
||||
|
||||
// PlainAuth returns an Auth that implements the PLAIN authentication
|
||||
// mechanism as defined in RFC 4616.
|
||||
// The returned Auth uses the given username and password to authenticate
|
||||
// on TLS connections to host and act as identity. Usually identity will be
|
||||
// left blank to act as username.
|
||||
// mechanism as defined in RFC 4616. The returned Auth uses the given
|
||||
// username and password to authenticate to host and act as identity.
|
||||
// Usually identity should be the empty string, to act as username.
|
||||
//
|
||||
// PlainAuth will only send the credentials if the connection is using TLS
|
||||
// or is connected to localhost. Otherwise authentication will fail with an
|
||||
// error, without sending the credentials.
|
||||
func PlainAuth(identity, username, password, host string) Auth {
|
||||
return &plainAuth{identity, username, password, host}
|
||||
}
|
||||
|
||||
func isLocalhost(name string) bool {
|
||||
return name == "localhost" || name == "127.0.0.1" || name == "::1"
|
||||
}
|
||||
|
||||
func (a *plainAuth) Start(server *ServerInfo) (string, []byte, error) {
|
||||
if !server.TLS {
|
||||
advertised := false
|
||||
for _, mechanism := range server.Auth {
|
||||
if mechanism == "PLAIN" {
|
||||
advertised = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !advertised {
|
||||
return "", nil, errors.New("unencrypted connection")
|
||||
}
|
||||
// Must have TLS, or else localhost server.
|
||||
// Note: If TLS is not true, then we can't trust ANYTHING in ServerInfo.
|
||||
// In particular, it doesn't matter if the server advertises PLAIN auth.
|
||||
// That might just be the attacker saying
|
||||
// "it's ok, you can trust me with your password."
|
||||
if !server.TLS && !isLocalhost(server.Name) {
|
||||
return "", nil, errors.New("unencrypted connection")
|
||||
}
|
||||
if server.Name != a.host {
|
||||
return "", nil, errors.New("wrong host name")
|
||||
|
||||
@@ -62,29 +62,41 @@ testLoop:
|
||||
}
|
||||
|
||||
func TestAuthPlain(t *testing.T) {
|
||||
auth := PlainAuth("foo", "bar", "baz", "servername")
|
||||
|
||||
tests := []struct {
|
||||
server *ServerInfo
|
||||
err string
|
||||
authName string
|
||||
server *ServerInfo
|
||||
err string
|
||||
}{
|
||||
{
|
||||
server: &ServerInfo{Name: "servername", TLS: true},
|
||||
authName: "servername",
|
||||
server: &ServerInfo{Name: "servername", TLS: true},
|
||||
},
|
||||
{
|
||||
// Okay; explicitly advertised by server.
|
||||
server: &ServerInfo{Name: "servername", Auth: []string{"PLAIN"}},
|
||||
// OK to use PlainAuth on localhost without TLS
|
||||
authName: "localhost",
|
||||
server: &ServerInfo{Name: "localhost", TLS: false},
|
||||
},
|
||||
{
|
||||
server: &ServerInfo{Name: "servername", Auth: []string{"CRAM-MD5"}},
|
||||
err: "unencrypted connection",
|
||||
// NOT OK on non-localhost, even if server says PLAIN is OK.
|
||||
// (We don't know that the server is the real server.)
|
||||
authName: "servername",
|
||||
server: &ServerInfo{Name: "servername", Auth: []string{"PLAIN"}},
|
||||
err: "unencrypted connection",
|
||||
},
|
||||
{
|
||||
server: &ServerInfo{Name: "attacker", TLS: true},
|
||||
err: "wrong host name",
|
||||
authName: "servername",
|
||||
server: &ServerInfo{Name: "servername", Auth: []string{"CRAM-MD5"}},
|
||||
err: "unencrypted connection",
|
||||
},
|
||||
{
|
||||
authName: "servername",
|
||||
server: &ServerInfo{Name: "attacker", TLS: true},
|
||||
err: "wrong host name",
|
||||
},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
auth := PlainAuth("foo", "bar", "baz", tt.authName)
|
||||
_, _, err := auth.Start(tt.server)
|
||||
got := ""
|
||||
if err != nil {
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
|
||||
// Package plugin implements loading and symbol resolution of Go plugins.
|
||||
//
|
||||
// Currently plugins only work on Linux.
|
||||
//
|
||||
// A plugin is a Go main package with exported functions and variables that
|
||||
// has been built with:
|
||||
//
|
||||
@@ -14,6 +12,9 @@
|
||||
// When a plugin is first opened, the init functions of all packages not
|
||||
// already part of the program are called. The main function is not run.
|
||||
// A plugin is only initialized once, and cannot be closed.
|
||||
//
|
||||
// The plugin support is currently incomplete, only supports Linux,
|
||||
// and has known bugs. Please report any issues.
|
||||
package plugin
|
||||
|
||||
// Plugin is a loaded Go plugin.
|
||||
|
||||
@@ -178,6 +178,12 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool {
|
||||
// DeepEqual has been defined so that the same short-cut applies
|
||||
// to slices and maps: if x and y are the same slice or the same map,
|
||||
// they are deeply equal regardless of content.
|
||||
//
|
||||
// As DeepEqual traverses the data values it may find a cycle. The
|
||||
// second and subsequent times that DeepEqual compares two pointer
|
||||
// values that have been compared before, it treats the values as
|
||||
// equal rather than examining the values to which they point.
|
||||
// This ensures that DeepEqual terminates.
|
||||
func DeepEqual(x, y interface{}) bool {
|
||||
if x == nil || y == nil {
|
||||
return x == y
|
||||
|
||||
@@ -163,6 +163,15 @@ func (p *cpuProfile) addExtra() {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *cpuProfile) addLostAtomic64(count uint64) {
|
||||
hdr := [1]uint64{count}
|
||||
lostStk := [2]uintptr{
|
||||
funcPC(_LostSIGPROFDuringAtomic64) + sys.PCQuantum,
|
||||
funcPC(_System) + sys.PCQuantum,
|
||||
}
|
||||
cpuprof.log.write(nil, 0, hdr[:], lostStk[:])
|
||||
}
|
||||
|
||||
// CPUProfile panics.
|
||||
// It formerly provided raw access to chunks of
|
||||
// a pprof-format profile generated by the runtime.
|
||||
|
||||
@@ -170,7 +170,7 @@ func TestPeriodicGC(t *testing.T) {
|
||||
// slack if things are slow.
|
||||
var numGCs uint32
|
||||
const want = 2
|
||||
for i := 0; i < 20 && numGCs < want; i++ {
|
||||
for i := 0; i < 200 && numGCs < want; i++ {
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
|
||||
// Test that periodic GC actually happened.
|
||||
|
||||
@@ -495,7 +495,7 @@ again:
|
||||
}
|
||||
|
||||
// store new key/value at insert position
|
||||
*((*uint32)(insertk)) = key
|
||||
typedmemmove(t.key, insertk, unsafe.Pointer(&key))
|
||||
*inserti = top
|
||||
h.count++
|
||||
|
||||
@@ -583,7 +583,7 @@ again:
|
||||
}
|
||||
|
||||
// store new key/value at insert position
|
||||
*((*uint64)(insertk)) = key
|
||||
typedmemmove(t.key, insertk, unsafe.Pointer(&key))
|
||||
*inserti = top
|
||||
h.count++
|
||||
|
||||
@@ -723,7 +723,7 @@ func mapdelete_fast32(t *maptype, h *hmap, key uint32) {
|
||||
if key != *k {
|
||||
continue
|
||||
}
|
||||
*k = 0
|
||||
typedmemclr(t.key, unsafe.Pointer(k))
|
||||
v := unsafe.Pointer(uintptr(unsafe.Pointer(b)) + dataOffset + bucketCnt*4 + i*uintptr(t.valuesize))
|
||||
typedmemclr(t.elem, v)
|
||||
b.tophash[i] = empty
|
||||
@@ -778,7 +778,7 @@ func mapdelete_fast64(t *maptype, h *hmap, key uint64) {
|
||||
if key != *k {
|
||||
continue
|
||||
}
|
||||
*k = 0
|
||||
typedmemclr(t.key, unsafe.Pointer(k))
|
||||
v := unsafe.Pointer(uintptr(unsafe.Pointer(b)) + dataOffset + bucketCnt*8 + i*uintptr(t.valuesize))
|
||||
typedmemclr(t.elem, v)
|
||||
b.tophash[i] = empty
|
||||
|
||||
@@ -416,7 +416,10 @@ func (h *mheap) sysAlloc(n uintptr) unsafe.Pointer {
|
||||
var reserved bool
|
||||
p := uintptr(sysReserve(unsafe.Pointer(h.arena_end), p_size, &reserved))
|
||||
if p == 0 {
|
||||
return nil
|
||||
// TODO: Try smaller reservation
|
||||
// growths in case we're in a crowded
|
||||
// 32-bit address space.
|
||||
goto reservationFailed
|
||||
}
|
||||
// p can be just about anywhere in the address
|
||||
// space, including before arena_end.
|
||||
@@ -476,6 +479,7 @@ func (h *mheap) sysAlloc(n uintptr) unsafe.Pointer {
|
||||
return unsafe.Pointer(p)
|
||||
}
|
||||
|
||||
reservationFailed:
|
||||
// If using 64-bit, our reservation is all we have.
|
||||
if sys.PtrSize != 4 {
|
||||
return nil
|
||||
|
||||
@@ -503,6 +503,11 @@ func (h *mheap) init(spansStart, spansBytes uintptr) {
|
||||
sp.array = unsafe.Pointer(spansStart)
|
||||
sp.len = 0
|
||||
sp.cap = int(spansBytes / sys.PtrSize)
|
||||
|
||||
// Map metadata structures. But don't map race detector memory
|
||||
// since we're not actually growing the arena here (and TSAN
|
||||
// gets mad if you map 0 bytes).
|
||||
h.setArenaUsed(h.arena_used, false)
|
||||
}
|
||||
|
||||
// setArenaUsed extends the usable arena to address arena_used and
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -20,11 +21,12 @@ import (
|
||||
"runtime/pprof/internal/profile"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func cpuHogger(f func(), dur time.Duration) {
|
||||
func cpuHogger(f func() int, dur time.Duration) {
|
||||
// We only need to get one 100 Hz clock tick, so we've got
|
||||
// a large safety buffer.
|
||||
// But do at least 500 iterations (which should take about 100ms),
|
||||
@@ -44,7 +46,7 @@ var (
|
||||
// The actual CPU hogging function.
|
||||
// Must not call other functions nor access heap/globals in the loop,
|
||||
// otherwise under race detector the samples will be in the race runtime.
|
||||
func cpuHog1() {
|
||||
func cpuHog1() int {
|
||||
foo := salt1
|
||||
for i := 0; i < 1e5; i++ {
|
||||
if foo > 0 {
|
||||
@@ -53,10 +55,10 @@ func cpuHog1() {
|
||||
foo *= foo + 1
|
||||
}
|
||||
}
|
||||
salt1 = foo
|
||||
return foo
|
||||
}
|
||||
|
||||
func cpuHog2() {
|
||||
func cpuHog2() int {
|
||||
foo := salt2
|
||||
for i := 0; i < 1e5; i++ {
|
||||
if foo > 0 {
|
||||
@@ -65,7 +67,7 @@ func cpuHog2() {
|
||||
foo *= foo + 2
|
||||
}
|
||||
}
|
||||
salt2 = foo
|
||||
return foo
|
||||
}
|
||||
|
||||
func TestCPUProfile(t *testing.T) {
|
||||
@@ -93,8 +95,9 @@ func TestCPUProfileInlining(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func inlinedCaller() {
|
||||
func inlinedCaller() int {
|
||||
inlinedCallee()
|
||||
return 0
|
||||
}
|
||||
|
||||
func inlinedCallee() {
|
||||
@@ -713,3 +716,54 @@ func TestCPUProfileLabel(t *testing.T) {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestLabelRace(t *testing.T) {
|
||||
// Test the race detector annotations for synchronization
|
||||
// between settings labels and consuming them from the
|
||||
// profile.
|
||||
testCPUProfile(t, []string{"runtime/pprof.cpuHogger;key=value"}, func(dur time.Duration) {
|
||||
start := time.Now()
|
||||
var wg sync.WaitGroup
|
||||
for time.Since(start) < dur {
|
||||
for i := 0; i < 10; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
Do(context.Background(), Labels("key", "value"), func(context.Context) {
|
||||
cpuHogger(cpuHog1, time.Millisecond)
|
||||
})
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Check that there is no deadlock when the program receives SIGPROF while in
|
||||
// 64bit atomics' critical section. Used to happen on mips{,le}. See #20146.
|
||||
func TestAtomicLoadStore64(t *testing.T) {
|
||||
f, err := ioutil.TempFile("", "profatomic")
|
||||
if err != nil {
|
||||
t.Fatalf("TempFile: %v", err)
|
||||
}
|
||||
defer os.Remove(f.Name())
|
||||
defer f.Close()
|
||||
|
||||
if err := StartCPUProfile(f); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer StopCPUProfile()
|
||||
|
||||
var flag uint64
|
||||
done := make(chan bool, 1)
|
||||
|
||||
go func() {
|
||||
for atomic.LoadUint64(&flag) == 0 {
|
||||
runtime.Gosched()
|
||||
}
|
||||
done <- true
|
||||
}()
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
atomic.StoreUint64(&flag, 1)
|
||||
<-done
|
||||
}
|
||||
|
||||
@@ -3232,10 +3232,14 @@ var prof struct {
|
||||
hz int32
|
||||
}
|
||||
|
||||
func _System() { _System() }
|
||||
func _ExternalCode() { _ExternalCode() }
|
||||
func _LostExternalCode() { _LostExternalCode() }
|
||||
func _GC() { _GC() }
|
||||
func _System() { _System() }
|
||||
func _ExternalCode() { _ExternalCode() }
|
||||
func _LostExternalCode() { _LostExternalCode() }
|
||||
func _GC() { _GC() }
|
||||
func _LostSIGPROFDuringAtomic64() { _LostSIGPROFDuringAtomic64() }
|
||||
|
||||
// Counts SIGPROFs received while in atomic64 critical section, on mips{,le}
|
||||
var lostAtomic64Count uint64
|
||||
|
||||
// Called if we receive a SIGPROF signal.
|
||||
// Called by the signal handler, may run during STW.
|
||||
@@ -3245,6 +3249,21 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
|
||||
return
|
||||
}
|
||||
|
||||
// On mips{,le}, 64bit atomics are emulated with spinlocks, in
|
||||
// runtime/internal/atomic. If SIGPROF arrives while the program is inside
|
||||
// the critical section, it creates a deadlock (when writing the sample).
|
||||
// As a workaround, create a counter of SIGPROFs while in critical section
|
||||
// to store the count, and pass it to sigprof.add() later when SIGPROF is
|
||||
// received from somewhere else (with _LostSIGPROFDuringAtomic64 as pc).
|
||||
if GOARCH == "mips" || GOARCH == "mipsle" {
|
||||
if f := findfunc(pc); f.valid() {
|
||||
if hasprefix(funcname(f), "runtime/internal/atomic") {
|
||||
lostAtomic64Count++
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Profiling runs concurrently with GC, so it must not allocate.
|
||||
// Set a trap in case the code does allocate.
|
||||
// Note that on windows, one thread takes profiles of all the
|
||||
@@ -3371,6 +3390,10 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
|
||||
}
|
||||
|
||||
if prof.hz != 0 {
|
||||
if (GOARCH == "mips" || GOARCH == "mipsle") && lostAtomic64Count > 0 {
|
||||
cpuprof.addLostAtomic64(lostAtomic64Count)
|
||||
lostAtomic64Count = 0
|
||||
}
|
||||
cpuprof.add(gp, stk[:n])
|
||||
}
|
||||
getg().m.mallocing--
|
||||
|
||||
@@ -545,7 +545,7 @@ Read:
|
||||
b.rNext = br.addCountsAndClearFlags(skip+di, ti)
|
||||
|
||||
if raceenabled {
|
||||
// Match racewritepc in runtime_setProfLabel,
|
||||
// Match racereleasemerge in runtime_setProfLabel,
|
||||
// so that the setting of the labels in runtime_setProfLabel
|
||||
// is treated as happening before any use of the labels
|
||||
// by our caller. The synchronization on labelSync itself is a fiction
|
||||
|
||||
@@ -13,8 +13,23 @@ func runtime_setProfLabel(labels unsafe.Pointer) {
|
||||
// Introduce race edge for read-back via profile.
|
||||
// This would more properly use &getg().labels as the sync address,
|
||||
// but we do the read in a signal handler and can't call the race runtime then.
|
||||
//
|
||||
// This uses racereleasemerge rather than just racerelease so
|
||||
// the acquire in profBuf.read synchronizes with *all* prior
|
||||
// setProfLabel operations, not just the most recent one. This
|
||||
// is important because profBuf.read will observe different
|
||||
// labels set by different setProfLabel operations on
|
||||
// different goroutines, so it needs to synchronize with all
|
||||
// of them (this wouldn't be an issue if we could synchronize
|
||||
// on &getg().labels since we would synchronize with each
|
||||
// most-recent labels write separately.)
|
||||
//
|
||||
// racereleasemerge is like a full read-modify-write on
|
||||
// labelSync, rather than just a store-release, so it carries
|
||||
// a dependency on the previous racereleasemerge, which
|
||||
// ultimately carries forward to the acquire in profBuf.read.
|
||||
if raceenabled {
|
||||
racerelease(unsafe.Pointer(&labelSync))
|
||||
racereleasemerge(unsafe.Pointer(&labelSync))
|
||||
}
|
||||
getg().labels = labels
|
||||
}
|
||||
|
||||
@@ -259,4 +259,25 @@ Goroutine [0-9] \(running\) created at:
|
||||
runtime\.newextram\(\)
|
||||
.*/runtime/proc.go:[0-9]+ \+0x[0-9,a-f]+
|
||||
==================`},
|
||||
{"second_test_passes", "test", "", "atexit_sleep_ms=0", `
|
||||
package main_test
|
||||
import "testing"
|
||||
func TestFail(t *testing.T) {
|
||||
done := make(chan bool)
|
||||
x := 0
|
||||
go func() {
|
||||
x = 42
|
||||
done <- true
|
||||
}()
|
||||
x = 43
|
||||
<-done
|
||||
}
|
||||
|
||||
func TestPass(t *testing.T) {
|
||||
}
|
||||
`, `
|
||||
==================
|
||||
--- FAIL: TestFail \(0...s\)
|
||||
.*testing.go:.*: race detected during execution of test
|
||||
FAIL`},
|
||||
}
|
||||
|
||||
@@ -409,6 +409,11 @@ var modulesSlice unsafe.Pointer // see activeModules
|
||||
//
|
||||
// A module is active once its gcdatamask and gcbssmask have been
|
||||
// assembled and it is usable by the GC.
|
||||
//
|
||||
// This is nosplit/nowritebarrier because it is called by the
|
||||
// cgo pointer checking code.
|
||||
//go:nosplit
|
||||
//go:nowritebarrier
|
||||
func activeModules() []*moduledata {
|
||||
p := (*[]*moduledata)(atomic.Loadp(unsafe.Pointer(&modulesSlice)))
|
||||
if p == nil {
|
||||
|
||||
@@ -100,7 +100,7 @@ TEXT runtime·usleep(SB),NOSPLIT,$8
|
||||
MOVL AX, 0(SP)
|
||||
MOVL $1000, AX // usec to nsec
|
||||
MULL DX
|
||||
MOVL DX, 4(SP)
|
||||
MOVL AX, 4(SP)
|
||||
|
||||
// pselect6(0, 0, 0, 0, &ts, 0)
|
||||
MOVL $308, AX
|
||||
|
||||
@@ -695,8 +695,7 @@ func tRunner(t *T, fn func(t *T)) {
|
||||
// a call to runtime.Goexit, record the duration and send
|
||||
// a signal saying that the test is done.
|
||||
defer func() {
|
||||
t.raceErrors += race.Errors()
|
||||
if t.raceErrors > 0 {
|
||||
if t.raceErrors+race.Errors() > 0 {
|
||||
t.Errorf("race detected during execution of test")
|
||||
}
|
||||
|
||||
@@ -970,7 +969,7 @@ func listTests(matchString func(pat, str string) (bool, error), tests []Internal
|
||||
}
|
||||
}
|
||||
for _, example := range examples {
|
||||
if ok, _ := matchString(*matchList, example.Name); ok && example.Output != "" {
|
||||
if ok, _ := matchString(*matchList, example.Name); ok {
|
||||
fmt.Println(example.Name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,14 @@ func testZoneAbbr(t *testing.T) {
|
||||
t1 := Now()
|
||||
// discard nsec
|
||||
t1 = Date(t1.Year(), t1.Month(), t1.Day(), t1.Hour(), t1.Minute(), t1.Second(), 0, t1.Location())
|
||||
|
||||
// Skip the test if we're in a timezone with no abbreviation.
|
||||
// Format will fallback to the numeric abbreviation, and
|
||||
// Parse(RFC1123, ..) will fail (see Issue 21183).
|
||||
if tz := t1.Format("MST"); tz[0] == '-' || tz[0] == '+' {
|
||||
t.Skip("No zone abbreviation")
|
||||
}
|
||||
|
||||
t2, err := Parse(RFC1123, t1.Format(RFC1123))
|
||||
if err != nil {
|
||||
t.Fatalf("Parse failed: %v", err)
|
||||
|
||||
15
test/README.md
Normal file
15
test/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
The test directory contains tests of the Go tool chain and runtime.
|
||||
It includes black box tests, regression tests, and error output tests.
|
||||
They are run as part of all.bash.
|
||||
|
||||
To run just these tests, execute:
|
||||
|
||||
go run run.go
|
||||
|
||||
Standard library tests should be written as regular Go tests in the appropriate package.
|
||||
|
||||
The tool chain and runtime also have regular Go tests in their packages.
|
||||
The main reasons to add a new test to this directory are:
|
||||
|
||||
* it is most naturally expressed using the test runner; or
|
||||
* it is also applicable to `gccgo` and other Go tool chains.
|
||||
Reference in New Issue
Block a user