mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.cc] all: merge master (d1210ac) into dev.cc
Change-Id: I068d617175776c2f5df00b17ff0d404a584ab570
This commit is contained in:
commit
929f3210ac
196 changed files with 3951 additions and 2753 deletions
|
|
@ -19,6 +19,8 @@ Go is the work of hundreds of contributors. We appreciate your help!
|
|||
To contribute, please read the contribution guidelines:
|
||||
https://golang.org/doc/contribute.html
|
||||
|
||||
##### Please note that we do not use pull requests.
|
||||
|
||||
Unless otherwise noted, the Go source files are distributed
|
||||
under the BSD-style license found in the LICENSE file.
|
||||
|
||||
|
|
|
|||
|
|
@ -247,5 +247,3 @@ pkg runtime (openbsd-amd64-cgo), const EWOULDBLOCK = 35
|
|||
pkg runtime (openbsd-amd64-cgo), const EWOULDBLOCK ideal-int
|
||||
pkg runtime (openbsd-amd64-cgo), const HW_NCPU = 3
|
||||
pkg runtime (openbsd-amd64-cgo), const HW_NCPU ideal-int
|
||||
pkg runtime, func GCcheckmarkdisable()
|
||||
pkg runtime, func GCcheckmarkenable()
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ Git, note that you still need the commit hooks that the git-codereview command
|
|||
configures; those hooks add a Gerrit <code>Change-Id</code> line to the commit
|
||||
message and check that all Go source files have been formatted with gofmt. Even
|
||||
if you intend to use plain Git for daily work, install the hooks in a new Git
|
||||
checkout by running <code>git-codereview</code> <code>hooks</code>).
|
||||
checkout by running <code>git-codereview</code> <code>hooks</code>.
|
||||
</p>
|
||||
|
||||
<h3>Set up git aliases</h3>
|
||||
|
|
@ -461,7 +461,7 @@ $ git sync
|
|||
</pre>
|
||||
|
||||
<p>
|
||||
(In git terms, git sync runs
|
||||
(In git terms, <code>git</code> <code>sync</code> runs
|
||||
<code>git</code> <code>pull</code> <code>-r</code>.)
|
||||
</p>
|
||||
|
||||
|
|
|
|||
|
|
@ -4,10 +4,16 @@ bufio: add Reader.Discard (https://golang.org/cl/2260)
|
|||
crypto/cipher: clarify what will happen if len(src) != len(dst) for the Stream interface. (https://golang.org/cl/1754)
|
||||
crypto/tls: change default minimum version to TLS 1.0. (https://golang.org/cl/1791)
|
||||
encoding/base64: add unpadded encodings (https://golang.org/cl/1511)
|
||||
log: add global Output function (https://golang.org/cl/2686)
|
||||
net/http: support for setting trailers from a server Handler (https://golang.org/cl/2157)
|
||||
net/smtp: add TLSConnectionState accessor (https://golang.org/cl/2151)
|
||||
|
||||
Tools:
|
||||
|
||||
cmd/vet: better validation of struct tags (https://golang.org/cl/2685)
|
||||
|
||||
Performance:
|
||||
|
||||
strconv: optimize decimal to string conversion (https://golang.org/cl/2105)
|
||||
math/big: faster assembly kernels for amd64 and 386 (https://golang.org/cl/2503, https://golang.org/cl/2560)
|
||||
math/big: faster "pure Go" kernels for platforms w/o assembly kernels (https://golang.org/cl/2480)
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ struct Reloc
|
|||
uchar siz;
|
||||
uchar done;
|
||||
int32 type;
|
||||
int32 variant; // RV_*: variant on computed value
|
||||
int64 add;
|
||||
int64 xadd;
|
||||
LSym* sym;
|
||||
|
|
@ -141,6 +142,7 @@ struct LSym
|
|||
uchar hide;
|
||||
uchar leaf; // arm only
|
||||
uchar fnptr; // arm only
|
||||
uchar localentry; // ppc64: instrs between global & local entry
|
||||
uchar seenglobl;
|
||||
uchar onlist; // on the textp or datap lists
|
||||
int16 symid; // for writing .5/.6/.8 files
|
||||
|
|
@ -210,6 +212,7 @@ enum
|
|||
SMACHO, /* Mach-O __nl_symbol_ptr */
|
||||
SMACHOGOT,
|
||||
SWINDOWS,
|
||||
SELFGOT, /* also .toc in ppc64 ABI */
|
||||
SNOPTRDATA,
|
||||
SINITARR,
|
||||
SDATA,
|
||||
|
|
@ -254,6 +257,20 @@ enum
|
|||
R_PLT1,
|
||||
R_PLT2,
|
||||
R_USEFIELD,
|
||||
R_POWER_TOC, // ELF R_PPC64_TOC16*
|
||||
};
|
||||
|
||||
// Reloc.variant
|
||||
enum
|
||||
{
|
||||
RV_NONE, // identity variant
|
||||
RV_POWER_LO, // x & 0xFFFF
|
||||
RV_POWER_HI, // x >> 16
|
||||
RV_POWER_HA, // (x + 0x8000) >> 16
|
||||
RV_POWER_DS, // x & 0xFFFC, check x&0x3 == 0
|
||||
|
||||
RV_CHECK_OVERFLOW = 1<<8, // check overflow flag
|
||||
RV_TYPE_MASK = (RV_CHECK_OVERFLOW - 1),
|
||||
};
|
||||
|
||||
// Auto.type
|
||||
|
|
|
|||
|
|
@ -63,5 +63,6 @@ func Test8811(t *testing.T) { test8811(t) }
|
|||
func TestReturnAfterGrow(t *testing.T) { testReturnAfterGrow(t) }
|
||||
func TestReturnAfterGrowFromGo(t *testing.T) { testReturnAfterGrowFromGo(t) }
|
||||
func Test9026(t *testing.T) { test9026(t) }
|
||||
func Test9557(t *testing.T) { test9557(t) }
|
||||
|
||||
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import "testing"
|
|||
|
||||
var v7234 = [...]string{"runtime/cgo"}
|
||||
|
||||
func TestIssue7234(t *testing.T) {
|
||||
func Test7234(t *testing.T) {
|
||||
if v7234[0] != "runtime/cgo" {
|
||||
t.Errorf("bad string constant %q", v7234[0])
|
||||
}
|
||||
|
|
|
|||
36
misc/cgo/test/issue9557.go
Normal file
36
misc/cgo/test/issue9557.go
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// cgo rewrote C.var to *_Cvar_var, but left
|
||||
// C.var.field as _Cvar.var.field. It now rewrites
|
||||
// the latter as (*_Cvar_var).field.
|
||||
// See https://golang.org/issue/9557.
|
||||
|
||||
package cgotest
|
||||
|
||||
// struct issue9557_t {
|
||||
// int a;
|
||||
// } test9557bar = { 42 };
|
||||
//
|
||||
// struct issue9557_t *issue9557foo = &test9557bar;
|
||||
import "C"
|
||||
import "testing"
|
||||
|
||||
func test9557(t *testing.T) {
|
||||
// implicitly dereference a Go variable
|
||||
foo := C.issue9557foo
|
||||
if v := foo.a; v != 42 {
|
||||
t.Fatalf("foo.a expected 42, but got %d", v)
|
||||
}
|
||||
|
||||
// explicitly dereference a C variable
|
||||
if v := (*C.issue9557foo).a; v != 42 {
|
||||
t.Fatalf("(*C.issue9557foo).a expected 42, but is %d", v)
|
||||
}
|
||||
|
||||
// implicitly dereference a C variable
|
||||
if v := C.issue9557foo.a; v != 42 {
|
||||
t.Fatalf("C.issue9557foo.a expected 42, but is %d", v)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
// Copyright 2013 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.
|
||||
|
||||
#include "runtime.h"
|
||||
#include "cdefstest.h"
|
||||
|
||||
struct CdefsTest test;
|
||||
struct PackedTest packed;
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
// +build ignore
|
||||
|
||||
package cgotest
|
||||
|
||||
/*
|
||||
// This file tests a bug found in the cgo -cdefs tool that incorrectly
|
||||
// translated Go pointer arrays generated by the cgo godefs tool back into C
|
||||
// pointer arrays.
|
||||
//
|
||||
// The comments below show how the type is translated from gcc-style C into Go
|
||||
// and back into C for both the buggy version and the correct version
|
||||
|
||||
struct cdefsTest {
|
||||
// This was already being handled correctly
|
||||
// Correct: -> Array [20]int8 -> int8 array[20]
|
||||
char array1[20];
|
||||
|
||||
// Buggy: -> Array [20][20]int8 -> [20]int8 array[20]
|
||||
// Correct: -> Array [20][20]int8 -> int8 array[20][20]
|
||||
char array2[20][20];
|
||||
|
||||
// Buggy: -> Array [20]*int8 -> *int8 array[20]
|
||||
// Correct: -> Array [20]*int8 -> int8 *array[20]
|
||||
char *array3[20];
|
||||
|
||||
// Buggy: -> Array [20][20]*int8 -> [20]*int8 array[20]
|
||||
// Correct: -> Array [20]**int8 -> int8 *array[20][20]
|
||||
char *array4[20][20];
|
||||
|
||||
// Buggy: -> Array [20][20]**int8 -> [20]**int8 array[20]
|
||||
// Correct: -> Array [20][20]**int8 -> int8 **array[20][20]
|
||||
char **array5[20][20];
|
||||
};
|
||||
|
||||
// Test that packed structures can be translated to C correctly too.
|
||||
// See issue 8477.
|
||||
|
||||
struct packedTest {
|
||||
char first;
|
||||
int second;
|
||||
long long third;
|
||||
} __attribute__((packed));
|
||||
|
||||
// Test that conflicting type definitions don't cause problems with cgo.
|
||||
// See issue 8477.
|
||||
|
||||
typedef struct timespec {
|
||||
double bogus;
|
||||
} pid_t;
|
||||
|
||||
*/
|
||||
import "C"
|
||||
|
||||
type CdefsTest C.struct_cdefsTest
|
||||
|
||||
//type PackedTest C.struct_packedTest
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
// Copyright 2013 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.
|
||||
|
||||
#include "runtime.h"
|
||||
#include "cdefstest.h"
|
||||
|
||||
void runtime·printf(int8*, ...);
|
||||
|
||||
// From cdefstest.go.
|
||||
typedef struct CdefsOrig CdefsOrig;
|
||||
struct CdefsOrig {
|
||||
int8 array1[20];
|
||||
int8 array2[20][20];
|
||||
int8 *array3[20];
|
||||
int8 *array4[20][20];
|
||||
int8 **array5[20][20];
|
||||
};
|
||||
|
||||
// Packed structs are no longer supported for -cdefs.
|
||||
/*
|
||||
typedef struct PackedOrig PackedOrig;
|
||||
#pragma pack on
|
||||
struct PackedOrig {
|
||||
int8 first;
|
||||
int32 second;
|
||||
int64 third;
|
||||
};
|
||||
#pragma pack off
|
||||
*/
|
||||
|
||||
void
|
||||
main·test(int32 ret)
|
||||
{
|
||||
CdefsOrig o;
|
||||
CdefsTest t;
|
||||
// PackedOrig po;
|
||||
// PackedTest pt;
|
||||
|
||||
ret = 0;
|
||||
if(sizeof(t.array1) != sizeof(o.array1) || offsetof(CdefsTest, array1[0]) != offsetof(CdefsOrig, array1[0])) {
|
||||
runtime·printf("array1: size, offset = %d, %d, want %d, %d\n", sizeof(t.array1), offsetof(CdefsTest, array1[0]), sizeof(o.array1), offsetof(CdefsOrig, array1[0]));
|
||||
ret = 1;
|
||||
}
|
||||
if(sizeof(t.array2) != sizeof(o.array2) || offsetof(CdefsTest, array2[0][0]) != offsetof(CdefsOrig, array2[0][0])) {
|
||||
runtime·printf("array2: size, offset = %d, %d, want %d, %d\n", sizeof(t.array2), offsetof(CdefsTest, array2[0][0]), sizeof(o.array2), offsetof(CdefsOrig, array2[0][0]));
|
||||
ret = 1;
|
||||
}
|
||||
if(sizeof(t.array3) != sizeof(o.array3) || offsetof(CdefsTest, array3[0]) != offsetof(CdefsOrig, array3[0])) {
|
||||
runtime·printf("array3: size, offset = %d, %d, want %d, %d\n", sizeof(t.array3), offsetof(CdefsTest, array3[0]), sizeof(o.array3), offsetof(CdefsOrig, array3[0]));
|
||||
ret = 1;
|
||||
}
|
||||
if(sizeof(t.array4) != sizeof(o.array4) || offsetof(CdefsTest, array4[0][0]) != offsetof(CdefsOrig, array4[0][0])) {
|
||||
runtime·printf("array4: size, offset = %d, %d, want %d, %d\n", sizeof(t.array4), offsetof(CdefsTest, array4[0][0]), sizeof(o.array4), offsetof(CdefsOrig, array4[0][0]));
|
||||
ret = 1;
|
||||
}
|
||||
if(sizeof(t.array5) != sizeof(o.array5) || offsetof(CdefsTest, array5[0][0]) != offsetof(CdefsOrig, array5[0][0])) {
|
||||
runtime·printf("array5: size, offset = %d, %d, want %d, %d\n", sizeof(t.array5), offsetof(CdefsTest, array5[0][0]), sizeof(o.array5), offsetof(CdefsOrig, array5[0][0]));
|
||||
ret = 1;
|
||||
}
|
||||
/*
|
||||
if(sizeof(pt.first) != sizeof(po.first) || offsetof(PackedTest, first) != offsetof(PackedOrig, first)) {
|
||||
runtime·printf("first: size, offset = %d, %d, want %d, %d\n", sizeof(pt.first), offsetof(PackedTest, first), sizeof(po.first), offsetof(PackedOrig, first));
|
||||
ret = 1;
|
||||
}
|
||||
if(sizeof(pt.second) != sizeof(po.second) || offsetof(PackedTest, second) != offsetof(PackedOrig, second)) {
|
||||
runtime·printf("second: size, offset = %d, %d, want %d, %d\n", sizeof(pt.second), offsetof(PackedTest, second), sizeof(po.second), offsetof(PackedOrig, second));
|
||||
ret = 1;
|
||||
}
|
||||
if(sizeof(pt.third) != sizeof(po.third) || offsetof(PackedTest, third) != offsetof(PackedOrig, third)) {
|
||||
runtime·printf("third: size, offset = %d, %d, want %d, %d\n", sizeof(pt.third), offsetof(PackedTest, third), sizeof(po.third), offsetof(PackedOrig, third));
|
||||
ret = 1;
|
||||
}
|
||||
*/
|
||||
FLUSH(&ret); // flush return value
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import "os"
|
||||
|
||||
func test() int32 // in main.c
|
||||
|
||||
func main() {
|
||||
os.Exit(int(test()))
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
# Copyright 2013 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.
|
||||
|
||||
# Just add issue file prefixes to this list if more issues come up
|
||||
FILE_PREFIXES="cdefstest"
|
||||
|
||||
for FP in $FILE_PREFIXES
|
||||
do
|
||||
go tool cgo -cdefs ${FP}.go > ${FP}.h
|
||||
done
|
||||
|
||||
go build . && ./testcdefs
|
||||
EXIT=$?
|
||||
rm -rf _obj testcdefs *.h
|
||||
exit $EXIT
|
||||
|
|
@ -30,15 +30,16 @@ import (
|
|||
"runtime"
|
||||
"strings"
|
||||
|
||||
"code.google.com/p/goauth2/oauth"
|
||||
storage "code.google.com/p/google-api-go-client/storage/v1"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/google"
|
||||
)
|
||||
|
||||
var (
|
||||
tag = flag.String("tag", "release", "mercurial tag to check out")
|
||||
toolTag = flag.String("tool", defaultToolTag, "go.tools tag to check out")
|
||||
tag = flag.String("tag", "", "git revision to check out")
|
||||
toolTag = flag.String("tool", defaultToolTag, "go.tools revision to check out")
|
||||
tourTag = flag.String("tour", defaultTourTag, "go-tour tag to check out")
|
||||
repo = flag.String("repo", "https://code.google.com/p/go", "repo URL")
|
||||
repo = flag.String("repo", "https://go.googlesource.com/go", "repo URL")
|
||||
verbose = flag.Bool("v", false, "verbose output")
|
||||
upload = flag.Bool("upload", false, "upload resulting files to Google Code")
|
||||
addLabel = flag.String("label", "", "additional label to apply to file when uploading")
|
||||
|
|
@ -80,9 +81,9 @@ var preBuildCleanFiles = []string{
|
|||
}
|
||||
|
||||
var cleanFiles = []string{
|
||||
".hg",
|
||||
".hgtags",
|
||||
".hgignore",
|
||||
".git",
|
||||
".gitignore",
|
||||
".gitattributes",
|
||||
"VERSION.cache",
|
||||
}
|
||||
|
||||
|
|
@ -140,6 +141,10 @@ func main() {
|
|||
os.Exit(2)
|
||||
}
|
||||
flag.Parse()
|
||||
if *tag == "" {
|
||||
fmt.Fprintln(os.Stderr, "you must specify a -tag")
|
||||
os.Exit(2)
|
||||
}
|
||||
if flag.NArg() == 0 {
|
||||
flag.Usage()
|
||||
}
|
||||
|
|
@ -236,11 +241,11 @@ func (b *Build) Do() error {
|
|||
b.gopath = work
|
||||
|
||||
// Clone Go distribution and update to tag.
|
||||
_, err = b.hgCmd(work, "clone", *repo, b.root)
|
||||
_, err = b.run(work, "git", "clone", *repo, b.root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = b.hgCmd(b.root, "update", *tag)
|
||||
_, err = b.run(b.root, "git", "checkout", *tag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -620,10 +625,6 @@ func ext() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (b *Build) hgCmd(dir string, args ...string) ([]byte, error) {
|
||||
return b.run(dir, "hg", append([]string{"--config", "extensions.codereview=!"}, args...)...)
|
||||
}
|
||||
|
||||
func (b *Build) run(dir, name string, args ...string) ([]byte, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
absName, err := lookPath(name)
|
||||
|
|
@ -749,18 +750,13 @@ type File struct {
|
|||
}
|
||||
|
||||
func setupOAuthClient() error {
|
||||
config := &oauth.Config{
|
||||
ClientId: "999119582588-h7kpj5pcm6d9solh5lgrbusmvvk4m9dn.apps.googleusercontent.com",
|
||||
config := &oauth2.Config{
|
||||
ClientID: "999119582588-h7kpj5pcm6d9solh5lgrbusmvvk4m9dn.apps.googleusercontent.com",
|
||||
ClientSecret: "8YLFgOhXIELWbO-NtF3iqIQz",
|
||||
Scope: storage.DevstorageRead_writeScope,
|
||||
AuthURL: "https://accounts.google.com/o/oauth2/auth",
|
||||
TokenURL: "https://accounts.google.com/o/oauth2/token",
|
||||
TokenCache: oauth.CacheFile(*tokenCache),
|
||||
RedirectURL: "oob",
|
||||
Endpoint: google.Endpoint,
|
||||
Scopes: []string{storage.DevstorageRead_writeScope},
|
||||
}
|
||||
transport := &oauth.Transport{Config: config}
|
||||
if token, err := config.TokenCache.Token(); err != nil {
|
||||
url := transport.Config.AuthCodeURL("")
|
||||
url := config.AuthCodeURL("junk")
|
||||
fmt.Println("Visit the following URL, obtain an authentication" +
|
||||
"code, and enter it below.")
|
||||
fmt.Println(url)
|
||||
|
|
@ -769,13 +765,11 @@ func setupOAuthClient() error {
|
|||
if _, err := fmt.Scan(&code); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := transport.Exchange(code); err != nil {
|
||||
tok, err := config.Exchange(oauth2.NoContext, code)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
transport.Token = token
|
||||
}
|
||||
oauthClient = transport.Client()
|
||||
oauthClient = config.Client(oauth2.NoContext, tok)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -1011,6 +1005,11 @@ var hgTool = tool{
|
|||
},
|
||||
}
|
||||
|
||||
var gitTool = tool{
|
||||
"http://git-scm.com/download/win",
|
||||
[]string{`C:\Program Files\Git`, `C:\Program Files (x86)\Git`},
|
||||
}
|
||||
|
||||
var gccTool = tool{
|
||||
"Mingw gcc; http://sourceforge.net/projects/mingw/files/Installer/mingw-get-inst/",
|
||||
[]string{`C:\Mingw\bin`},
|
||||
|
|
@ -1022,6 +1021,7 @@ var windowsDeps = map[string]tool{
|
|||
"candle": wixTool,
|
||||
"light": wixTool,
|
||||
"cmd": {"Windows cmd.exe", nil},
|
||||
"git": gitTool,
|
||||
"hg": hgTool,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import "testing"
|
|||
// as expected.
|
||||
func TestRead(t *testing.T) {
|
||||
f := Fopen("file_test.go", "r")
|
||||
if f == nil {
|
||||
if f.Swigcptr() == 0 {
|
||||
t.Fatal("fopen failed")
|
||||
}
|
||||
if Fgetc(f) != '/' || Fgetc(f) != '/' || Fgetc(f) != ' ' || Fgetc(f) != 'C' {
|
||||
|
|
|
|||
|
|
@ -122,6 +122,8 @@ main(int argc, char *argv[])
|
|||
if(assemble(argv[0]))
|
||||
errorexit();
|
||||
Bflush(&bstdout);
|
||||
if(nerrors > 0)
|
||||
errorexit();
|
||||
exits(0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -371,6 +371,15 @@ archreloc(Reloc *r, LSym *s, vlong *val)
|
|||
return -1;
|
||||
}
|
||||
|
||||
vlong
|
||||
archrelocvariant(Reloc *r, LSym *s, vlong t)
|
||||
{
|
||||
USED(r);
|
||||
USED(s);
|
||||
sysfatal("unexpected relocation variant");
|
||||
return t;
|
||||
}
|
||||
|
||||
static Reloc *
|
||||
addpltreloc(Link *ctxt, LSym *plt, LSym *got, LSym *sym, int typ)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ void adddynrel(LSym *s, Reloc *r);
|
|||
void adddynrela(LSym *rel, LSym *s, Reloc *r);
|
||||
void adddynsym(Link *ctxt, LSym *s);
|
||||
int archreloc(Reloc *r, LSym *s, vlong *val);
|
||||
vlong archrelocvariant(Reloc *r, LSym *s, vlong t);
|
||||
void asmb(void);
|
||||
int elfreloc1(Reloc *r, vlong sectoff);
|
||||
void elfsetupplt(void);
|
||||
|
|
|
|||
|
|
@ -132,6 +132,8 @@ main(int argc, char *argv[])
|
|||
if(assemble(argv[0]))
|
||||
errorexit();
|
||||
Bflush(&bstdout);
|
||||
if(nerrors > 0)
|
||||
errorexit();
|
||||
exits(0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -624,7 +624,6 @@ bignodes(void)
|
|||
* t = f
|
||||
* hard part is conversions.
|
||||
*/
|
||||
// TODO: lost special constants for floating point. XORPD for 0.0?
|
||||
void
|
||||
gmove(Node *f, Node *t)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ peep(Prog *firstp)
|
|||
case AMOVSS:
|
||||
case AMOVSD:
|
||||
if(regtyp(&p->to))
|
||||
if(p->from.type == D_CONST)
|
||||
if(p->from.type == D_CONST || p->from.type == D_FCONST)
|
||||
conprop(r);
|
||||
break;
|
||||
}
|
||||
|
|
@ -384,7 +384,7 @@ regtyp(Adr *a)
|
|||
t = a->type;
|
||||
if(t >= D_AX && t <= D_R15)
|
||||
return 1;
|
||||
if(t >= D_X0 && t <= D_X0+15)
|
||||
if(t >= D_X0 && t <= D_X15)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -396,6 +396,15 @@ archreloc(Reloc *r, LSym *s, vlong *val)
|
|||
return -1;
|
||||
}
|
||||
|
||||
vlong
|
||||
archrelocvariant(Reloc *r, LSym *s, vlong t)
|
||||
{
|
||||
USED(r);
|
||||
USED(s);
|
||||
sysfatal("unexpected relocation variant");
|
||||
return t;
|
||||
}
|
||||
|
||||
void
|
||||
elfsetupplt(void)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ void adddynrel(LSym *s, Reloc *r);
|
|||
void adddynrela(LSym *rela, LSym *s, Reloc *r);
|
||||
void adddynsym(Link *ctxt, LSym *s);
|
||||
int archreloc(Reloc *r, LSym *s, vlong *val);
|
||||
vlong archrelocvariant(Reloc *r, LSym *s, vlong t);
|
||||
void asmb(void);
|
||||
int elfreloc1(Reloc *r, vlong sectoff);
|
||||
void elfsetupplt(void);
|
||||
|
|
|
|||
|
|
@ -127,6 +127,8 @@ main(int argc, char *argv[])
|
|||
if(assemble(argv[0]))
|
||||
errorexit();
|
||||
Bflush(&bstdout);
|
||||
if(nerrors > 0)
|
||||
errorexit();
|
||||
exits(0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ peep(Prog *firstp)
|
|||
case AMOVSS:
|
||||
case AMOVSD:
|
||||
if(regtyp(&p->to))
|
||||
if(p->from.type == D_CONST)
|
||||
if(p->from.type == D_CONST || p->from.type == D_FCONST)
|
||||
conprop(r);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -364,6 +364,15 @@ archreloc(Reloc *r, LSym *s, vlong *val)
|
|||
return -1;
|
||||
}
|
||||
|
||||
vlong
|
||||
archrelocvariant(Reloc *r, LSym *s, vlong t)
|
||||
{
|
||||
USED(r);
|
||||
USED(s);
|
||||
sysfatal("unexpected relocation variant");
|
||||
return t;
|
||||
}
|
||||
|
||||
void
|
||||
elfsetupplt(void)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ void adddynrel(LSym *s, Reloc *r);
|
|||
void adddynrela(LSym *rela, LSym *s, Reloc *r);
|
||||
void adddynsym(Link *ctxt, LSym *s);
|
||||
int archreloc(Reloc *r, LSym *s, vlong *val);
|
||||
vlong archrelocvariant(Reloc *r, LSym *s, vlong t);
|
||||
void asmb(void);
|
||||
int elfreloc1(Reloc *r, vlong sectoff);
|
||||
void elfsetupplt(void);
|
||||
|
|
|
|||
|
|
@ -131,6 +131,8 @@ main(int argc, char *argv[])
|
|||
if(assemble(argv[0]))
|
||||
errorexit();
|
||||
Bflush(&bstdout);
|
||||
if(nerrors > 0)
|
||||
errorexit();
|
||||
exits(0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -262,8 +262,15 @@ afunclit(Addr *a, Node *n)
|
|||
static int resvd[] =
|
||||
{
|
||||
REGZERO,
|
||||
REGSP, // reserved for SP, XXX: not reserved in 9c.
|
||||
30, // for g
|
||||
REGSP, // reserved for SP
|
||||
// We need to preserve the C ABI TLS pointer because sigtramp
|
||||
// may happen during C code and needs to access the g. C
|
||||
// clobbers REGG, so if Go were to clobber REGTLS, sigtramp
|
||||
// won't know which convention to use. By preserving REGTLS,
|
||||
// we can just retrieve g from TLS when we aren't sure.
|
||||
REGTLS,
|
||||
// TODO(austin): Consolidate REGTLS and REGG?
|
||||
REGG,
|
||||
REGTMP, // REGTMP
|
||||
FREGCVI+NREG,
|
||||
FREGZERO+NREG,
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ regopt(Prog *firstp)
|
|||
}
|
||||
|
||||
// Exclude registers with fixed functions
|
||||
regbits = (1<<D_R0)|RtoB(REGSP)|RtoB(REGG);
|
||||
regbits = (1<<D_R0)|RtoB(REGSP)|RtoB(REGG)|RtoB(REGTLS);
|
||||
// Also exclude floating point registers with fixed constants
|
||||
regbits |= FtoB(D_F0+27)|FtoB(D_F0+28)|FtoB(D_F0+29)|FtoB(D_F0+30)|FtoB(D_F0+31);
|
||||
externs = zbits;
|
||||
|
|
|
|||
|
|
@ -30,10 +30,13 @@
|
|||
/*
|
||||
* powerpc 64
|
||||
*/
|
||||
#define NSNAME 8
|
||||
#define NSYM 50
|
||||
#define NREG 32 /* number of general registers */
|
||||
#define NFREG 32 /* number of floating point registers */
|
||||
enum
|
||||
{
|
||||
NSNAME = 8,
|
||||
NSYM = 50,
|
||||
NREG = 32, /* number of general registers */
|
||||
NFREG = 32, /* number of floating point registers */
|
||||
};
|
||||
|
||||
#include "../ld/textflag.h"
|
||||
|
||||
|
|
@ -48,6 +51,7 @@ enum
|
|||
REGRT2 = 4, /* reserved for runtime, duffcopy */
|
||||
REGMIN = 7, /* register variables allocated from here to REGMAX */
|
||||
REGENV = 11, /* environment for closures */
|
||||
REGTLS = 13, /* C ABI TLS base pointer */
|
||||
REGMAX = 27,
|
||||
REGEXT = 30, /* external registers allocated from here down */
|
||||
REGG = 30, /* G */
|
||||
|
|
|
|||
512
src/cmd/9l/asm.c
512
src/cmd/9l/asm.c
|
|
@ -36,6 +36,7 @@
|
|||
#include "../ld/dwarf.h"
|
||||
|
||||
|
||||
// TODO(austin): ABI v1 uses /usr/lib/ld.so.1
|
||||
char linuxdynld[] = "/lib64/ld64.so.1";
|
||||
char freebsddynld[] = "XXX";
|
||||
char openbsddynld[] = "XXX";
|
||||
|
|
@ -65,27 +66,264 @@ needlib(char *name)
|
|||
|
||||
int nelfsym = 1;
|
||||
|
||||
static void gencallstub(int abicase, LSym *stub, LSym *targ);
|
||||
static void addpltsym(Link*, LSym*);
|
||||
static LSym* ensureglinkresolver(void);
|
||||
|
||||
void
|
||||
gentext(void)
|
||||
{
|
||||
LSym *s, *stub, **pprevtextp;
|
||||
Reloc *r;
|
||||
char *n;
|
||||
uint32 o1;
|
||||
uchar *cast;
|
||||
int i;
|
||||
|
||||
// The ppc64 ABI PLT has similar concepts to other
|
||||
// architectures, but is laid out quite differently. When we
|
||||
// see an R_PPC64_REL24 relocation to a dynamic symbol
|
||||
// (indicating that the call needs to go through the PLT), we
|
||||
// generate up to three stubs and reserve a PLT slot.
|
||||
//
|
||||
// 1) The call site will be bl x; nop (where the relocation
|
||||
// applies to the bl). We rewrite this to bl x_stub; ld
|
||||
// r2,24(r1). The ld is necessary because x_stub will save
|
||||
// r2 (the TOC pointer) at 24(r1) (the "TOC save slot").
|
||||
//
|
||||
// 2) We reserve space for a pointer in the .plt section (once
|
||||
// per referenced dynamic function). .plt is a data
|
||||
// section filled solely by the dynamic linker (more like
|
||||
// .plt.got on other architectures). Initially, the
|
||||
// dynamic linker will fill each slot with a pointer to the
|
||||
// corresponding x@plt entry point.
|
||||
//
|
||||
// 3) We generate the "call stub" x_stub (once per dynamic
|
||||
// function/object file pair). This saves the TOC in the
|
||||
// TOC save slot, reads the function pointer from x's .plt
|
||||
// slot and calls it like any other global entry point
|
||||
// (including setting r12 to the function address).
|
||||
//
|
||||
// 4) We generate the "symbol resolver stub" x@plt (once per
|
||||
// dynamic function). This is solely a branch to the glink
|
||||
// resolver stub.
|
||||
//
|
||||
// 5) We generate the glink resolver stub (only once). This
|
||||
// computes which symbol resolver stub we came through and
|
||||
// invokes the dynamic resolver via a pointer provided by
|
||||
// the dynamic linker. This will patch up the .plt slot to
|
||||
// point directly at the function so future calls go
|
||||
// straight from the call stub to the real function, and
|
||||
// then call the function.
|
||||
|
||||
// NOTE: It's possible we could make ppc64 closer to other
|
||||
// architectures: ppc64's .plt is like .plt.got on other
|
||||
// platforms and ppc64's .glink is like .plt on other
|
||||
// platforms.
|
||||
|
||||
// Find all R_PPC64_REL24 relocations that reference dynamic
|
||||
// imports. Reserve PLT entries for these symbols and
|
||||
// generate call stubs. The call stubs need to live in .text,
|
||||
// which is why we need to do this pass this early.
|
||||
//
|
||||
// This assumes "case 1" from the ABI, where the caller needs
|
||||
// us to save and restore the TOC pointer.
|
||||
pprevtextp = &ctxt->textp;
|
||||
for(s=*pprevtextp; s!=S; pprevtextp=&s->next, s=*pprevtextp) {
|
||||
for(r=s->r; r<s->r+s->nr; r++) {
|
||||
if(!(r->type == 256 + R_PPC64_REL24 &&
|
||||
r->sym->type == SDYNIMPORT))
|
||||
continue;
|
||||
|
||||
// Reserve PLT entry and generate symbol
|
||||
// resolver
|
||||
addpltsym(ctxt, r->sym);
|
||||
|
||||
// Generate call stub
|
||||
n = smprint("%s.%s", s->name, r->sym->name);
|
||||
stub = linklookup(ctxt, n, 0);
|
||||
free(n);
|
||||
stub->reachable |= s->reachable;
|
||||
if(stub->size == 0) {
|
||||
// Need outer to resolve .TOC.
|
||||
stub->outer = s;
|
||||
|
||||
// Link in to textp before s (we could
|
||||
// do it after, but would have to skip
|
||||
// the subsymbols)
|
||||
*pprevtextp = stub;
|
||||
stub->next = s;
|
||||
pprevtextp = &stub->next;
|
||||
|
||||
gencallstub(1, stub, r->sym);
|
||||
}
|
||||
|
||||
// Update the relocation to use the call stub
|
||||
r->sym = stub;
|
||||
|
||||
// Restore TOC after bl. The compiler put a
|
||||
// nop here for us to overwrite.
|
||||
o1 = 0xe8410018; // ld r2,24(r1)
|
||||
cast = (uchar*)&o1;
|
||||
for(i=0; i<4; i++)
|
||||
s->p[r->off+4+i] = cast[inuxi4[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Construct a call stub in stub that calls symbol targ via its PLT
|
||||
// entry.
|
||||
static void
|
||||
gencallstub(int abicase, LSym *stub, LSym *targ)
|
||||
{
|
||||
LSym *plt;
|
||||
Reloc *r;
|
||||
|
||||
if(abicase != 1)
|
||||
// If we see R_PPC64_TOCSAVE or R_PPC64_REL24_NOTOC
|
||||
// relocations, we'll need to implement cases 2 and 3.
|
||||
sysfatal("gencallstub only implements case 1 calls");
|
||||
|
||||
plt = linklookup(ctxt, ".plt", 0);
|
||||
|
||||
stub->type = STEXT;
|
||||
|
||||
// Save TOC pointer in TOC save slot
|
||||
adduint32(ctxt, stub, 0xf8410018); // std r2,24(r1)
|
||||
|
||||
// Load the function pointer from the PLT.
|
||||
r = addrel(stub);
|
||||
r->off = stub->size;
|
||||
r->sym = plt;
|
||||
r->add = targ->plt;
|
||||
r->siz = 2;
|
||||
if(ctxt->arch->endian == BigEndian)
|
||||
r->off += r->siz;
|
||||
r->type = R_POWER_TOC;
|
||||
r->variant = RV_POWER_HA;
|
||||
adduint32(ctxt, stub, 0x3d820000); // addis r12,r2,targ@plt@toc@ha
|
||||
r = addrel(stub);
|
||||
r->off = stub->size;
|
||||
r->sym = plt;
|
||||
r->add = targ->plt;
|
||||
r->siz = 2;
|
||||
if(ctxt->arch->endian == BigEndian)
|
||||
r->off += r->siz;
|
||||
r->type = R_POWER_TOC;
|
||||
r->variant = RV_POWER_LO;
|
||||
adduint32(ctxt, stub, 0xe98c0000); // ld r12,targ@plt@toc@l(r12)
|
||||
|
||||
// Jump to the loaded pointer
|
||||
adduint32(ctxt, stub, 0x7d8903a6); // mtctr r12
|
||||
adduint32(ctxt, stub, 0x4e800420); // bctr
|
||||
}
|
||||
|
||||
void
|
||||
adddynrela(LSym *rel, LSym *s, Reloc *r)
|
||||
{
|
||||
// TODO(minux)
|
||||
USED(rel); USED(s); USED(r);
|
||||
sysfatal("adddynrela not implemented");
|
||||
}
|
||||
|
||||
void
|
||||
adddynrel(LSym *s, Reloc *r)
|
||||
{
|
||||
LSym *targ;
|
||||
|
||||
// TODO(minux)
|
||||
LSym *targ, *rela;
|
||||
|
||||
targ = r->sym;
|
||||
ctxt->cursym = s;
|
||||
|
||||
switch(r->type) {
|
||||
default:
|
||||
if(r->type >= 256) {
|
||||
diag("unexpected relocation type %d", r->type);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
// Handle relocations found in ELF object files.
|
||||
case 256 + R_PPC64_REL24:
|
||||
r->type = R_CALLPOWER;
|
||||
// This is a local call, so the caller isn't setting
|
||||
// up r12 and r2 is the same for the caller and
|
||||
// callee. Hence, we need to go to the local entry
|
||||
// point. (If we don't do this, the callee will try
|
||||
// to use r12 to compute r2.)
|
||||
r->add += r->sym->localentry * 4;
|
||||
if(targ->type == SDYNIMPORT)
|
||||
// Should have been handled in elfsetupplt
|
||||
diag("unexpected R_PPC64_REL24 for dyn import");
|
||||
return;
|
||||
|
||||
case 256 + R_PPC64_ADDR64:
|
||||
r->type = R_ADDR;
|
||||
if(targ->type == SDYNIMPORT) {
|
||||
// These happen in .toc sections
|
||||
adddynsym(ctxt, targ);
|
||||
|
||||
rela = linklookup(ctxt, ".rela", 0);
|
||||
addaddrplus(ctxt, rela, s, r->off);
|
||||
adduint64(ctxt, rela, ELF64_R_INFO(targ->dynid, R_PPC64_ADDR64));
|
||||
adduint64(ctxt, rela, r->add);
|
||||
r->type = 256; // ignore during relocsym
|
||||
}
|
||||
return;
|
||||
|
||||
case 256 + R_PPC64_TOC16:
|
||||
r->type = R_POWER_TOC;
|
||||
r->variant = RV_POWER_LO | RV_CHECK_OVERFLOW;
|
||||
return;
|
||||
|
||||
case 256 + R_PPC64_TOC16_LO:
|
||||
r->type = R_POWER_TOC;
|
||||
r->variant = RV_POWER_LO;
|
||||
return;
|
||||
|
||||
case 256 + R_PPC64_TOC16_HA:
|
||||
r->type = R_POWER_TOC;
|
||||
r->variant = RV_POWER_HA | RV_CHECK_OVERFLOW;
|
||||
return;
|
||||
|
||||
case 256 + R_PPC64_TOC16_HI:
|
||||
r->type = R_POWER_TOC;
|
||||
r->variant = RV_POWER_HI | RV_CHECK_OVERFLOW;
|
||||
return;
|
||||
|
||||
case 256 + R_PPC64_TOC16_DS:
|
||||
r->type = R_POWER_TOC;
|
||||
r->variant = RV_POWER_DS | RV_CHECK_OVERFLOW;
|
||||
return;
|
||||
|
||||
case 256 + R_PPC64_TOC16_LO_DS:
|
||||
r->type = R_POWER_TOC;
|
||||
r->variant = RV_POWER_DS;
|
||||
return;
|
||||
|
||||
case 256 + R_PPC64_REL16_LO:
|
||||
r->type = R_PCREL;
|
||||
r->variant = RV_POWER_LO;
|
||||
r->add += 2; // Compensate for relocation size of 2
|
||||
return;
|
||||
|
||||
case 256 + R_PPC64_REL16_HI:
|
||||
r->type = R_PCREL;
|
||||
r->variant = RV_POWER_HI | RV_CHECK_OVERFLOW;
|
||||
r->add += 2;
|
||||
return;
|
||||
|
||||
case 256 + R_PPC64_REL16_HA:
|
||||
r->type = R_PCREL;
|
||||
r->variant = RV_POWER_HA | RV_CHECK_OVERFLOW;
|
||||
r->add += 2;
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle references to ELF symbols from our own object files.
|
||||
if(targ->type != SDYNIMPORT)
|
||||
return;
|
||||
|
||||
// TODO(austin): Translate our relocations to ELF
|
||||
|
||||
diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
|
||||
}
|
||||
|
||||
|
|
@ -100,8 +338,16 @@ elfreloc1(Reloc *r, vlong sectoff)
|
|||
void
|
||||
elfsetupplt(void)
|
||||
{
|
||||
// TODO(minux)
|
||||
return;
|
||||
LSym *plt;
|
||||
|
||||
plt = linklookup(ctxt, ".plt", 0);
|
||||
if(plt->size == 0) {
|
||||
// The dynamic linker stores the address of the
|
||||
// dynamic resolver and the DSO identifier in the two
|
||||
// doublewords at the beginning of the .plt section
|
||||
// before the PLT array. Reserve space for these.
|
||||
plt->size = 16;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -113,12 +359,29 @@ machoreloc1(Reloc *r, vlong sectoff)
|
|||
return -1;
|
||||
}
|
||||
|
||||
// Return the value of .TOC. for symbol s
|
||||
static vlong
|
||||
symtoc(LSym *s)
|
||||
{
|
||||
LSym *toc;
|
||||
|
||||
if(s->outer != nil)
|
||||
toc = linkrlookup(ctxt, ".TOC.", s->outer->version);
|
||||
else
|
||||
toc = linkrlookup(ctxt, ".TOC.", s->version);
|
||||
|
||||
if(toc == nil) {
|
||||
diag("TOC-relative relocation in object without .TOC.");
|
||||
return 0;
|
||||
}
|
||||
return toc->value;
|
||||
}
|
||||
|
||||
int
|
||||
archreloc(Reloc *r, LSym *s, vlong *val)
|
||||
{
|
||||
uint32 o1, o2;
|
||||
int32 t;
|
||||
vlong t;
|
||||
|
||||
if(linkmode == LinkExternal) {
|
||||
// TODO(minux): translate R_ADDRPOWER and R_CALLPOWER into standard ELF relocations.
|
||||
|
|
@ -166,23 +429,252 @@ archreloc(Reloc *r, LSym *s, vlong *val)
|
|||
t = symaddr(r->sym) + r->add - (s->value + r->off);
|
||||
if(t & 3)
|
||||
ctxt->diag("relocation for %s+%d is not aligned: %lld", r->sym->name, r->off, t);
|
||||
if(t << 6 >> 6 != t)
|
||||
if((int32)(t << 6) >> 6 != t)
|
||||
// TODO(austin) This can happen if text > 32M.
|
||||
// Add a call trampoline to .text in that case.
|
||||
ctxt->diag("relocation for %s+%d is too big: %lld", r->sym->name, r->off, t);
|
||||
|
||||
*val = (o1 & 0xfc000003U) | (t & ~0xfc000003U);
|
||||
return 0;
|
||||
case R_POWER_TOC: // S + A - .TOC.
|
||||
*val = symaddr(r->sym) + r->add - symtoc(s);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
vlong
|
||||
archrelocvariant(Reloc *r, LSym *s, vlong t)
|
||||
{
|
||||
uint32 o1;
|
||||
switch(r->variant & RV_TYPE_MASK) {
|
||||
default:
|
||||
diag("unexpected relocation variant %d", r->variant);
|
||||
|
||||
case RV_NONE:
|
||||
return t;
|
||||
|
||||
case RV_POWER_LO:
|
||||
if(r->variant & RV_CHECK_OVERFLOW) {
|
||||
// Whether to check for signed or unsigned
|
||||
// overflow depends on the instruction
|
||||
if(ctxt->arch->endian == BigEndian)
|
||||
o1 = be32(s->p + r->off - 2);
|
||||
else
|
||||
o1 = le32(s->p + r->off);
|
||||
switch(o1 >> 26) {
|
||||
case 24: // ori
|
||||
case 26: // xori
|
||||
case 28: // andi
|
||||
if((t >> 16) != 0)
|
||||
goto overflow;
|
||||
break;
|
||||
default:
|
||||
if((int16)t != t)
|
||||
goto overflow;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (int16)t;
|
||||
|
||||
case RV_POWER_HA:
|
||||
t += 0x8000;
|
||||
// Fallthrough
|
||||
case RV_POWER_HI:
|
||||
t >>= 16;
|
||||
if(r->variant & RV_CHECK_OVERFLOW) {
|
||||
// Whether to check for signed or unsigned
|
||||
// overflow depends on the instruction
|
||||
if(ctxt->arch->endian == BigEndian)
|
||||
o1 = be32(s->p + r->off - 2);
|
||||
else
|
||||
o1 = le32(s->p + r->off);
|
||||
switch(o1 >> 26) {
|
||||
case 25: // oris
|
||||
case 27: // xoris
|
||||
case 29: // andis
|
||||
if((t >> 16) != 0)
|
||||
goto overflow;
|
||||
break;
|
||||
default:
|
||||
if((int16)t != t)
|
||||
goto overflow;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (int16)t;
|
||||
|
||||
case RV_POWER_DS:
|
||||
if(ctxt->arch->endian == BigEndian)
|
||||
o1 = be16(s->p + r->off);
|
||||
else
|
||||
o1 = le16(s->p + r->off);
|
||||
if(t & 3)
|
||||
diag("relocation for %s+%d is not aligned: %lld", r->sym->name, r->off, t);
|
||||
if((r->variant & RV_CHECK_OVERFLOW) && (int16)t != t)
|
||||
goto overflow;
|
||||
return (o1 & 0x3) | (vlong)(int16)t;
|
||||
}
|
||||
|
||||
overflow:
|
||||
diag("relocation for %s+%d is too big: %lld", r->sym->name, r->off, t);
|
||||
return t;
|
||||
}
|
||||
|
||||
static void
|
||||
addpltsym(Link *ctxt, LSym *s)
|
||||
{
|
||||
if(s->plt >= 0)
|
||||
return;
|
||||
|
||||
adddynsym(ctxt, s);
|
||||
|
||||
if(iself) {
|
||||
LSym *plt, *rela, *glink;
|
||||
Reloc *r;
|
||||
|
||||
plt = linklookup(ctxt, ".plt", 0);
|
||||
rela = linklookup(ctxt, ".rela.plt", 0);
|
||||
if(plt->size == 0)
|
||||
elfsetupplt();
|
||||
|
||||
// Create the glink resolver if necessary
|
||||
glink = ensureglinkresolver();
|
||||
|
||||
// Write symbol resolver stub (just a branch to the
|
||||
// glink resolver stub)
|
||||
r = addrel(glink);
|
||||
r->sym = glink;
|
||||
r->off = glink->size;
|
||||
r->siz = 4;
|
||||
r->type = R_CALLPOWER;
|
||||
adduint32(ctxt, glink, 0x48000000); // b .glink
|
||||
|
||||
// In the ppc64 ABI, the dynamic linker is responsible
|
||||
// for writing the entire PLT. We just need to
|
||||
// reserve 8 bytes for each PLT entry and generate a
|
||||
// JMP_SLOT dynamic relocation for it.
|
||||
//
|
||||
// TODO(austin): ABI v1 is different
|
||||
s->plt = plt->size;
|
||||
plt->size += 8;
|
||||
|
||||
addaddrplus(ctxt, rela, plt, s->plt);
|
||||
adduint64(ctxt, rela, ELF64_R_INFO(s->dynid, R_PPC64_JMP_SLOT));
|
||||
adduint64(ctxt, rela, 0);
|
||||
} else {
|
||||
diag("addpltsym: unsupported binary format");
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the glink resolver stub if necessary and return the .glink section
|
||||
static LSym*
|
||||
ensureglinkresolver(void)
|
||||
{
|
||||
LSym *glink, *s;
|
||||
Reloc *r;
|
||||
|
||||
glink = linklookup(ctxt, ".glink", 0);
|
||||
if(glink->size != 0)
|
||||
return glink;
|
||||
|
||||
// This is essentially the resolver from the ppc64 ELF ABI.
|
||||
// At entry, r12 holds the address of the symbol resolver stub
|
||||
// for the target routine and the argument registers hold the
|
||||
// arguments for the target routine.
|
||||
//
|
||||
// This stub is PIC, so first get the PC of label 1 into r11.
|
||||
// Other things will be relative to this.
|
||||
adduint32(ctxt, glink, 0x7c0802a6); // mflr r0
|
||||
adduint32(ctxt, glink, 0x429f0005); // bcl 20,31,1f
|
||||
adduint32(ctxt, glink, 0x7d6802a6); // 1: mflr r11
|
||||
adduint32(ctxt, glink, 0x7c0803a6); // mtlf r0
|
||||
|
||||
// Compute the .plt array index from the entry point address.
|
||||
// Because this is PIC, everything is relative to label 1b (in
|
||||
// r11):
|
||||
// r0 = ((r12 - r11) - (res_0 - r11)) / 4 = (r12 - res_0) / 4
|
||||
adduint32(ctxt, glink, 0x3800ffd0); // li r0,-(res_0-1b)=-48
|
||||
adduint32(ctxt, glink, 0x7c006214); // add r0,r0,r12
|
||||
adduint32(ctxt, glink, 0x7c0b0050); // sub r0,r0,r11
|
||||
adduint32(ctxt, glink, 0x7800f082); // srdi r0,r0,2
|
||||
|
||||
// r11 = address of the first byte of the PLT
|
||||
r = addrel(glink);
|
||||
r->off = glink->size;
|
||||
r->sym = linklookup(ctxt, ".plt", 0);
|
||||
r->siz = 8;
|
||||
r->type = R_ADDRPOWER;
|
||||
// addis r11,0,.plt@ha; addi r11,r11,.plt@l
|
||||
r->add = (0x3d600000ull << 32) | 0x396b0000;
|
||||
glink->size += 8;
|
||||
|
||||
// Load r12 = dynamic resolver address and r11 = DSO
|
||||
// identifier from the first two doublewords of the PLT.
|
||||
adduint32(ctxt, glink, 0xe98b0000); // ld r12,0(r11)
|
||||
adduint32(ctxt, glink, 0xe96b0008); // ld r11,8(r11)
|
||||
|
||||
// Jump to the dynamic resolver
|
||||
adduint32(ctxt, glink, 0x7d8903a6); // mtctr r12
|
||||
adduint32(ctxt, glink, 0x4e800420); // bctr
|
||||
|
||||
// The symbol resolvers must immediately follow.
|
||||
// res_0:
|
||||
|
||||
// Add DT_PPC64_GLINK .dynamic entry, which points to 32 bytes
|
||||
// before the first symbol resolver stub.
|
||||
s = linklookup(ctxt, ".dynamic", 0);
|
||||
elfwritedynentsymplus(s, DT_PPC64_GLINK, glink, glink->size - 32);
|
||||
|
||||
return glink;
|
||||
}
|
||||
|
||||
void
|
||||
adddynsym(Link *ctxt, LSym *s)
|
||||
{
|
||||
USED(ctxt); USED(s);
|
||||
// TODO(minux)
|
||||
LSym *d;
|
||||
int t;
|
||||
char *name;
|
||||
|
||||
if(s->dynid >= 0)
|
||||
return;
|
||||
|
||||
if(iself) {
|
||||
s->dynid = nelfsym++;
|
||||
|
||||
d = linklookup(ctxt, ".dynsym", 0);
|
||||
|
||||
name = s->extname;
|
||||
adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name));
|
||||
|
||||
/* type */
|
||||
t = STB_GLOBAL << 4;
|
||||
if(s->cgoexport && (s->type&SMASK) == STEXT)
|
||||
t |= STT_FUNC;
|
||||
else
|
||||
t |= STT_OBJECT;
|
||||
adduint8(ctxt, d, t);
|
||||
|
||||
/* reserved */
|
||||
adduint8(ctxt, d, 0);
|
||||
|
||||
/* section where symbol is defined */
|
||||
if(s->type == SDYNIMPORT)
|
||||
adduint16(ctxt, d, SHN_UNDEF);
|
||||
else
|
||||
adduint16(ctxt, d, 1);
|
||||
|
||||
/* value */
|
||||
if(s->type == SDYNIMPORT)
|
||||
adduint64(ctxt, d, 0);
|
||||
else
|
||||
addaddr(ctxt, d, s);
|
||||
|
||||
/* size of object */
|
||||
adduint64(ctxt, d, s->size);
|
||||
} else {
|
||||
diag("adddynsym: unsupported binary format");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ void adddynlib(char *lib);
|
|||
void adddynrel(LSym *s, Reloc *r);
|
||||
void adddynsym(Link *ctxt, LSym *s);
|
||||
int archreloc(Reloc *r, LSym *s, vlong *val);
|
||||
vlong archrelocvariant(Reloc *r, LSym *s, vlong t);
|
||||
void listinit(void);
|
||||
vlong rnd(vlong, int32);
|
||||
|
||||
|
|
|
|||
|
|
@ -80,7 +80,8 @@ archinit(void)
|
|||
INITRND = 4096;
|
||||
break;
|
||||
case Hlinux: /* ppc64 elf */
|
||||
debug['d'] = 1; // TODO(minux): dynamic linking is not supported yet.
|
||||
if(strcmp(thestring, "ppc64") == 0)
|
||||
debug['d'] = 1; // TODO(austin): ELF ABI v1 not supported yet
|
||||
elfinit();
|
||||
HEADR = ELFRESERVE;
|
||||
if(INITTEXT == -1)
|
||||
|
|
|
|||
|
|
@ -237,10 +237,6 @@ The following options are available when running cgo directly:
|
|||
Write out input file in Go syntax replacing C package
|
||||
names with real values. Used to generate files in the
|
||||
syscall package when bootstrapping a new target.
|
||||
-cdefs
|
||||
Like -godefs, but write file in C syntax.
|
||||
Used to generate files in the runtime package when
|
||||
bootstrapping a new target.
|
||||
-objdir directory
|
||||
Put all generated files in directory.
|
||||
-gccgo
|
||||
|
|
|
|||
|
|
@ -154,20 +154,6 @@ func splitQuoted(s string) (r []string, err error) {
|
|||
return args, err
|
||||
}
|
||||
|
||||
var safeBytes = []byte(`+-.,/0123456789:=ABCDEFGHIJKLMNOPQRSTUVWXYZ\_abcdefghijklmnopqrstuvwxyz`)
|
||||
|
||||
func safeName(s string) bool {
|
||||
if s == "" {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < len(s); i++ {
|
||||
if c := s[i]; c < 0x80 && bytes.IndexByte(safeBytes, c) < 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Translate rewrites f.AST, the original Go input, to remove
|
||||
// references to the imported package C, replacing them with
|
||||
// references to the equivalent Go types, functions, and variables.
|
||||
|
|
@ -582,7 +568,7 @@ func (p *Package) mangleName(n *Name) {
|
|||
|
||||
// rewriteRef rewrites all the C.xxx references in f.AST to refer to the
|
||||
// Go equivalents, now that we have figured out the meaning of all
|
||||
// the xxx. In *godefs or *cdefs mode, rewriteRef replaces the names
|
||||
// the xxx. In *godefs mode, rewriteRef replaces the names
|
||||
// with full definitions instead of mangled names.
|
||||
func (p *Package) rewriteRef(f *File) {
|
||||
// Keep a list of all the functions, to remove the ones
|
||||
|
|
@ -673,6 +659,13 @@ func (p *Package) rewriteRef(f *File) {
|
|||
expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
|
||||
}
|
||||
|
||||
case "selector":
|
||||
if r.Name.Kind == "var" {
|
||||
expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
|
||||
} else {
|
||||
error_(r.Pos(), "only C variables allowed in selector expression", fixGo(r.Name.Go))
|
||||
}
|
||||
|
||||
case "type":
|
||||
if r.Name.Kind != "type" {
|
||||
error_(r.Pos(), "expression C.%s used as type", fixGo(r.Name.Go))
|
||||
|
|
@ -688,7 +681,7 @@ func (p *Package) rewriteRef(f *File) {
|
|||
error_(r.Pos(), "must call C.%s", fixGo(r.Name.Go))
|
||||
}
|
||||
}
|
||||
if *godefs || *cdefs {
|
||||
if *godefs {
|
||||
// Substitute definition for mangled type name.
|
||||
if id, ok := expr.(*ast.Ident); ok {
|
||||
if t := typedef[id.Name]; t != nil {
|
||||
|
|
@ -992,8 +985,8 @@ func (c *typeConv) Init(ptrSize, intSize int64) {
|
|||
c.goVoid = c.Ident("_Ctype_void")
|
||||
|
||||
// Normally cgo translates void* to unsafe.Pointer,
|
||||
// but for historical reasons -cdefs and -godefs use *byte instead.
|
||||
if *cdefs || *godefs {
|
||||
// but for historical reasons -godefs uses *byte instead.
|
||||
if *godefs {
|
||||
c.goVoidPtr = &ast.StarExpr{X: c.byte}
|
||||
} else {
|
||||
c.goVoidPtr = c.Ident("unsafe.Pointer")
|
||||
|
|
@ -1334,8 +1327,8 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
|||
// If sub.Go.Name is "_Ctype_struct_foo" or "_Ctype_union_foo" or "_Ctype_class_foo",
|
||||
// use that as the Go form for this typedef too, so that the typedef will be interchangeable
|
||||
// with the base type.
|
||||
// In -godefs and -cdefs mode, do this for all typedefs.
|
||||
if isStructUnionClass(sub.Go) || *godefs || *cdefs {
|
||||
// In -godefs mode, do this for all typedefs.
|
||||
if isStructUnionClass(sub.Go) || *godefs {
|
||||
t.Go = sub.Go
|
||||
|
||||
if isStructUnionClass(sub.Go) {
|
||||
|
|
@ -1397,7 +1390,7 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
|||
name := c.Ident("_Ctype_" + s)
|
||||
tt := *t
|
||||
typedef[name.Name] = &tt
|
||||
if !*godefs && !*cdefs {
|
||||
if !*godefs {
|
||||
t.Go = name
|
||||
}
|
||||
}
|
||||
|
|
@ -1573,7 +1566,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
|
|||
used[f.Name] = true
|
||||
}
|
||||
|
||||
if !*godefs && !*cdefs {
|
||||
if !*godefs {
|
||||
for cid, goid := range ident {
|
||||
if token.Lookup(goid).IsKeyword() {
|
||||
// Avoid keyword
|
||||
|
|
@ -1600,12 +1593,12 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
|
|||
name := f.Name
|
||||
ft := f.Type
|
||||
|
||||
// In godefs or cdefs mode, if this field is a C11
|
||||
// In godefs mode, if this field is a C11
|
||||
// anonymous union then treat the first field in the
|
||||
// union as the field in the struct. This handles
|
||||
// cases like the glibc <sys/resource.h> file; see
|
||||
// issue 6677.
|
||||
if *godefs || *cdefs {
|
||||
if *godefs {
|
||||
if st, ok := f.Type.(*dwarf.StructType); ok && name == "" && st.Kind == "union" && len(st.Field) > 0 && !used[st.Field[0].Name] {
|
||||
name = st.Field[0].Name
|
||||
ident[name] = name
|
||||
|
|
@ -1635,14 +1628,12 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
|
|||
talign = size
|
||||
}
|
||||
|
||||
if talign > 0 && f.ByteOffset%talign != 0 && !*cdefs {
|
||||
if talign > 0 && f.ByteOffset%talign != 0 {
|
||||
// Drop misaligned fields, the same way we drop integer bit fields.
|
||||
// The goal is to make available what can be made available.
|
||||
// Otherwise one bad and unneeded field in an otherwise okay struct
|
||||
// makes the whole program not compile. Much of the time these
|
||||
// structs are in system headers that cannot be corrected.
|
||||
// Exception: In -cdefs mode, we use #pragma pack, so misaligned
|
||||
// fields should still work.
|
||||
continue
|
||||
}
|
||||
n := len(fld)
|
||||
|
|
@ -1672,7 +1663,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
|
|||
buf.WriteString("}")
|
||||
csyntax = buf.String()
|
||||
|
||||
if *godefs || *cdefs {
|
||||
if *godefs {
|
||||
godefsFields(fld)
|
||||
}
|
||||
expr = &ast.StructType{Fields: &ast.FieldList{List: fld}}
|
||||
|
|
@ -1707,12 +1698,10 @@ func godefsFields(fld []*ast.Field) {
|
|||
n.Name = "Pad_cgo_" + strconv.Itoa(npad)
|
||||
npad++
|
||||
}
|
||||
if !*cdefs {
|
||||
n.Name = upper(n.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fieldPrefix returns the prefix that should be removed from all the
|
||||
// field names when generating the C or Go code. For generated
|
||||
|
|
@ -1721,9 +1710,6 @@ func godefsFields(fld []*ast.Field) {
|
|||
// package syscall's data structures, we drop a common prefix
|
||||
// (so sec, usec, which will get turned into Sec, Usec for exporting).
|
||||
func fieldPrefix(fld []*ast.Field) string {
|
||||
if *cdefs {
|
||||
return ""
|
||||
}
|
||||
prefix := ""
|
||||
for _, f := range fld {
|
||||
for _, n := range f.Names {
|
||||
|
|
|
|||
|
|
@ -114,173 +114,6 @@ func (p *Package) godefs(f *File, srcfile string) string {
|
|||
return buf.String()
|
||||
}
|
||||
|
||||
// cdefs returns the output for -cdefs mode.
|
||||
// The easiest way to do this is to translate the godefs Go to C.
|
||||
func (p *Package) cdefs(f *File, srcfile string) string {
|
||||
godefsOutput := p.godefs(f, srcfile)
|
||||
|
||||
lines := strings.Split(godefsOutput, "\n")
|
||||
lines[0] = "// Created by cgo -cdefs - DO NOT EDIT"
|
||||
|
||||
for i, line := range lines {
|
||||
lines[i] = strings.TrimSpace(line)
|
||||
}
|
||||
|
||||
var out bytes.Buffer
|
||||
printf := func(format string, args ...interface{}) { fmt.Fprintf(&out, format, args...) }
|
||||
|
||||
didTypedef := false
|
||||
for i := 0; i < len(lines); i++ {
|
||||
line := lines[i]
|
||||
|
||||
// Delete
|
||||
// package x
|
||||
if strings.HasPrefix(line, "package ") {
|
||||
continue
|
||||
}
|
||||
|
||||
// Convert
|
||||
// const (
|
||||
// A = 1
|
||||
// B = 2
|
||||
// )
|
||||
//
|
||||
// to
|
||||
//
|
||||
// enum {
|
||||
// A = 1,
|
||||
// B = 2,
|
||||
// };
|
||||
if line == "const (" {
|
||||
printf("enum {\n")
|
||||
for i++; i < len(lines) && lines[i] != ")"; i++ {
|
||||
line = lines[i]
|
||||
if line != "" {
|
||||
printf("\t%s,", line)
|
||||
}
|
||||
printf("\n")
|
||||
}
|
||||
printf("};\n")
|
||||
continue
|
||||
}
|
||||
|
||||
// Convert
|
||||
// const A = 1
|
||||
// to
|
||||
// enum { A = 1 };
|
||||
if strings.HasPrefix(line, "const ") {
|
||||
printf("enum { %s };\n", line[len("const "):])
|
||||
continue
|
||||
}
|
||||
|
||||
// On first type definition, typedef all the structs
|
||||
// in case there are dependencies between them.
|
||||
if !didTypedef && strings.HasPrefix(line, "type ") {
|
||||
didTypedef = true
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if strings.HasPrefix(line, "type ") && strings.HasSuffix(line, " struct {") {
|
||||
s := strings.TrimSuffix(strings.TrimPrefix(line, "type "), " struct {")
|
||||
printf("typedef struct %s %s;\n", s, s)
|
||||
}
|
||||
}
|
||||
printf("\n")
|
||||
printf("#pragma pack on\n")
|
||||
printf("\n")
|
||||
}
|
||||
|
||||
// Convert
|
||||
// type T struct {
|
||||
// X int64
|
||||
// Y *int32
|
||||
// Z [4]byte
|
||||
// }
|
||||
//
|
||||
// to
|
||||
//
|
||||
// struct T {
|
||||
// int64 X;
|
||||
// int32 *Y;
|
||||
// byte Z[4];
|
||||
// }
|
||||
if strings.HasPrefix(line, "type ") && strings.HasSuffix(line, " struct {") {
|
||||
if len(lines) > i+1 && lines[i+1] == "}" {
|
||||
// do not output empty struct
|
||||
i++
|
||||
continue
|
||||
}
|
||||
s := line[len("type ") : len(line)-len(" struct {")]
|
||||
printf("struct %s {\n", s)
|
||||
for i++; i < len(lines) && lines[i] != "}"; i++ {
|
||||
line := lines[i]
|
||||
if line != "" {
|
||||
f := strings.Fields(line)
|
||||
if len(f) != 2 {
|
||||
fmt.Fprintf(os.Stderr, "cgo: cannot parse struct field: %s\n", line)
|
||||
nerrors++
|
||||
continue
|
||||
}
|
||||
printf("\t%s;", cdecl(f[0], f[1]))
|
||||
}
|
||||
printf("\n")
|
||||
}
|
||||
printf("};\n")
|
||||
continue
|
||||
}
|
||||
|
||||
// Convert
|
||||
// type T int
|
||||
// to
|
||||
// typedef int T;
|
||||
if strings.HasPrefix(line, "type ") {
|
||||
f := strings.Fields(line[len("type "):])
|
||||
if len(f) != 2 {
|
||||
fmt.Fprintf(os.Stderr, "cgo: cannot parse type definition: %s\n", line)
|
||||
nerrors++
|
||||
continue
|
||||
}
|
||||
printf("typedef\t%s;\n", cdecl(f[0], f[1]))
|
||||
continue
|
||||
}
|
||||
|
||||
printf("%s\n", line)
|
||||
}
|
||||
|
||||
if didTypedef {
|
||||
printf("\n")
|
||||
printf("#pragma pack off\n")
|
||||
}
|
||||
|
||||
return out.String()
|
||||
}
|
||||
|
||||
// cdecl returns the C declaration for the given Go name and type.
|
||||
// It only handles the specific cases necessary for converting godefs output.
|
||||
func cdecl(name, typ string) string {
|
||||
// X *[0]byte -> X *void
|
||||
if strings.HasPrefix(typ, "*[0]") {
|
||||
typ = "*void"
|
||||
}
|
||||
// X [4]byte -> X[4] byte
|
||||
for strings.HasPrefix(typ, "[") {
|
||||
i := strings.Index(typ, "]") + 1
|
||||
name = name + typ[:i]
|
||||
typ = typ[i:]
|
||||
}
|
||||
// X *byte -> *X byte
|
||||
for strings.HasPrefix(typ, "*") {
|
||||
name = "*" + name
|
||||
typ = typ[1:]
|
||||
}
|
||||
// X T -> T X
|
||||
// Handle the special case: 'unsafe.Pointer' is 'void *'
|
||||
if typ == "unsafe.Pointer" {
|
||||
typ = "void"
|
||||
name = "*" + name
|
||||
}
|
||||
return typ + "\t" + name
|
||||
}
|
||||
|
||||
var gofmtBuf bytes.Buffer
|
||||
|
||||
// gofmt returns the gofmt-formatted string for an AST node.
|
||||
|
|
|
|||
|
|
@ -155,10 +155,9 @@ var dynpackage = flag.String("dynpackage", "main", "set Go package for -dynimpor
|
|||
var dynlinker = flag.Bool("dynlinker", false, "record dynamic linker information in -dynimport mode")
|
||||
|
||||
// These flags are for bootstrapping a new Go implementation,
|
||||
// to generate Go and C headers that match the data layout and
|
||||
// to generate Go types that match the data layout and
|
||||
// constant values used in the host's C libraries and system calls.
|
||||
var godefs = flag.Bool("godefs", false, "for bootstrap: write Go definitions for C file to standard output")
|
||||
var cdefs = flag.Bool("cdefs", false, "for bootstrap: write C definitions for C file to standard output")
|
||||
var objDir = flag.String("objdir", "", "object directory")
|
||||
|
||||
var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo")
|
||||
|
|
@ -185,12 +184,7 @@ func main() {
|
|||
return
|
||||
}
|
||||
|
||||
if *godefs && *cdefs {
|
||||
fmt.Fprintf(os.Stderr, "cgo: cannot use -cdefs and -godefs together\n")
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
if *godefs || *cdefs {
|
||||
if *godefs {
|
||||
// Generating definitions pulled from header files,
|
||||
// to be checked into Go repositories.
|
||||
// Line numbers are just noise.
|
||||
|
|
@ -282,14 +276,12 @@ func main() {
|
|||
p.Record(f)
|
||||
if *godefs {
|
||||
os.Stdout.WriteString(p.godefs(f, input))
|
||||
} else if *cdefs {
|
||||
os.Stdout.WriteString(p.cdefs(f, input))
|
||||
} else {
|
||||
p.writeOutput(f, input)
|
||||
}
|
||||
}
|
||||
|
||||
if !*godefs && !*cdefs {
|
||||
if !*godefs {
|
||||
p.writeDefs()
|
||||
}
|
||||
if nerrors > 0 {
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ func (p *Package) writeDefs() {
|
|||
}
|
||||
fmt.Fprintf(fm, "void _cgo_allocate(void *a, int c) { }\n")
|
||||
fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\n")
|
||||
fmt.Fprintf(fm, "void _cgo_reginit(void) { }\n")
|
||||
|
||||
// Write second Go output: definitions of _C_xxx.
|
||||
// In a separate file so that the import of "unsafe" does not
|
||||
|
|
|
|||
|
|
@ -48,10 +48,13 @@ widstruct(Type *errtype, Type *t, vlong o, int flag)
|
|||
Type *f;
|
||||
int64 w;
|
||||
int32 maxalign;
|
||||
vlong starto, lastzero;
|
||||
|
||||
starto = o;
|
||||
maxalign = flag;
|
||||
if(maxalign < 1)
|
||||
maxalign = 1;
|
||||
lastzero = 0;
|
||||
for(f=t->type; f!=T; f=f->down) {
|
||||
if(f->etype != TFIELD)
|
||||
fatal("widstruct: not TFIELD: %lT", f);
|
||||
|
|
@ -80,22 +83,28 @@ widstruct(Type *errtype, Type *t, vlong o, int flag)
|
|||
} else
|
||||
f->nname->xoffset = o;
|
||||
}
|
||||
if(w == 0)
|
||||
lastzero = o;
|
||||
o += w;
|
||||
if(o >= MAXWIDTH) {
|
||||
yyerror("type %lT too large", errtype);
|
||||
o = 8; // small but nonzero
|
||||
}
|
||||
}
|
||||
// For nonzero-sized structs which end in a zero-sized thing, we add
|
||||
// an extra byte of padding to the type. This padding ensures that
|
||||
// taking the address of the zero-sized thing can't manufacture a
|
||||
// pointer to the next object in the heap. See issue 9401.
|
||||
if(flag == 1 && o > starto && o == lastzero)
|
||||
o++;
|
||||
|
||||
// final width is rounded
|
||||
if(flag)
|
||||
o = rnd(o, maxalign);
|
||||
t->align = maxalign;
|
||||
|
||||
// type width only includes back to first field's offset
|
||||
if(t->type == T)
|
||||
t->width = 0;
|
||||
else
|
||||
t->width = o - t->type->width;
|
||||
t->width = o - starto;
|
||||
return o;
|
||||
}
|
||||
|
||||
|
|
@ -128,6 +137,11 @@ dowidth(Type *t)
|
|||
return;
|
||||
}
|
||||
|
||||
// break infinite recursion if the broken recursive type
|
||||
// is referenced again
|
||||
if(t->broke && t->width == 0)
|
||||
return;
|
||||
|
||||
// defer checkwidth calls until after we're done
|
||||
defercalc++;
|
||||
|
||||
|
|
|
|||
|
|
@ -126,12 +126,13 @@ char *runtimeimport =
|
|||
"func @\"\".makeslice (@\"\".typ·2 *byte, @\"\".nel·3 int64, @\"\".cap·4 int64) (@\"\".ary·1 []any)\n"
|
||||
"func @\"\".growslice (@\"\".typ·2 *byte, @\"\".old·3 []any, @\"\".n·4 int64) (@\"\".ary·1 []any)\n"
|
||||
"func @\"\".memmove (@\"\".to·1 *any, @\"\".frm·2 *any, @\"\".length·3 uintptr)\n"
|
||||
"func @\"\".memclr (@\"\".ptr·1 *byte, @\"\".length·2 uintptr)\n"
|
||||
"func @\"\".memequal (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
|
||||
"func @\"\".memequal8 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
|
||||
"func @\"\".memequal16 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
|
||||
"func @\"\".memequal32 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
|
||||
"func @\"\".memequal64 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
|
||||
"func @\"\".memequal128 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
|
||||
"func @\"\".memequal8 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n"
|
||||
"func @\"\".memequal16 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n"
|
||||
"func @\"\".memequal32 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n"
|
||||
"func @\"\".memequal64 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n"
|
||||
"func @\"\".memequal128 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n"
|
||||
"func @\"\".int64div (? int64, ? int64) (? int64)\n"
|
||||
"func @\"\".uint64div (? uint64, ? uint64) (? uint64)\n"
|
||||
"func @\"\".int64mod (? int64, ? int64) (? int64)\n"
|
||||
|
|
|
|||
|
|
@ -551,6 +551,7 @@ dumpasmhdr(void)
|
|||
t = n->type;
|
||||
if(t->etype != TSTRUCT || t->map != T || t->funarg)
|
||||
break;
|
||||
Bprint(b, "#define %s__size %d\n", t->sym->name, (int)t->width);
|
||||
for(t=t->type; t != T; t=t->down)
|
||||
if(!isblanksym(t->sym))
|
||||
Bprint(b, "#define %s_%s %d\n", n->sym->name, t->sym->name, (int)t->width);
|
||||
|
|
|
|||
|
|
@ -384,6 +384,7 @@ enum
|
|||
SymUniq = 1<<3,
|
||||
SymSiggen = 1<<4,
|
||||
SymAsm = 1<<5,
|
||||
SymAlgGen = 1<<6,
|
||||
};
|
||||
|
||||
struct Sym
|
||||
|
|
@ -1450,6 +1451,7 @@ void walkswitch(Node *sw);
|
|||
* typecheck.c
|
||||
*/
|
||||
int islvalue(Node *n);
|
||||
int samesafeexpr(Node *l, Node *r);
|
||||
Node* typecheck(Node **np, int top);
|
||||
void typechecklist(NodeList *l, int top);
|
||||
Node* typecheckdef(Node *n);
|
||||
|
|
|
|||
|
|
@ -210,11 +210,12 @@ racewalknode(Node **np, NodeList **init, int wr, int skip)
|
|||
case OCALLFUNC:
|
||||
// Instrument dst argument of runtime.writebarrier* calls
|
||||
// as we do not instrument runtime code.
|
||||
if(n->left->sym != S && n->left->sym->pkg == runtimepkg && strncmp(n->left->sym->name, "writebarrier", 12) == 0) {
|
||||
if(n->left->sym != S && n->left->sym->pkg == runtimepkg &&
|
||||
(strncmp(n->left->sym->name, "writebarrier", 12) == 0 || strcmp(n->left->sym->name, "typedmemmove") == 0)) {
|
||||
// Find the dst argument.
|
||||
// The list can be reordered, so it's not necessary just the first or the second element.
|
||||
for(l = n->list; l; l = l->next) {
|
||||
if(strcmp(n->left->sym->name, "writebarrierfat") == 0) {
|
||||
if(strcmp(n->left->sym->name, "typedmemmove") == 0) {
|
||||
if(l->n->left->xoffset == widthptr)
|
||||
break;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -144,6 +144,73 @@ walkrange(Node *n)
|
|||
fatal("walkrange");
|
||||
|
||||
case TARRAY:
|
||||
// Lower n into runtime·memclr if possible, for
|
||||
// fast zeroing of slices and arrays (issue 5373).
|
||||
// Look for instances of
|
||||
//
|
||||
// for i := range a {
|
||||
// a[i] = zero
|
||||
// }
|
||||
//
|
||||
// in which the evaluation of a is side-effect-free.
|
||||
if(!debug['N'])
|
||||
if(!flag_race)
|
||||
if(v1 != N)
|
||||
if(v2 == N)
|
||||
if(n->nbody != nil)
|
||||
if(n->nbody->n != N) // at least one statement in body
|
||||
if(n->nbody->next == nil) { // at most one statement in body
|
||||
tmp = n->nbody->n; // first statement of body
|
||||
if(tmp->op == OAS)
|
||||
if(tmp->left->op == OINDEX)
|
||||
if(samesafeexpr(tmp->left->left, a))
|
||||
if(samesafeexpr(tmp->left->right, v1))
|
||||
if(t->type->width > 0)
|
||||
if(iszero(tmp->right)) {
|
||||
// Convert to
|
||||
// if len(a) != 0 {
|
||||
// hp = &a[0]
|
||||
// hn = len(a)*sizeof(elem(a))
|
||||
// memclr(hp, hn)
|
||||
// i = len(a) - 1
|
||||
// }
|
||||
n->op = OIF;
|
||||
n->nbody = nil;
|
||||
n->ntest = nod(ONE, nod(OLEN, a, N), nodintconst(0));
|
||||
n->nincr = nil;
|
||||
|
||||
// hp = &a[0]
|
||||
hp = temp(ptrto(types[TUINT8]));
|
||||
tmp = nod(OINDEX, a, nodintconst(0));
|
||||
tmp->bounded = 1;
|
||||
tmp = nod(OADDR, tmp, N);
|
||||
tmp = nod(OCONVNOP, tmp, N);
|
||||
tmp->type = ptrto(types[TUINT8]);
|
||||
n->nbody = list(n->nbody, nod(OAS, hp, tmp));
|
||||
|
||||
// hn = len(a) * sizeof(elem(a))
|
||||
hn = temp(types[TUINTPTR]);
|
||||
tmp = nod(OLEN, a, N);
|
||||
tmp = nod(OMUL, tmp, nodintconst(t->type->width));
|
||||
tmp = conv(tmp, types[TUINTPTR]);
|
||||
n->nbody = list(n->nbody, nod(OAS, hn, tmp));
|
||||
|
||||
// memclr(hp, hn)
|
||||
fn = mkcall("memclr", T, nil, hp, hn);
|
||||
n->nbody = list(n->nbody, fn);
|
||||
|
||||
// i = len(a) - 1
|
||||
v1 = nod(OAS, v1, nod(OSUB, nod(OLEN, a, N), nodintconst(1)));
|
||||
n->nbody = list(n->nbody, v1);
|
||||
|
||||
typecheck(&n->ntest, Erv);
|
||||
typechecklist(n->nbody, Etop);
|
||||
walkstmt(&n);
|
||||
lineno = lno;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// orderstmt arranged for a copy of the array/slice variable if needed.
|
||||
ha = a;
|
||||
hv1 = temp(types[TINT]);
|
||||
|
|
|
|||
|
|
@ -731,7 +731,7 @@ dcommontype(Sym *s, int ot, Type *t)
|
|||
dowidth(t);
|
||||
alg = algtype(t);
|
||||
algsym = S;
|
||||
if(alg < 0)
|
||||
if(alg < 0 || alg == AMEM)
|
||||
algsym = dalgsym(t);
|
||||
|
||||
if(t->sym != nil && !isptr[t->etype])
|
||||
|
|
@ -791,7 +791,7 @@ dcommontype(Sym *s, int ot, Type *t)
|
|||
if(gcprog)
|
||||
i |= KindGCProg;
|
||||
ot = duint8(s, ot, i); // kind
|
||||
if(alg >= 0)
|
||||
if(algsym == S)
|
||||
ot = dsymptr(s, ot, algarray, alg*sizeofAlg);
|
||||
else
|
||||
ot = dsymptr(s, ot, algsym, 0);
|
||||
|
|
@ -1311,29 +1311,58 @@ dalgsym(Type *t)
|
|||
{
|
||||
int ot;
|
||||
Sym *s, *hash, *hashfunc, *eq, *eqfunc;
|
||||
char *p;
|
||||
|
||||
// dalgsym is only called for a type that needs an algorithm table,
|
||||
// which implies that the type is comparable (or else it would use ANOEQ).
|
||||
|
||||
if(algtype(t) == AMEM) {
|
||||
// we use one algorithm table for all AMEM types of a given size
|
||||
p = smprint(".alg%lld", t->width);
|
||||
s = pkglookup(p, typepkg);
|
||||
free(p);
|
||||
if(s->flags & SymAlgGen)
|
||||
return s;
|
||||
s->flags |= SymAlgGen;
|
||||
|
||||
// make hash closure
|
||||
p = smprint(".hashfunc%lld", t->width);
|
||||
hashfunc = pkglookup(p, typepkg);
|
||||
free(p);
|
||||
ot = 0;
|
||||
ot = dsymptr(hashfunc, ot, pkglookup("memhash_varlen", runtimepkg), 0);
|
||||
ot = duintxx(hashfunc, ot, t->width, widthptr); // size encoded in closure
|
||||
ggloblsym(hashfunc, ot, DUPOK|RODATA);
|
||||
|
||||
// make equality closure
|
||||
p = smprint(".eqfunc%lld", t->width);
|
||||
eqfunc = pkglookup(p, typepkg);
|
||||
free(p);
|
||||
ot = 0;
|
||||
ot = dsymptr(eqfunc, ot, pkglookup("memequal_varlen", runtimepkg), 0);
|
||||
ot = duintxx(eqfunc, ot, t->width, widthptr);
|
||||
ggloblsym(eqfunc, ot, DUPOK|RODATA);
|
||||
} else {
|
||||
// generate an alg table specific to this type
|
||||
s = typesymprefix(".alg", t);
|
||||
hash = typesymprefix(".hash", t);
|
||||
genhash(hash, t);
|
||||
eq = typesymprefix(".eq", t);
|
||||
hashfunc = typesymprefix(".hashfunc", t);
|
||||
eqfunc = typesymprefix(".eqfunc", t);
|
||||
|
||||
genhash(hash, t);
|
||||
geneq(eq, t);
|
||||
|
||||
// make Go funcs (closures) for calling hash and equal from Go
|
||||
hashfunc = typesymprefix(".hashfunc", t);
|
||||
dsymptr(hashfunc, 0, hash, 0);
|
||||
ggloblsym(hashfunc, widthptr, DUPOK|RODATA);
|
||||
eqfunc = typesymprefix(".eqfunc", t);
|
||||
dsymptr(eqfunc, 0, eq, 0);
|
||||
ggloblsym(eqfunc, widthptr, DUPOK|RODATA);
|
||||
|
||||
}
|
||||
// ../../runtime/alg.go:/typeAlg
|
||||
ot = 0;
|
||||
ot = dsymptr(s, ot, hashfunc, 0);
|
||||
ot = dsymptr(s, ot, eqfunc, 0);
|
||||
|
||||
ggloblsym(s, ot, DUPOK|RODATA);
|
||||
return s;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -160,13 +160,14 @@ func block()
|
|||
func makeslice(typ *byte, nel int64, cap int64) (ary []any)
|
||||
func growslice(typ *byte, old []any, n int64) (ary []any)
|
||||
func memmove(to *any, frm *any, length uintptr)
|
||||
func memclr(ptr *byte, length uintptr)
|
||||
|
||||
func memequal(x, y *any, size uintptr) bool
|
||||
func memequal8(x, y *any, size uintptr) bool
|
||||
func memequal16(x, y *any, size uintptr) bool
|
||||
func memequal32(x, y *any, size uintptr) bool
|
||||
func memequal64(x, y *any, size uintptr) bool
|
||||
func memequal128(x, y *any, size uintptr) bool
|
||||
func memequal8(x, y *any) bool
|
||||
func memequal16(x, y *any) bool
|
||||
func memequal32(x, y *any) bool
|
||||
func memequal64(x, y *any) bool
|
||||
func memequal128(x, y *any) bool
|
||||
|
||||
// only used on 32-bit
|
||||
func int64div(int64, int64) int64
|
||||
|
|
|
|||
|
|
@ -2652,7 +2652,7 @@ hashfor(Type *t)
|
|||
a = algtype1(t, nil);
|
||||
switch(a) {
|
||||
case AMEM:
|
||||
return hashmem(t);
|
||||
fatal("hashfor with AMEM type");
|
||||
case AINTER:
|
||||
sym = pkglookup("interhash", runtimepkg);
|
||||
break;
|
||||
|
|
@ -2684,7 +2684,6 @@ hashfor(Type *t)
|
|||
tfn = nod(OTFUNC, N, N);
|
||||
tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
|
||||
tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
|
||||
tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
|
||||
tfn->rlist = list(tfn->rlist, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
|
||||
typecheck(&tfn, Etype);
|
||||
n->type = tfn->type;
|
||||
|
|
@ -2710,7 +2709,7 @@ genhash(Sym *sym, Type *t)
|
|||
dclcontext = PEXTERN;
|
||||
markdcl();
|
||||
|
||||
// func sym(p *T, s uintptr, h uintptr) uintptr
|
||||
// func sym(p *T, h uintptr) uintptr
|
||||
fn = nod(ODCLFUNC, N, N);
|
||||
fn->nname = newname(sym);
|
||||
fn->nname->class = PFUNC;
|
||||
|
|
@ -2720,8 +2719,6 @@ genhash(Sym *sym, Type *t)
|
|||
n = nod(ODCLFIELD, newname(lookup("p")), typenod(ptrto(t)));
|
||||
tfn->list = list(tfn->list, n);
|
||||
np = n->left;
|
||||
n = nod(ODCLFIELD, newname(lookup("s")), typenod(types[TUINTPTR]));
|
||||
tfn->list = list(tfn->list, n);
|
||||
n = nod(ODCLFIELD, newname(lookup("h")), typenod(types[TUINTPTR]));
|
||||
tfn->list = list(tfn->list, n);
|
||||
nh = n->left;
|
||||
|
|
@ -2773,14 +2770,13 @@ genhash(Sym *sym, Type *t)
|
|||
nh,
|
||||
nod(OMUL, nh, nodintconst(mul))));
|
||||
|
||||
// h = hashel(&p[i], sizeof(p[i]), h)
|
||||
// h = hashel(&p[i], h)
|
||||
call = nod(OCALL, hashel, N);
|
||||
nx = nod(OINDEX, np, ni);
|
||||
nx->bounded = 1;
|
||||
na = nod(OADDR, nx, N);
|
||||
na->etype = 1; // no escape to heap
|
||||
call->list = list(call->list, na);
|
||||
call->list = list(call->list, nodintconst(t->type->width));
|
||||
call->list = list(call->list, nh);
|
||||
n->nbody = list(n->nbody, nod(OAS, nh, call));
|
||||
|
||||
|
|
@ -2813,8 +2809,8 @@ genhash(Sym *sym, Type *t)
|
|||
na = nod(OADDR, nx, N);
|
||||
na->etype = 1; // no escape to heap
|
||||
call->list = list(call->list, na);
|
||||
call->list = list(call->list, nodintconst(size));
|
||||
call->list = list(call->list, nh);
|
||||
call->list = list(call->list, nodintconst(size));
|
||||
fn->nbody = list(fn->nbody, nod(OAS, nh, call));
|
||||
|
||||
first = T;
|
||||
|
|
@ -2825,17 +2821,29 @@ genhash(Sym *sym, Type *t)
|
|||
continue;
|
||||
|
||||
// Run hash for this field.
|
||||
hashel = hashfor(t1->type);
|
||||
// h = hashel(&p.t1, size, h)
|
||||
if(algtype1(t1->type, nil) == AMEM) {
|
||||
hashel = hashmem(t1->type);
|
||||
// h = memhash(&p.t1, h, size)
|
||||
call = nod(OCALL, hashel, N);
|
||||
nx = nod(OXDOT, np, newname(t1->sym)); // TODO: fields from other packages?
|
||||
na = nod(OADDR, nx, N);
|
||||
na->etype = 1; // no escape to heap
|
||||
call->list = list(call->list, na);
|
||||
call->list = list(call->list, nh);
|
||||
call->list = list(call->list, nodintconst(t1->type->width));
|
||||
fn->nbody = list(fn->nbody, nod(OAS, nh, call));
|
||||
} else {
|
||||
hashel = hashfor(t1->type);
|
||||
// h = hashel(&p.t1, h)
|
||||
call = nod(OCALL, hashel, N);
|
||||
nx = nod(OXDOT, np, newname(t1->sym)); // TODO: fields from other packages?
|
||||
na = nod(OADDR, nx, N);
|
||||
na->etype = 1; // no escape to heap
|
||||
call->list = list(call->list, na);
|
||||
call->list = list(call->list, nh);
|
||||
fn->nbody = list(fn->nbody, nod(OAS, nh, call));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
r = nod(ORETURN, N, N);
|
||||
|
|
@ -2881,7 +2889,7 @@ eqfield(Node *p, Node *q, Node *field)
|
|||
}
|
||||
|
||||
static Node*
|
||||
eqmemfunc(vlong size, Type *type)
|
||||
eqmemfunc(vlong size, Type *type, int *needsize)
|
||||
{
|
||||
char buf[30];
|
||||
Node *fn;
|
||||
|
|
@ -2889,6 +2897,7 @@ eqmemfunc(vlong size, Type *type)
|
|||
switch(size) {
|
||||
default:
|
||||
fn = syslook("memequal", 1);
|
||||
*needsize = 1;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
|
|
@ -2897,6 +2906,7 @@ eqmemfunc(vlong size, Type *type)
|
|||
case 16:
|
||||
snprint(buf, sizeof buf, "memequal%d", (int)size*8);
|
||||
fn = syslook(buf, 1);
|
||||
*needsize = 0;
|
||||
break;
|
||||
}
|
||||
argtype(fn, type);
|
||||
|
|
@ -2905,11 +2915,12 @@ eqmemfunc(vlong size, Type *type)
|
|||
}
|
||||
|
||||
// Return node for
|
||||
// if !memequal(&p.field, &q.field, size) { return false }
|
||||
// if !memequal(&p.field, &q.field [, size]) { return false }
|
||||
static Node*
|
||||
eqmem(Node *p, Node *q, Node *field, vlong size)
|
||||
{
|
||||
Node *nif, *nx, *ny, *call, *r;
|
||||
int needsize;
|
||||
|
||||
nx = nod(OADDR, nod(OXDOT, p, field), N);
|
||||
nx->etype = 1; // does not escape
|
||||
|
|
@ -2918,9 +2929,10 @@ eqmem(Node *p, Node *q, Node *field, vlong size)
|
|||
typecheck(&nx, Erv);
|
||||
typecheck(&ny, Erv);
|
||||
|
||||
call = nod(OCALL, eqmemfunc(size, nx->type->type), N);
|
||||
call = nod(OCALL, eqmemfunc(size, nx->type->type, &needsize), N);
|
||||
call->list = list(call->list, nx);
|
||||
call->list = list(call->list, ny);
|
||||
if(needsize)
|
||||
call->list = list(call->list, nodintconst(size));
|
||||
|
||||
nif = nod(OIF, N, N);
|
||||
|
|
@ -2951,7 +2963,7 @@ geneq(Sym *sym, Type *t)
|
|||
dclcontext = PEXTERN;
|
||||
markdcl();
|
||||
|
||||
// func sym(p, q *T, s uintptr) bool
|
||||
// func sym(p, q *T) bool
|
||||
fn = nod(ODCLFUNC, N, N);
|
||||
fn->nname = newname(sym);
|
||||
fn->nname->class = PFUNC;
|
||||
|
|
@ -2964,8 +2976,6 @@ geneq(Sym *sym, Type *t)
|
|||
n = nod(ODCLFIELD, newname(lookup("q")), typenod(ptrto(t)));
|
||||
tfn->list = list(tfn->list, n);
|
||||
nq = n->left;
|
||||
n = nod(ODCLFIELD, newname(lookup("s")), typenod(types[TUINTPTR]));
|
||||
tfn->list = list(tfn->list, n);
|
||||
n = nod(ODCLFIELD, N, typenod(types[TBOOL]));
|
||||
tfn->rlist = list(tfn->rlist, n);
|
||||
|
||||
|
|
|
|||
|
|
@ -2831,7 +2831,7 @@ checkassignlist(NodeList *l)
|
|||
|
||||
// Check whether l and r are the same side effect-free expression,
|
||||
// so that it is safe to reuse one instead of computing both.
|
||||
static int
|
||||
int
|
||||
samesafeexpr(Node *l, Node *r)
|
||||
{
|
||||
if(l->op != r->op || !eqtype(l->type, r->type))
|
||||
|
|
|
|||
|
|
@ -794,8 +794,6 @@ walkexpr(Node **np, NodeList **init)
|
|||
// var,b = mapaccess2*(t, m, i)
|
||||
// a = *var
|
||||
a = n->list->n;
|
||||
var = temp(ptrto(t->type));
|
||||
var->typecheck = 1;
|
||||
fn = mapfn(p, t);
|
||||
r = mkcall1(fn, getoutargx(fn->type), init, typename(t), r->left, key);
|
||||
|
||||
|
|
@ -806,10 +804,17 @@ walkexpr(Node **np, NodeList **init)
|
|||
r->type->type->down->type = n->list->next->n->type;
|
||||
n->rlist = list1(r);
|
||||
n->op = OAS2FUNC;
|
||||
|
||||
// don't generate a = *var if a is _
|
||||
if(!isblank(a)) {
|
||||
var = temp(ptrto(t->type));
|
||||
var->typecheck = 1;
|
||||
n->list->n = var;
|
||||
walkexpr(&n, init);
|
||||
*init = list(*init, n);
|
||||
n = nod(OAS, a, nod(OIND, var, N));
|
||||
}
|
||||
|
||||
typecheck(&n, Etop);
|
||||
walkexpr(&n, init);
|
||||
// mapaccess needs a zero value to be at least this big.
|
||||
|
|
@ -3194,7 +3199,7 @@ sliceany(Node* n, NodeList **init)
|
|||
}
|
||||
|
||||
static Node*
|
||||
eqfor(Type *t)
|
||||
eqfor(Type *t, int *needsize)
|
||||
{
|
||||
int a;
|
||||
Node *n;
|
||||
|
|
@ -3213,6 +3218,7 @@ eqfor(Type *t)
|
|||
n = syslook("memequal", 1);
|
||||
argtype(n, t);
|
||||
argtype(n, t);
|
||||
*needsize = 1;
|
||||
return n;
|
||||
}
|
||||
|
||||
|
|
@ -3222,10 +3228,10 @@ eqfor(Type *t)
|
|||
ntype = nod(OTFUNC, N, N);
|
||||
ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
|
||||
ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
|
||||
ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
|
||||
ntype->rlist = list(ntype->rlist, nod(ODCLFIELD, N, typenod(types[TBOOL])));
|
||||
typecheck(&ntype, Etype);
|
||||
n->type = ntype->type;
|
||||
*needsize = 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
|
|
@ -3245,7 +3251,7 @@ static void
|
|||
walkcompare(Node **np, NodeList **init)
|
||||
{
|
||||
Node *n, *l, *r, *call, *a, *li, *ri, *expr, *cmpl, *cmpr;
|
||||
int andor, i;
|
||||
int andor, i, needsize;
|
||||
Type *t, *t1;
|
||||
|
||||
n = *np;
|
||||
|
|
@ -3333,9 +3339,10 @@ walkcompare(Node **np, NodeList **init)
|
|||
}
|
||||
|
||||
// Chose not to inline. Call equality function directly.
|
||||
call = nod(OCALL, eqfor(t), N);
|
||||
call = nod(OCALL, eqfor(t, &needsize), N);
|
||||
call->list = list(call->list, l);
|
||||
call->list = list(call->list, r);
|
||||
if(needsize)
|
||||
call->list = list(call->list, nodintconst(t->width));
|
||||
r = call;
|
||||
if(n->op != OEQ)
|
||||
|
|
|
|||
|
|
@ -875,7 +875,26 @@ listed in the GOPATH environment variable (see 'go help gopath').
|
|||
|
||||
The go command attempts to download the version of the
|
||||
package appropriate for the Go release being used.
|
||||
Run 'go help install' for more.
|
||||
Run 'go help get' for more.
|
||||
|
||||
Import path checking
|
||||
|
||||
When the custom import path feature described above redirects to a
|
||||
known code hosting site, each of the resulting packages has two possible
|
||||
import paths, using the custom domain or the known hosting site.
|
||||
|
||||
A package statement is said to have an "import comment" if it is immediately
|
||||
followed (before the next newline) by a comment of one of these two forms:
|
||||
|
||||
package math // import "path"
|
||||
package math /* import "path" * /
|
||||
|
||||
The go command will refuse to install a package with an import comment
|
||||
unless it is being referred to by that import path. In this way, import comments
|
||||
let package authors make sure the custom import path is used and not a
|
||||
direct path to the underlying code hosting site.
|
||||
|
||||
See https://golang.org/s/go14customimport for details.
|
||||
|
||||
|
||||
Description of package lists
|
||||
|
|
|
|||
|
|
@ -290,7 +290,7 @@ func downloadPackage(p *Package) error {
|
|||
}
|
||||
}
|
||||
if remote != repo {
|
||||
return fmt.Errorf("%s is from %s, should be from %s", dir, remote, repo)
|
||||
return fmt.Errorf("%s is a custom import path for %s, but %s is checked out from %s", rr.root, repo, dir, remote)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -235,7 +235,26 @@ listed in the GOPATH environment variable (see 'go help gopath').
|
|||
|
||||
The go command attempts to download the version of the
|
||||
package appropriate for the Go release being used.
|
||||
Run 'go help install' for more.
|
||||
Run 'go help get' for more.
|
||||
|
||||
Import path checking
|
||||
|
||||
When the custom import path feature described above redirects to a
|
||||
known code hosting site, each of the resulting packages has two possible
|
||||
import paths, using the custom domain or the known hosting site.
|
||||
|
||||
A package statement is said to have an "import comment" if it is immediately
|
||||
followed (before the next newline) by a comment of one of these two forms:
|
||||
|
||||
package math // import "path"
|
||||
package math /* import "path" */
|
||||
|
||||
The go command will refuse to install a package with an import comment
|
||||
unless it is being referred to by that import path. In this way, import comments
|
||||
let package authors make sure the custom import path is used and not a
|
||||
direct path to the underlying code hosting site.
|
||||
|
||||
See https://golang.org/s/go14customimport for details.
|
||||
`,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,6 @@
|
|||
# license that can be found in the LICENSE file.
|
||||
|
||||
go install # So the next line will produce updated documentation.
|
||||
go help documentation > doc.go
|
||||
go help documentation | sed 's; \*/; * /;' >doc.go
|
||||
gofmt -w doc.go
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,11 @@ datcmp(LSym *s1, LSym *s2)
|
|||
{
|
||||
if(s1->type != s2->type)
|
||||
return (int)s1->type - (int)s2->type;
|
||||
if(s1->size != s2->size) {
|
||||
// For ppc64, we want to interleave the .got and .toc sections
|
||||
// from input files. Both are type SELFGOT, so in that case
|
||||
// fall through to the name comparison (conveniently, .got
|
||||
// sorts before .toc).
|
||||
if(s1->type != SELFGOT && s1->size != s2->size) {
|
||||
if(s1->size < s2->size)
|
||||
return -1;
|
||||
return +1;
|
||||
|
|
@ -132,6 +136,7 @@ relocsym(LSym *s)
|
|||
{
|
||||
Reloc *r;
|
||||
LSym *rs;
|
||||
int16 i16;
|
||||
int32 i, off, siz, fl;
|
||||
vlong o;
|
||||
uchar *cast;
|
||||
|
|
@ -308,6 +313,8 @@ relocsym(LSym *s)
|
|||
o = r->sym->size + r->add;
|
||||
break;
|
||||
}
|
||||
if(r->variant != RV_NONE)
|
||||
o = archrelocvariant(r, s, o);
|
||||
//print("relocate %s %#llux (%#llux+%#llux, size %d) => %s %#llux +%#llx [%llx]\n", s->name, (uvlong)(s->value+off), (uvlong)s->value, (uvlong)r->off, r->siz, r->sym ? r->sym->name : "<nil>", (uvlong)symaddr(r->sym), (vlong)r->add, (vlong)o);
|
||||
switch(siz) {
|
||||
default:
|
||||
|
|
@ -317,6 +324,14 @@ relocsym(LSym *s)
|
|||
// TODO(rsc): Remove.
|
||||
s->p[off] = (int8)o;
|
||||
break;
|
||||
case 2:
|
||||
if(o != (int16)o)
|
||||
diag("relocation address is too big: %#llx", o);
|
||||
i16 = o;
|
||||
cast = (uchar*)&i16;
|
||||
for(i=0; i<2; i++)
|
||||
s->p[off+i] = cast[inuxi2[i]];
|
||||
break;
|
||||
case 4:
|
||||
if(r->type == R_PCREL || r->type == R_CALL) {
|
||||
if(o != (int32)o)
|
||||
|
|
@ -909,7 +924,7 @@ dodata(void)
|
|||
vlong datsize;
|
||||
Section *sect;
|
||||
Segment *segro;
|
||||
LSym *s, *last, **l;
|
||||
LSym *s, *last, **l, *toc;
|
||||
LSym *gcdata, *gcbss;
|
||||
ProgGen gen;
|
||||
|
||||
|
|
@ -983,7 +998,7 @@ dodata(void)
|
|||
|
||||
/* writable ELF sections */
|
||||
datsize = 0;
|
||||
for(; s != nil && s->type < SNOPTRDATA; s = s->next) {
|
||||
for(; s != nil && s->type < SELFGOT; s = s->next) {
|
||||
sect = addsection(&segdata, s->name, 06);
|
||||
sect->align = symalign(s);
|
||||
datsize = rnd(datsize, sect->align);
|
||||
|
|
@ -995,6 +1010,33 @@ dodata(void)
|
|||
sect->len = datsize - sect->vaddr;
|
||||
}
|
||||
|
||||
/* .got (and .toc on ppc64) */
|
||||
if(s->type == SELFGOT) {
|
||||
sect = addsection(&segdata, ".got", 06);
|
||||
sect->align = maxalign(s, SELFGOT);
|
||||
datsize = rnd(datsize, sect->align);
|
||||
sect->vaddr = datsize;
|
||||
for(; s != nil && s->type == SELFGOT; s = s->next) {
|
||||
datsize = aligndatsize(datsize, s);
|
||||
s->sect = sect;
|
||||
s->type = SDATA;
|
||||
s->value = datsize - sect->vaddr;
|
||||
|
||||
// Resolve .TOC. symbol for this object file (ppc64)
|
||||
toc = linkrlookup(ctxt, ".TOC.", s->version);
|
||||
if(toc != nil) {
|
||||
toc->sect = sect;
|
||||
toc->outer = s;
|
||||
toc->sub = s->sub;
|
||||
s->sub = toc;
|
||||
|
||||
toc->value = 0x8000;
|
||||
}
|
||||
growdatsize(&datsize, s);
|
||||
}
|
||||
sect->len = datsize - sect->vaddr;
|
||||
}
|
||||
|
||||
/* pointer-free data */
|
||||
sect = addsection(&segdata, ".noptrdata", 06);
|
||||
sect->align = maxalign(s, SINITARR-1);
|
||||
|
|
@ -1273,6 +1315,9 @@ textaddress(void)
|
|||
sub->value += va;
|
||||
if(sym->size == 0 && sym->sub != S)
|
||||
ctxt->cursym = sym;
|
||||
if(sym->size < MINFUNC)
|
||||
va += MINFUNC; // spacing required for findfunctab
|
||||
else
|
||||
va += sym->size;
|
||||
}
|
||||
sect->len = va - sect->vaddr;
|
||||
|
|
|
|||
|
|
@ -306,12 +306,18 @@ elfwritedynent(LSym *s, int tag, uint64 val)
|
|||
|
||||
void
|
||||
elfwritedynentsym(LSym *s, int tag, LSym *t)
|
||||
{
|
||||
elfwritedynentsymplus(s, tag, t, 0);
|
||||
}
|
||||
|
||||
void
|
||||
elfwritedynentsymplus(LSym *s, int tag, LSym *t, vlong add)
|
||||
{
|
||||
if(elf64)
|
||||
adduint64(ctxt, s, tag);
|
||||
else
|
||||
adduint32(ctxt, s, tag);
|
||||
addaddr(ctxt, s, t);
|
||||
addaddrplus(ctxt, s, t, add);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -977,6 +983,8 @@ doelf(void)
|
|||
addstring(shstrtab, ".interp");
|
||||
addstring(shstrtab, ".hash");
|
||||
addstring(shstrtab, ".got");
|
||||
if(thechar == '9')
|
||||
addstring(shstrtab, ".glink");
|
||||
addstring(shstrtab, ".got.plt");
|
||||
addstring(shstrtab, ".dynamic");
|
||||
addstring(shstrtab, ".dynsym");
|
||||
|
|
@ -1020,7 +1028,14 @@ doelf(void)
|
|||
/* global offset table */
|
||||
s = linklookup(ctxt, ".got", 0);
|
||||
s->reachable = 1;
|
||||
s->type = SELFSECT; // writable
|
||||
s->type = SELFGOT; // writable
|
||||
|
||||
/* ppc64 glink resolver */
|
||||
if(thechar == '9') {
|
||||
s = linklookup(ctxt, ".glink", 0);
|
||||
s->reachable = 1;
|
||||
s->type = SELFRXSECT;
|
||||
}
|
||||
|
||||
/* hash */
|
||||
s = linklookup(ctxt, ".hash", 0);
|
||||
|
|
@ -1033,6 +1048,11 @@ doelf(void)
|
|||
|
||||
s = linklookup(ctxt, ".plt", 0);
|
||||
s->reachable = 1;
|
||||
if(thechar == '9')
|
||||
// In the ppc64 ABI, .plt is a data section
|
||||
// written by the dynamic linker.
|
||||
s->type = SELFSECT;
|
||||
else
|
||||
s->type = SELFRXSECT;
|
||||
|
||||
elfsetupplt();
|
||||
|
|
@ -1080,8 +1100,14 @@ doelf(void)
|
|||
if(rpath)
|
||||
elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath));
|
||||
|
||||
if(thechar == '9')
|
||||
elfwritedynentsym(s, DT_PLTGOT, linklookup(ctxt, ".plt", 0));
|
||||
else
|
||||
elfwritedynentsym(s, DT_PLTGOT, linklookup(ctxt, ".got.plt", 0));
|
||||
|
||||
if(thechar == '9')
|
||||
elfwritedynent(s, DT_PPC64_OPT, 0);
|
||||
|
||||
// Solaris dynamic linker can't handle an empty .rela.plt if
|
||||
// DT_JMPREL is emitted so we have to defer generation of DT_PLTREL,
|
||||
// DT_PLTRELSZ, and DT_JMPREL dynamic entries until after we know the
|
||||
|
|
@ -1309,6 +1335,7 @@ asmbelf(vlong symo)
|
|||
|
||||
switch(eh->machine) {
|
||||
case EM_X86_64:
|
||||
case EM_PPC64:
|
||||
sh = elfshname(".rela.plt");
|
||||
sh->type = SHT_RELA;
|
||||
sh->flags = SHF_ALLOC;
|
||||
|
|
@ -1345,16 +1372,33 @@ asmbelf(vlong symo)
|
|||
break;
|
||||
}
|
||||
|
||||
if(eh->machine == EM_PPC64) {
|
||||
sh = elfshname(".glink");
|
||||
sh->type = SHT_PROGBITS;
|
||||
sh->flags = SHF_ALLOC+SHF_EXECINSTR;
|
||||
sh->addralign = 4;
|
||||
shsym(sh, linklookup(ctxt, ".glink", 0));
|
||||
}
|
||||
|
||||
sh = elfshname(".plt");
|
||||
sh->type = SHT_PROGBITS;
|
||||
sh->flags = SHF_ALLOC+SHF_EXECINSTR;
|
||||
if(eh->machine == EM_X86_64)
|
||||
sh->entsize = 16;
|
||||
else
|
||||
else if(eh->machine == EM_PPC64) {
|
||||
// On ppc64, this is just a table of addresses
|
||||
// filled by the dynamic linker
|
||||
sh->type = SHT_NOBITS;
|
||||
sh->flags = SHF_ALLOC+SHF_WRITE;
|
||||
sh->entsize = 8;
|
||||
} else
|
||||
sh->entsize = 4;
|
||||
sh->addralign = 4;
|
||||
sh->addralign = sh->entsize;
|
||||
shsym(sh, linklookup(ctxt, ".plt", 0));
|
||||
|
||||
// On ppc64, .got comes from the input files, so don't
|
||||
// create it here, and .got.plt is not used.
|
||||
if(eh->machine != EM_PPC64) {
|
||||
sh = elfshname(".got");
|
||||
sh->type = SHT_PROGBITS;
|
||||
sh->flags = SHF_ALLOC+SHF_WRITE;
|
||||
|
|
@ -1368,6 +1412,7 @@ asmbelf(vlong symo)
|
|||
sh->entsize = RegSize;
|
||||
sh->addralign = RegSize;
|
||||
shsym(sh, linklookup(ctxt, ".got.plt", 0));
|
||||
}
|
||||
|
||||
sh = elfshname(".hash");
|
||||
sh->type = SHT_HASH;
|
||||
|
|
|
|||
|
|
@ -317,6 +317,9 @@ typedef struct {
|
|||
#define DT_VERNEEDNUM 0x6fffffff
|
||||
#define DT_VERSYM 0x6ffffff0
|
||||
|
||||
#define DT_PPC64_GLINK (DT_LOPROC + 0)
|
||||
#define DT_PPC64_OPT (DT_LOPROC + 3)
|
||||
|
||||
/* Values for DT_FLAGS */
|
||||
/* Indicates that the object being loaded may make reference to
|
||||
the $ORIGIN substitution string */
|
||||
|
|
@ -700,6 +703,18 @@ typedef struct {
|
|||
/* Count of defined relocation types. */
|
||||
#define R_PPC_EMB_COUNT (R_PPC_EMB_RELSDA - R_PPC_EMB_NADDR32 + 1)
|
||||
|
||||
#define R_PPC64_REL24 R_PPC_REL24
|
||||
#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT
|
||||
#define R_PPC64_ADDR64 38
|
||||
#define R_PPC64_TOC16 47
|
||||
#define R_PPC64_TOC16_LO 48
|
||||
#define R_PPC64_TOC16_HI 49
|
||||
#define R_PPC64_TOC16_HA 50
|
||||
#define R_PPC64_TOC16_DS 63
|
||||
#define R_PPC64_TOC16_LO_DS 64
|
||||
#define R_PPC64_REL16_LO 250
|
||||
#define R_PPC64_REL16_HI 251
|
||||
#define R_PPC64_REL16_HA 252
|
||||
|
||||
#define R_SPARC_NONE 0
|
||||
#define R_SPARC_8 1
|
||||
|
|
@ -970,6 +985,7 @@ uint32 elfwritephdrs(void);
|
|||
uint32 elfwriteshdrs(void);
|
||||
void elfwritedynent(LSym*, int, uint64);
|
||||
void elfwritedynentsym(LSym*, int, LSym*);
|
||||
void elfwritedynentsymplus(LSym*, int, LSym*, vlong);
|
||||
void elfwritedynentsymsize(LSym*, int, LSym*);
|
||||
uint32 elfhash(uchar*);
|
||||
uint64 startelf(void);
|
||||
|
|
|
|||
|
|
@ -327,7 +327,7 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
|
|||
int32 base;
|
||||
uint64 add, info;
|
||||
char *name;
|
||||
int i, j, rela, is64, n;
|
||||
int i, j, rela, is64, n, flag;
|
||||
uchar hdrbuf[64];
|
||||
uchar *p;
|
||||
ElfHdrBytes *hdr;
|
||||
|
|
@ -554,6 +554,9 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
|
|||
s->type = STEXT;
|
||||
break;
|
||||
}
|
||||
if(strcmp(sect->name, ".got") == 0 ||
|
||||
strcmp(sect->name, ".toc") == 0)
|
||||
s->type = SELFGOT;
|
||||
if(sect->type == ElfSectProgbits) {
|
||||
s->p = sect->base;
|
||||
s->np = sect->size;
|
||||
|
|
@ -616,6 +619,13 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
|
|||
diag("%s: duplicate definition of %s", pn, s->name);
|
||||
s->external = 1;
|
||||
}
|
||||
if(obj->machine == ElfMachPower64) {
|
||||
flag = sym.other >> 5;
|
||||
if(2 <= flag && flag <= 6)
|
||||
s->localentry = 1 << (flag - 2);
|
||||
else if(flag == 7)
|
||||
diag("%s: invalid sym.other 0x%x for %s", pn, sym.other, s->name);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort outer lists by address, adding to textp.
|
||||
|
|
@ -714,6 +724,8 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
|
|||
else
|
||||
diag("invalid rela size %d", rp->siz);
|
||||
}
|
||||
if(rp->siz == 2)
|
||||
rp->add = (int16)rp->add;
|
||||
if(rp->siz == 4)
|
||||
rp->add = (int32)rp->add;
|
||||
//print("rel %s %d %d %s %#llx\n", sect->sym->name, rp->type, rp->siz, rp->sym->name, rp->add);
|
||||
|
|
@ -803,6 +815,10 @@ readsym(ElfObj *obj, int i, ElfSym *sym, int needSym)
|
|||
s = nil;
|
||||
if(strcmp(sym->name, "_GLOBAL_OFFSET_TABLE_") == 0)
|
||||
sym->name = ".got";
|
||||
if(strcmp(sym->name, ".TOC.") == 0)
|
||||
// Magic symbol on ppc64. Will be set to this object
|
||||
// file's .got+0x8000.
|
||||
sym->bind = ElfSymBindLocal;
|
||||
switch(sym->type) {
|
||||
case ElfSymTypeSection:
|
||||
s = obj->sect[sym->shndx].sym;
|
||||
|
|
@ -833,6 +849,15 @@ readsym(ElfObj *obj, int i, ElfSym *sym, int needSym)
|
|||
// symbols, ignore these
|
||||
break;
|
||||
}
|
||||
if(strcmp(sym->name, ".TOC.") == 0) {
|
||||
// We need to be able to look this up,
|
||||
// so put it in the hash table.
|
||||
if(needSym) {
|
||||
s = linklookup(ctxt, sym->name, ctxt->version);
|
||||
s->type |= SHIDDEN;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(needSym) {
|
||||
// local names and hidden visiblity global names are unique
|
||||
// and should only reference by its index, not name, so we
|
||||
|
|
@ -883,6 +908,17 @@ reltype(char *pn, int elftype, uchar *siz)
|
|||
switch(R(thechar, elftype)) {
|
||||
default:
|
||||
diag("%s: unknown relocation type %d; compiled without -fpic?", pn, elftype);
|
||||
case R('9', R_PPC64_TOC16):
|
||||
case R('9', R_PPC64_TOC16_LO):
|
||||
case R('9', R_PPC64_TOC16_HI):
|
||||
case R('9', R_PPC64_TOC16_HA):
|
||||
case R('9', R_PPC64_TOC16_DS):
|
||||
case R('9', R_PPC64_TOC16_LO_DS):
|
||||
case R('9', R_PPC64_REL16_LO):
|
||||
case R('9', R_PPC64_REL16_HI):
|
||||
case R('9', R_PPC64_REL16_HA):
|
||||
*siz = 2;
|
||||
break;
|
||||
case R('5', R_ARM_ABS32):
|
||||
case R('5', R_ARM_GOT32):
|
||||
case R('5', R_ARM_PLT32):
|
||||
|
|
@ -904,9 +940,11 @@ reltype(char *pn, int elftype, uchar *siz)
|
|||
case R('8', R_386_PLT32):
|
||||
case R('8', R_386_GOTOFF):
|
||||
case R('8', R_386_GOTPC):
|
||||
case R('9', R_PPC64_REL24):
|
||||
*siz = 4;
|
||||
break;
|
||||
case R('6', R_X86_64_64):
|
||||
case R('9', R_PPC64_ADDR64):
|
||||
*siz = 8;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
|
||||
enum {
|
||||
MAXIO = 8192,
|
||||
MINFUNC = 16, // minimum size for a function
|
||||
};
|
||||
|
||||
typedef struct Segment Segment;
|
||||
|
|
@ -260,6 +261,7 @@ void patch(void);
|
|||
int pathchar(void);
|
||||
void pcln(void);
|
||||
void pclntab(void);
|
||||
void findfunctab(void);
|
||||
void putelfsectionsym(LSym* s, int shndx);
|
||||
void putelfsymshndx(vlong sympos, int shndx);
|
||||
void putsymb(LSym *s, char *name, int t, vlong v, vlong size, int ver, LSym *typ);
|
||||
|
|
|
|||
|
|
@ -242,3 +242,58 @@ pclntab(void)
|
|||
if(debug['v'])
|
||||
Bprint(&bso, "%5.2f pclntab=%lld bytes, funcdata total %lld bytes\n", cputime(), (vlong)ftab->size, (vlong)funcdata_bytes);
|
||||
}
|
||||
|
||||
enum {
|
||||
BUCKETSIZE = 256*MINFUNC,
|
||||
SUBBUCKETS = 16,
|
||||
};
|
||||
|
||||
// findfunctab generates a lookup table to quickly find the containing
|
||||
// function for a pc. See src/runtime/symtab.go:findfunc for details.
|
||||
void
|
||||
findfunctab(void)
|
||||
{
|
||||
LSym *t, *s;
|
||||
int32 idx, bidx, i, j, nbuckets;
|
||||
vlong min, max;
|
||||
|
||||
t = linklookup(ctxt, "runtime.findfunctab", 0);
|
||||
t->type = SRODATA;
|
||||
t->reachable = 1;
|
||||
|
||||
// find min and max address
|
||||
min = ctxt->textp->value;
|
||||
max = 0;
|
||||
for(s = ctxt->textp; s != nil; s = s->next)
|
||||
max = s->value + s->size;
|
||||
|
||||
// allocate table
|
||||
nbuckets = (max-min+BUCKETSIZE-1)/BUCKETSIZE;
|
||||
symgrow(ctxt, t, nbuckets * (4+SUBBUCKETS));
|
||||
|
||||
// fill in table
|
||||
s = ctxt->textp;
|
||||
idx = 0;
|
||||
for(i = 0; i < nbuckets; i++) {
|
||||
// Find first function which overlaps this bucket.
|
||||
// Only do leaf symbols; skip symbols which are just containers (sub != nil but outer == nil).
|
||||
while(s != nil && (s->value+s->size <= min + i * BUCKETSIZE || s->sub != nil && s->outer == nil)) {
|
||||
s = s->next;
|
||||
idx++;
|
||||
}
|
||||
// record this function in bucket header
|
||||
setuint32(ctxt, t, i*(4+SUBBUCKETS), idx);
|
||||
bidx = idx;
|
||||
|
||||
// compute SUBBUCKETS deltas
|
||||
for(j = 0; j < SUBBUCKETS; j++) {
|
||||
while(s != nil && (s->value+s->size <= min + i * BUCKETSIZE + j * (BUCKETSIZE/SUBBUCKETS) || s->sub != nil && s->outer == nil)) {
|
||||
s = s->next;
|
||||
idx++;
|
||||
}
|
||||
if(idx - bidx >= 256)
|
||||
diag("too many functions in a findfunc bucket! %d %s", idx-bidx, s->name);
|
||||
setuint8(ctxt, t, i*(4+SUBBUCKETS)+4+j, idx-bidx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -187,6 +187,7 @@ main(int argc, char *argv[])
|
|||
gentext(); // trampolines, call stubs, etc.
|
||||
textaddress();
|
||||
pclntab();
|
||||
findfunctab();
|
||||
symtab();
|
||||
dodata();
|
||||
address();
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ type CurveParams struct {
|
|||
B *big.Int // the constant of the curve equation
|
||||
Gx, Gy *big.Int // (x,y) of the base point
|
||||
BitSize int // the size of the underlying field
|
||||
Name string // the canonical name of the curve
|
||||
}
|
||||
|
||||
func (curve *CurveParams) Params() *CurveParams {
|
||||
|
|
@ -334,7 +335,7 @@ func initAll() {
|
|||
|
||||
func initP384() {
|
||||
// See FIPS 186-3, section D.2.4
|
||||
p384 = new(CurveParams)
|
||||
p384 = &CurveParams{Name: "P-384"}
|
||||
p384.P, _ = new(big.Int).SetString("39402006196394479212279040100143613805079739270465446667948293404245721771496870329047266088258938001861606973112319", 10)
|
||||
p384.N, _ = new(big.Int).SetString("39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942643", 10)
|
||||
p384.B, _ = new(big.Int).SetString("b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef", 16)
|
||||
|
|
@ -345,7 +346,7 @@ func initP384() {
|
|||
|
||||
func initP521() {
|
||||
// See FIPS 186-3, section D.2.5
|
||||
p521 = new(CurveParams)
|
||||
p521 = &CurveParams{Name: "P-521"}
|
||||
p521.P, _ = new(big.Int).SetString("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", 10)
|
||||
p521.N, _ = new(big.Int).SetString("6864797660130609714981900799081393217269435300143305409394463459185543183397655394245057746333217197532963996371363321113864768612440380340372808892707005449", 10)
|
||||
p521.B, _ = new(big.Int).SetString("051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", 16)
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ type p224Curve struct {
|
|||
|
||||
func initP224() {
|
||||
// See FIPS 186-3, section D.2.2
|
||||
p224.CurveParams = new(CurveParams)
|
||||
p224.CurveParams = &CurveParams{Name: "P-224"}
|
||||
p224.P, _ = new(big.Int).SetString("26959946667150639794667015087019630673557916260026308143510066298881", 10)
|
||||
p224.N, _ = new(big.Int).SetString("26959946667150639794667015087019625940457807714424391721682722368061", 10)
|
||||
p224.B, _ = new(big.Int).SetString("b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4", 16)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ var (
|
|||
|
||||
func initP256() {
|
||||
// See FIPS 186-3, section D.2.3
|
||||
p256.CurveParams = new(CurveParams)
|
||||
p256.CurveParams = &CurveParams{Name: "P-256"}
|
||||
p256.P, _ = new(big.Int).SetString("115792089210356248762697446949407573530086143415290314195533631308867097853951", 10)
|
||||
p256.N, _ = new(big.Int).SetString("115792089210356248762697446949407573529996955224135760342422259061068512044369", 10)
|
||||
p256.B, _ = new(big.Int).SetString("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16)
|
||||
|
|
|
|||
|
|
@ -167,22 +167,24 @@ func Dial(network, addr string, config *Config) (*Conn, error) {
|
|||
|
||||
// LoadX509KeyPair reads and parses a public/private key pair from a pair of
|
||||
// files. The files must contain PEM encoded data.
|
||||
func LoadX509KeyPair(certFile, keyFile string) (cert Certificate, err error) {
|
||||
func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) {
|
||||
certPEMBlock, err := ioutil.ReadFile(certFile)
|
||||
if err != nil {
|
||||
return
|
||||
return Certificate{}, err
|
||||
}
|
||||
keyPEMBlock, err := ioutil.ReadFile(keyFile)
|
||||
if err != nil {
|
||||
return
|
||||
return Certificate{}, err
|
||||
}
|
||||
return X509KeyPair(certPEMBlock, keyPEMBlock)
|
||||
}
|
||||
|
||||
// X509KeyPair parses a public/private key pair from a pair of
|
||||
// PEM encoded data.
|
||||
func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err error) {
|
||||
func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) {
|
||||
var cert Certificate
|
||||
var certDERBlock *pem.Block
|
||||
fail := func(err error) (Certificate, error) { return Certificate{}, err }
|
||||
for {
|
||||
certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
|
||||
if certDERBlock == nil {
|
||||
|
|
@ -194,62 +196,56 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err error)
|
|||
}
|
||||
|
||||
if len(cert.Certificate) == 0 {
|
||||
err = errors.New("crypto/tls: failed to parse certificate PEM data")
|
||||
return
|
||||
return fail(errors.New("crypto/tls: failed to parse certificate PEM data"))
|
||||
}
|
||||
|
||||
var keyDERBlock *pem.Block
|
||||
for {
|
||||
keyDERBlock, keyPEMBlock = pem.Decode(keyPEMBlock)
|
||||
if keyDERBlock == nil {
|
||||
err = errors.New("crypto/tls: failed to parse key PEM data")
|
||||
return
|
||||
return fail(errors.New("crypto/tls: failed to parse key PEM data"))
|
||||
}
|
||||
if keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
cert.PrivateKey, err = parsePrivateKey(keyDERBlock.Bytes)
|
||||
if err != nil {
|
||||
return
|
||||
return fail(err)
|
||||
}
|
||||
|
||||
// We don't need to parse the public key for TLS, but we so do anyway
|
||||
// to check that it looks sane and matches the private key.
|
||||
x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
|
||||
if err != nil {
|
||||
return
|
||||
return fail(err)
|
||||
}
|
||||
|
||||
switch pub := x509Cert.PublicKey.(type) {
|
||||
case *rsa.PublicKey:
|
||||
priv, ok := cert.PrivateKey.(*rsa.PrivateKey)
|
||||
if !ok {
|
||||
err = errors.New("crypto/tls: private key type does not match public key type")
|
||||
return
|
||||
return fail(errors.New("crypto/tls: private key type does not match public key type"))
|
||||
}
|
||||
if pub.N.Cmp(priv.N) != 0 {
|
||||
err = errors.New("crypto/tls: private key does not match public key")
|
||||
return
|
||||
return fail(errors.New("crypto/tls: private key does not match public key"))
|
||||
}
|
||||
case *ecdsa.PublicKey:
|
||||
priv, ok := cert.PrivateKey.(*ecdsa.PrivateKey)
|
||||
if !ok {
|
||||
err = errors.New("crypto/tls: private key type does not match public key type")
|
||||
return
|
||||
return fail(errors.New("crypto/tls: private key type does not match public key type"))
|
||||
|
||||
}
|
||||
if pub.X.Cmp(priv.X) != 0 || pub.Y.Cmp(priv.Y) != 0 {
|
||||
err = errors.New("crypto/tls: private key does not match public key")
|
||||
return
|
||||
return fail(errors.New("crypto/tls: private key does not match public key"))
|
||||
}
|
||||
default:
|
||||
err = errors.New("crypto/tls: unknown public key algorithm")
|
||||
return
|
||||
return fail(errors.New("crypto/tls: unknown public key algorithm"))
|
||||
}
|
||||
|
||||
return
|
||||
return cert, nil
|
||||
}
|
||||
|
||||
// Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ func (certList *CertificateList) HasExpired(now time.Time) bool {
|
|||
// 5280, section 5.1.
|
||||
type TBSCertificateList struct {
|
||||
Raw asn1.RawContent
|
||||
Version int `asn1:"optional,default:2"`
|
||||
Version int `asn1:"optional,default:1"`
|
||||
Signature AlgorithmIdentifier
|
||||
Issuer RDNSequence
|
||||
ThisUpdate time.Time
|
||||
|
|
|
|||
|
|
@ -7,4 +7,5 @@ package x509
|
|||
// Possible certificate files; stop after finding one.
|
||||
var certFiles = []string{
|
||||
"/etc/certs/ca-certificates.crt", // Solaris 11.2+
|
||||
"/etc/ssl/certs/ca-certificates.crt", // Joyent SmartOS
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1377,8 +1377,11 @@ func signingParamsForPrivateKey(priv interface{}, requestedSigAlgo SignatureAlgo
|
|||
switch priv := priv.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
pubType = RSA
|
||||
sigAlgo.Algorithm = oidSignatureSHA256WithRSA
|
||||
hashFunc = crypto.SHA256
|
||||
sigAlgo.Algorithm = oidSignatureSHA256WithRSA
|
||||
sigAlgo.Parameters = asn1.RawValue{
|
||||
Tag: 5,
|
||||
}
|
||||
|
||||
case *ecdsa.PrivateKey:
|
||||
pubType = ECDSA
|
||||
|
|
@ -1572,7 +1575,7 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts [
|
|||
return nil, errors.New("x509: non-RSA private keys not supported")
|
||||
}
|
||||
tbsCertList := pkix.TBSCertificateList{
|
||||
Version: 2,
|
||||
Version: 1,
|
||||
Signature: pkix.AlgorithmIdentifier{
|
||||
Algorithm: oidSignatureSHA1WithRSA,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -267,6 +267,7 @@ var cgoEnabled = map[string]bool{
|
|||
"linux/386": true,
|
||||
"linux/amd64": true,
|
||||
"linux/arm": true,
|
||||
"linux/ppc64le": true,
|
||||
"android/386": true,
|
||||
"android/amd64": true,
|
||||
"android/arm": true,
|
||||
|
|
@ -1072,9 +1073,6 @@ func (ctxt *Context) shouldBuild(content []byte, allTags map[string]bool) bool {
|
|||
// saveCgo saves the information from the #cgo lines in the import "C" comment.
|
||||
// These lines set CFLAGS, CPPFLAGS, CXXFLAGS and LDFLAGS and pkg-config directives
|
||||
// that affect the way cgo's C code is built.
|
||||
//
|
||||
// TODO(rsc): This duplicates code in cgo.
|
||||
// Once the dust settles, remove this code from cgo.
|
||||
func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup) error {
|
||||
text := cg.Text()
|
||||
for _, line := range strings.Split(text, "\n") {
|
||||
|
|
|
|||
|
|
@ -139,7 +139,19 @@ var clipTests = []clipTest{
|
|||
image.Pt(20, 0),
|
||||
image.Pt(20, 0),
|
||||
},
|
||||
// TODO(nigeltao): write more tests.
|
||||
{
|
||||
"clip sr and mr",
|
||||
image.Rect(0, 0, 100, 100),
|
||||
image.Rect(0, 0, 100, 100),
|
||||
image.Rect(23, 23, 55, 86),
|
||||
image.Rect(44, 44, 87, 58),
|
||||
image.Pt(10, 10),
|
||||
image.Pt(11, 11),
|
||||
false,
|
||||
image.Rect(33, 33, 45, 47),
|
||||
image.Pt(43, 43),
|
||||
image.Pt(44, 44),
|
||||
},
|
||||
}
|
||||
|
||||
func TestClip(t *testing.T) {
|
||||
|
|
@ -149,12 +161,12 @@ func TestClip(t *testing.T) {
|
|||
for _, c := range clipTests {
|
||||
dst := dst0.SubImage(c.dr).(*image.RGBA)
|
||||
src := src0.SubImage(c.sr).(*image.RGBA)
|
||||
var mask image.Image
|
||||
if !c.nilMask {
|
||||
mask = mask0.SubImage(c.mr)
|
||||
}
|
||||
r, sp, mp := c.r, c.sp, c.mp
|
||||
clip(dst, &r, src, &sp, mask, &mp)
|
||||
if c.nilMask {
|
||||
clip(dst, &r, src, &sp, nil, nil)
|
||||
} else {
|
||||
clip(dst, &r, src, &sp, mask0.SubImage(c.mr), &mp)
|
||||
}
|
||||
|
||||
// Check that the actual results equal the expected results.
|
||||
if !c.r0.Eq(r) {
|
||||
|
|
@ -191,13 +203,3 @@ func TestClip(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestClipWithNilMP(t *testing.T) {
|
||||
src := image.NewRGBA(image.Rect(0, 0, 100, 100))
|
||||
// dst must be smaller than src for clipping to occur
|
||||
dst := image.NewRGBA(image.Rect(50, 50, 100, 100))
|
||||
r := image.Rect(0, 0, 100, 100)
|
||||
sp := image.ZP
|
||||
// issue 9177: floydSteinberg.Draw passes nil for mp, which used to cause clip to panic
|
||||
clip(dst, &r, src, &sp, nil, nil)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,11 +81,11 @@ func clip(dst Image, r *image.Rectangle, src image.Image, sp *image.Point, mask
|
|||
if dx == 0 && dy == 0 {
|
||||
return
|
||||
}
|
||||
(*sp).X += dx
|
||||
(*sp).Y += dy
|
||||
sp.X += dx
|
||||
sp.Y += dy
|
||||
if mp != nil {
|
||||
(*mp).X += dx
|
||||
(*mp).Y += dy
|
||||
mp.X += dx
|
||||
mp.Y += dy
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -329,25 +329,25 @@ static struct {
|
|||
static int checkpool(Link*, Prog*, int);
|
||||
static int flushpool(Link*, Prog*, int, int);
|
||||
static void addpool(Link*, Prog*, Addr*);
|
||||
static void asmout(Link*, Prog*, Optab*, int32*);
|
||||
static int asmoutnacl(Link*, int32, Prog*, Optab*, int32 *);
|
||||
static void asmout(Link*, Prog*, Optab*, uint32*);
|
||||
static int asmoutnacl(Link*, int32, Prog*, Optab*, uint32*);
|
||||
static Optab* oplook(Link*, Prog*);
|
||||
static int32 oprrr(Link*, int, int);
|
||||
static int32 olr(Link*, int32, int, int, int);
|
||||
static int32 olhr(Link*, int32, int, int, int);
|
||||
static int32 olrr(Link*, int, int, int, int);
|
||||
static int32 olhrr(Link*, int, int, int, int);
|
||||
static int32 osr(Link*, int, int, int32, int, int);
|
||||
static int32 oshr(Link*, int, int32, int, int);
|
||||
static int32 ofsr(Link*, int, int, int32, int, int, Prog*);
|
||||
static int32 osrr(Link*, int, int, int, int);
|
||||
static int32 oshrr(Link*, int, int, int, int);
|
||||
static int32 omvl(Link*, Prog*, Addr*, int);
|
||||
static uint32 oprrr(Link*, int, int);
|
||||
static uint32 olr(Link*, int32, int, int, int);
|
||||
static uint32 olhr(Link*, int32, int, int, int);
|
||||
static uint32 olrr(Link*, int, int, int, int);
|
||||
static uint32 olhrr(Link*, int, int, int, int);
|
||||
static uint32 osr(Link*, int, int, int32, int, int);
|
||||
static uint32 oshr(Link*, int, int32, int, int);
|
||||
static uint32 ofsr(Link*, int, int, int32, int, int, Prog*);
|
||||
static uint32 osrr(Link*, int, int, int, int);
|
||||
static uint32 oshrr(Link*, int, int, int, int);
|
||||
static uint32 omvl(Link*, Prog*, Addr*, int);
|
||||
static int32 immaddr(int32);
|
||||
static int aclass(Link*, Addr*);
|
||||
static int32 immrot(uint32);
|
||||
static int32 immaddr(int32);
|
||||
static int32 opbra(Link*, int, int);
|
||||
static uint32 opbra(Link*, int, int);
|
||||
|
||||
static Oprang oprange[ALAST];
|
||||
static uchar xcmp[C_GOK+1][C_GOK+1];
|
||||
|
|
@ -405,7 +405,7 @@ static void buildop(Link*);
|
|||
// In rare cases, asmoutnacl might split p into two instructions.
|
||||
// origPC is the PC for this Prog (no padding is taken into account).
|
||||
static int
|
||||
asmoutnacl(Link *ctxt, int32 origPC, Prog *p, Optab *o, int32 *out)
|
||||
asmoutnacl(Link *ctxt, int32 origPC, Prog *p, Optab *o, uint32 *out)
|
||||
{
|
||||
int size, reg;
|
||||
Prog *q;
|
||||
|
|
@ -642,7 +642,8 @@ span5(Link *ctxt, LSym *cursym)
|
|||
Prog *p, *op;
|
||||
Optab *o;
|
||||
int m, bflag, i, v, times;
|
||||
int32 c, opc, out[6+3];
|
||||
int32 c, opc;
|
||||
uint32 out[6+3];
|
||||
uchar *bp;
|
||||
|
||||
p = cursym->text;
|
||||
|
|
@ -682,7 +683,10 @@ span5(Link *ctxt, LSym *cursym)
|
|||
}
|
||||
// must check literal pool here in case p generates many instructions
|
||||
if(ctxt->blitrl){
|
||||
if(checkpool(ctxt, op, p->as == ACASE ? casesz(ctxt, p) : m)) {
|
||||
i = m;
|
||||
if(p->as == ACASE)
|
||||
i = casesz(ctxt, p);
|
||||
if(checkpool(ctxt, op, i)) {
|
||||
p = op;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -1070,8 +1074,11 @@ aclass(Link *ctxt, Addr *a)
|
|||
ctxt->instoffset = ctxt->autosize + a->offset;
|
||||
t = immaddr(ctxt->instoffset);
|
||||
if(t){
|
||||
if(immhalf(ctxt->instoffset))
|
||||
return immfloat(t) ? C_HFAUTO : C_HAUTO;
|
||||
if(immhalf(ctxt->instoffset)) {
|
||||
if(immfloat(t))
|
||||
return C_HFAUTO;
|
||||
return C_HAUTO;
|
||||
}
|
||||
if(immfloat(t))
|
||||
return C_FAUTO;
|
||||
return C_SAUTO;
|
||||
|
|
@ -1082,8 +1089,11 @@ aclass(Link *ctxt, Addr *a)
|
|||
ctxt->instoffset = ctxt->autosize + a->offset + 4L;
|
||||
t = immaddr(ctxt->instoffset);
|
||||
if(t){
|
||||
if(immhalf(ctxt->instoffset))
|
||||
return immfloat(t) ? C_HFAUTO : C_HAUTO;
|
||||
if(immhalf(ctxt->instoffset)) {
|
||||
if(immfloat(t))
|
||||
return C_HFAUTO;
|
||||
return C_HAUTO;
|
||||
}
|
||||
if(immfloat(t))
|
||||
return C_FAUTO;
|
||||
return C_SAUTO;
|
||||
|
|
@ -1093,8 +1103,11 @@ aclass(Link *ctxt, Addr *a)
|
|||
ctxt->instoffset = a->offset;
|
||||
t = immaddr(ctxt->instoffset);
|
||||
if(t) {
|
||||
if(immhalf(ctxt->instoffset)) /* n.b. that it will also satisfy immrot */
|
||||
return immfloat(t) ? C_HFOREG : C_HOREG;
|
||||
if(immhalf(ctxt->instoffset)) { /* n.b. that it will also satisfy immrot */
|
||||
if(immfloat(t))
|
||||
return C_HFOREG;
|
||||
return C_HOREG;
|
||||
}
|
||||
if(immfloat(t))
|
||||
return C_FOREG; /* n.b. that it will also satisfy immrot */
|
||||
t = immrot(ctxt->instoffset);
|
||||
|
|
@ -1488,12 +1501,13 @@ buildop(Link *ctxt)
|
|||
}
|
||||
}
|
||||
|
||||
static int32 mov(Link*, Prog*);
|
||||
static uint32 mov(Link*, Prog*);
|
||||
|
||||
static void
|
||||
asmout(Link *ctxt, Prog *p, Optab *o, int32 *out)
|
||||
asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
|
||||
{
|
||||
int32 o1, o2, o3, o4, o5, o6, v;
|
||||
uint32 o1, o2, o3, o4, o5, o6;
|
||||
int32 v;
|
||||
int r, rf, rt, rt2;
|
||||
Reloc *rel;
|
||||
|
||||
|
|
@ -2315,10 +2329,10 @@ if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->na
|
|||
return;
|
||||
}
|
||||
|
||||
static int32
|
||||
static uint32
|
||||
mov(Link *ctxt, Prog *p)
|
||||
{
|
||||
int32 o1;
|
||||
uint32 o1;
|
||||
int rt, r;
|
||||
|
||||
aclass(ctxt, &p->from);
|
||||
|
|
@ -2336,10 +2350,10 @@ mov(Link *ctxt, Prog *p)
|
|||
return o1;
|
||||
}
|
||||
|
||||
static int32
|
||||
static uint32
|
||||
oprrr(Link *ctxt, int a, int sc)
|
||||
{
|
||||
int32 o;
|
||||
uint32 o;
|
||||
|
||||
o = (sc & C_SCOND) << 28;
|
||||
if(sc & C_SBIT)
|
||||
|
|
@ -2450,7 +2464,7 @@ oprrr(Link *ctxt, int a, int sc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int32
|
||||
static uint32
|
||||
opbra(Link *ctxt, int a, int sc)
|
||||
{
|
||||
|
||||
|
|
@ -2485,10 +2499,10 @@ opbra(Link *ctxt, int a, int sc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int32
|
||||
static uint32
|
||||
olr(Link *ctxt, int32 v, int b, int r, int sc)
|
||||
{
|
||||
int32 o;
|
||||
uint32 o;
|
||||
|
||||
if(sc & C_SBIT)
|
||||
ctxt->diag(".nil on LDR/STR instruction");
|
||||
|
|
@ -2514,10 +2528,10 @@ olr(Link *ctxt, int32 v, int b, int r, int sc)
|
|||
return o;
|
||||
}
|
||||
|
||||
static int32
|
||||
static uint32
|
||||
olhr(Link *ctxt, int32 v, int b, int r, int sc)
|
||||
{
|
||||
int32 o;
|
||||
uint32 o;
|
||||
|
||||
if(sc & C_SBIT)
|
||||
ctxt->diag(".nil on LDRH/STRH instruction");
|
||||
|
|
@ -2539,10 +2553,10 @@ olhr(Link *ctxt, int32 v, int b, int r, int sc)
|
|||
return o;
|
||||
}
|
||||
|
||||
static int32
|
||||
static uint32
|
||||
osr(Link *ctxt, int a, int r, int32 v, int b, int sc)
|
||||
{
|
||||
int32 o;
|
||||
uint32 o;
|
||||
|
||||
o = olr(ctxt, v, b, r, sc) ^ (1<<20);
|
||||
if(a != AMOVW)
|
||||
|
|
@ -2550,46 +2564,46 @@ osr(Link *ctxt, int a, int r, int32 v, int b, int sc)
|
|||
return o;
|
||||
}
|
||||
|
||||
static int32
|
||||
static uint32
|
||||
oshr(Link *ctxt, int r, int32 v, int b, int sc)
|
||||
{
|
||||
int32 o;
|
||||
uint32 o;
|
||||
|
||||
o = olhr(ctxt, v, b, r, sc) ^ (1<<20);
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
static int32
|
||||
static uint32
|
||||
osrr(Link *ctxt, int r, int i, int b, int sc)
|
||||
{
|
||||
|
||||
return olr(ctxt, i, b, r, sc) ^ ((1<<25) | (1<<20));
|
||||
}
|
||||
|
||||
static int32
|
||||
static uint32
|
||||
oshrr(Link *ctxt, int r, int i, int b, int sc)
|
||||
{
|
||||
return olhr(ctxt, i, b, r, sc) ^ ((1<<22) | (1<<20));
|
||||
}
|
||||
|
||||
static int32
|
||||
static uint32
|
||||
olrr(Link *ctxt, int i, int b, int r, int sc)
|
||||
{
|
||||
|
||||
return olr(ctxt, i, b, r, sc) ^ (1<<25);
|
||||
}
|
||||
|
||||
static int32
|
||||
static uint32
|
||||
olhrr(Link *ctxt, int i, int b, int r, int sc)
|
||||
{
|
||||
return olhr(ctxt, i, b, r, sc) ^ (1<<22);
|
||||
}
|
||||
|
||||
static int32
|
||||
static uint32
|
||||
ofsr(Link *ctxt, int a, int r, int32 v, int b, int sc, Prog *p)
|
||||
{
|
||||
int32 o;
|
||||
uint32 o;
|
||||
|
||||
if(sc & C_SBIT)
|
||||
ctxt->diag(".nil on FLDR/FSTR instruction");
|
||||
|
|
@ -2623,10 +2637,11 @@ ofsr(Link *ctxt, int a, int r, int32 v, int b, int sc, Prog *p)
|
|||
return o;
|
||||
}
|
||||
|
||||
static int32
|
||||
static uint32
|
||||
omvl(Link *ctxt, Prog *p, Addr *a, int dr)
|
||||
{
|
||||
int32 v, o1;
|
||||
int32 v;
|
||||
uint32 o1;
|
||||
if(!p->pcond) {
|
||||
aclass(ctxt, a);
|
||||
v = immrot(~ctxt->instoffset);
|
||||
|
|
@ -2659,7 +2674,7 @@ chipfloat5(Link *ctxt, float64 e)
|
|||
{
|
||||
int n;
|
||||
ulong h1;
|
||||
int32 l, h;
|
||||
uint32 l, h;
|
||||
uint64 ei;
|
||||
|
||||
// We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
|
||||
|
|
@ -2667,8 +2682,8 @@ chipfloat5(Link *ctxt, float64 e)
|
|||
goto no;
|
||||
|
||||
memmove(&ei, &e, 8);
|
||||
l = (int32)ei;
|
||||
h = (int32)(ei>>32);
|
||||
l = (uint32)ei;
|
||||
h = (uint32)(ei>>32);
|
||||
|
||||
if(l != 0 || (h&0xffff) != 0)
|
||||
goto no;
|
||||
|
|
|
|||
|
|
@ -454,7 +454,7 @@ static int isint32(vlong);
|
|||
static int isuint32(uvlong);
|
||||
static int aclass(Link*, Addr*);
|
||||
static Optab* oplook(Link*, Prog*);
|
||||
static void asmout(Link*, Prog*, Optab*, int32*);
|
||||
static void asmout(Link*, Prog*, Optab*, uint32*);
|
||||
static vlong vregoff(Link*, Addr*);
|
||||
static int32 regoff(Link*, Addr*);
|
||||
static int32 oprrr(Link*, int);
|
||||
|
|
@ -468,13 +468,16 @@ static void maskgen(Link*, Prog*, uchar*, uint32);
|
|||
static int getmask64(uchar*, uvlong);
|
||||
static void maskgen64(Link*, Prog*, uchar*, uvlong);
|
||||
static uint32 loadu32(int, vlong);
|
||||
static void addaddrreloc(Link*, LSym*, int*, int*);
|
||||
static void addaddrreloc(Link*, LSym*, uint32*, uint32*);
|
||||
|
||||
static struct
|
||||
typedef struct Oprang Oprang;
|
||||
struct Oprang
|
||||
{
|
||||
Optab* start;
|
||||
Optab* stop;
|
||||
} oprange[ALAST];
|
||||
};
|
||||
|
||||
static Oprang oprange[ALAST];
|
||||
|
||||
static uchar xcmp[C_NCLASS][C_NCLASS];
|
||||
|
||||
|
|
@ -486,7 +489,8 @@ span9(Link *ctxt, LSym *cursym)
|
|||
Optab *o;
|
||||
int m, bflag;
|
||||
vlong c, otxt;
|
||||
int32 out[6], i, j;
|
||||
uint32 out[6];
|
||||
int32 i, j;
|
||||
uchar *bp, *cast;
|
||||
|
||||
p = cursym->text;
|
||||
|
|
@ -687,27 +691,7 @@ aclass(Link *ctxt, Addr *a)
|
|||
return C_LACON;
|
||||
return C_DACON;
|
||||
}
|
||||
consize:
|
||||
if(ctxt->instoffset >= 0) {
|
||||
if(ctxt->instoffset == 0)
|
||||
return C_ZCON;
|
||||
if(ctxt->instoffset <= 0x7fff)
|
||||
return C_SCON;
|
||||
if(ctxt->instoffset <= 0xffff)
|
||||
return C_ANDCON;
|
||||
if((ctxt->instoffset & 0xffff) == 0 && isuint32(ctxt->instoffset)) /* && (instoffset & (1<<31)) == 0) */
|
||||
return C_UCON;
|
||||
if(isint32(ctxt->instoffset) || isuint32(ctxt->instoffset))
|
||||
return C_LCON;
|
||||
return C_DCON;
|
||||
}
|
||||
if(ctxt->instoffset >= -0x8000)
|
||||
return C_ADDCON;
|
||||
if((ctxt->instoffset & 0xffff) == 0 && isint32(ctxt->instoffset))
|
||||
return C_UCON;
|
||||
if(isint32(ctxt->instoffset))
|
||||
return C_LCON;
|
||||
return C_DCON;
|
||||
goto consize;
|
||||
|
||||
case D_EXTERN:
|
||||
case D_STATIC:
|
||||
|
|
@ -736,6 +720,28 @@ aclass(Link *ctxt, Addr *a)
|
|||
}
|
||||
return C_GOK;
|
||||
|
||||
consize:
|
||||
if(ctxt->instoffset >= 0) {
|
||||
if(ctxt->instoffset == 0)
|
||||
return C_ZCON;
|
||||
if(ctxt->instoffset <= 0x7fff)
|
||||
return C_SCON;
|
||||
if(ctxt->instoffset <= 0xffff)
|
||||
return C_ANDCON;
|
||||
if((ctxt->instoffset & 0xffff) == 0 && isuint32(ctxt->instoffset)) /* && (instoffset & (1<<31)) == 0) */
|
||||
return C_UCON;
|
||||
if(isint32(ctxt->instoffset) || isuint32(ctxt->instoffset))
|
||||
return C_LCON;
|
||||
return C_DCON;
|
||||
}
|
||||
if(ctxt->instoffset >= -0x8000)
|
||||
return C_ADDCON;
|
||||
if((ctxt->instoffset & 0xffff) == 0 && isint32(ctxt->instoffset))
|
||||
return C_UCON;
|
||||
if(isint32(ctxt->instoffset))
|
||||
return C_LCON;
|
||||
return C_DCON;
|
||||
|
||||
case D_BRANCH:
|
||||
return C_SBRA;
|
||||
}
|
||||
|
|
@ -1271,61 +1277,120 @@ buildop(Link *ctxt)
|
|||
}
|
||||
}
|
||||
|
||||
#define OPVCC(o,xo,oe,rc) (((o)<<26)|((xo)<<1)|((oe)<<10)|((rc)&1))
|
||||
#define OPCC(o,xo,rc) OPVCC((o),(xo),0,(rc))
|
||||
#define OP(o,xo) OPVCC((o),(xo),0,0)
|
||||
uint32
|
||||
OPVCC(uint32 o, uint32 xo, uint32 oe, uint32 rc)
|
||||
{
|
||||
return o<<26 | xo<<1 | oe<<10 | rc&1;
|
||||
}
|
||||
|
||||
uint32
|
||||
OPCC(uint32 o, uint32 xo, uint32 rc)
|
||||
{
|
||||
return OPVCC(o, xo, 0, rc);
|
||||
}
|
||||
|
||||
uint32
|
||||
OP(uint32 o, uint32 xo)
|
||||
{
|
||||
return OPVCC(o, xo, 0, 0);
|
||||
}
|
||||
|
||||
/* the order is dest, a/s, b/imm for both arithmetic and logical operations */
|
||||
#define AOP_RRR(op,d,a,b) ((op)|(((d)&31L)<<21)|(((a)&31L)<<16)|(((b)&31L)<<11))
|
||||
#define AOP_IRR(op,d,a,simm) ((op)|(((d)&31L)<<21)|(((a)&31L)<<16)|((simm)&0xFFFF))
|
||||
#define LOP_RRR(op,a,s,b) ((op)|(((s)&31L)<<21)|(((a)&31L)<<16)|(((b)&31L)<<11))
|
||||
#define LOP_IRR(op,a,s,uimm) ((op)|(((s)&31L)<<21)|(((a)&31L)<<16)|((uimm)&0xFFFF))
|
||||
#define OP_BR(op,li,aa) ((op)|((li)&0x03FFFFFC)|((aa)<<1))
|
||||
#define OP_BC(op,bo,bi,bd,aa) ((op)|(((bo)&0x1F)<<21)|(((bi)&0x1F)<<16)|((bd)&0xFFFC)|((aa)<<1))
|
||||
#define OP_BCR(op,bo,bi) ((op)|(((bo)&0x1F)<<21)|(((bi)&0x1F)<<16))
|
||||
#define OP_RLW(op,a,s,sh,mb,me) ((op)|(((s)&31L)<<21)|(((a)&31L)<<16)|(((sh)&31L)<<11)|\
|
||||
(((mb)&31L)<<6)|(((me)&31L)<<1))
|
||||
uint32
|
||||
AOP_RRR(uint32 op, uint32 d, uint32 a, uint32 b)
|
||||
{
|
||||
return op | (d&31)<<21 | (a&31)<<16 | (b&31)<<11;
|
||||
}
|
||||
|
||||
#define OP_ADD OPVCC(31,266,0,0)
|
||||
#define OP_ADDI OPVCC(14,0,0,0)
|
||||
#define OP_ADDIS OPVCC(15,0,0,0)
|
||||
#define OP_ANDI OPVCC(28,0,0,0)
|
||||
#define OP_EXTSB OPVCC(31,954,0,0)
|
||||
#define OP_EXTSH OPVCC(31,922,0,0)
|
||||
#define OP_EXTSW OPVCC(31,986,0,0)
|
||||
#define OP_MCRF OPVCC(19,0,0,0)
|
||||
#define OP_MCRFS OPVCC(63,64,0,0)
|
||||
#define OP_MCRXR OPVCC(31,512,0,0)
|
||||
#define OP_MFCR OPVCC(31,19,0,0)
|
||||
#define OP_MFFS OPVCC(63,583,0,0)
|
||||
#define OP_MFMSR OPVCC(31,83,0,0)
|
||||
#define OP_MFSPR OPVCC(31,339,0,0)
|
||||
#define OP_MFSR OPVCC(31,595,0,0)
|
||||
#define OP_MFSRIN OPVCC(31,659,0,0)
|
||||
#define OP_MTCRF OPVCC(31,144,0,0)
|
||||
#define OP_MTFSF OPVCC(63,711,0,0)
|
||||
#define OP_MTFSFI OPVCC(63,134,0,0)
|
||||
#define OP_MTMSR OPVCC(31,146,0,0)
|
||||
#define OP_MTMSRD OPVCC(31,178,0,0)
|
||||
#define OP_MTSPR OPVCC(31,467,0,0)
|
||||
#define OP_MTSR OPVCC(31,210,0,0)
|
||||
#define OP_MTSRIN OPVCC(31,242,0,0)
|
||||
#define OP_MULLW OPVCC(31,235,0,0)
|
||||
#define OP_MULLD OPVCC(31,233,0,0)
|
||||
#define OP_OR OPVCC(31,444,0,0)
|
||||
#define OP_ORI OPVCC(24,0,0,0)
|
||||
#define OP_ORIS OPVCC(25,0,0,0)
|
||||
#define OP_RLWINM OPVCC(21,0,0,0)
|
||||
#define OP_SUBF OPVCC(31,40,0,0)
|
||||
#define OP_RLDIC OPVCC(30,4,0,0)
|
||||
#define OP_RLDICR OPVCC(30,2,0,0)
|
||||
#define OP_RLDICL OPVCC(30,0,0,0)
|
||||
uint32
|
||||
AOP_IRR(uint32 op, uint32 d, uint32 a, uint32 simm)
|
||||
{
|
||||
return op | (d&31)<<21 | (a&31)<<16 | (simm&0xFFFF);
|
||||
}
|
||||
|
||||
#define oclass(v) ((v).class-1)
|
||||
uint32
|
||||
LOP_RRR(uint32 op, uint32 a, uint32 s, uint32 b)
|
||||
{
|
||||
return op | (s&31)<<21 | (a&31)<<16 | (b&31)<<11;
|
||||
}
|
||||
|
||||
uint32
|
||||
LOP_IRR(uint32 op, uint32 a, uint32 s, uint32 uimm)
|
||||
{
|
||||
return op | (s&31)<<21 | (a&31)<<16 | (uimm&0xFFFF);
|
||||
}
|
||||
|
||||
uint32
|
||||
OP_BR(uint32 op, uint32 li, uint32 aa)
|
||||
{
|
||||
return op | li&0x03FFFFFC | aa<<1;
|
||||
}
|
||||
|
||||
uint32
|
||||
OP_BC(uint32 op, uint32 bo, uint32 bi, uint32 bd, uint32 aa)
|
||||
{
|
||||
return op | (bo&0x1F)<<21 | (bi&0x1F)<<16 | bd&0xFFFC | aa<<1;
|
||||
}
|
||||
|
||||
uint32
|
||||
OP_BCR(uint32 op, uint32 bo, uint32 bi)
|
||||
{
|
||||
return op | (bo&0x1F)<<21 | (bi&0x1F)<<16;
|
||||
}
|
||||
|
||||
uint32
|
||||
OP_RLW(uint32 op, uint32 a, uint32 s, uint32 sh, uint32 mb, uint32 me)
|
||||
{
|
||||
return op | (s&31)<<21 | (a&31)<<16 | (sh&31)<<11 | (mb&31)<<6 | (me&31)<<1;
|
||||
}
|
||||
|
||||
enum {
|
||||
/* each rhs is OPVCC(_, _, _, _) */
|
||||
OP_ADD = 31<<26 | 266<<1 | 0<<10 | 0,
|
||||
OP_ADDI = 14<<26 | 0<<1 | 0<<10 | 0,
|
||||
OP_ADDIS = 15<<26 | 0<<1 | 0<<10 | 0,
|
||||
OP_ANDI = 28<<26 | 0<<1 | 0<<10 | 0,
|
||||
OP_EXTSB = 31<<26 | 954<<1 | 0<<10 | 0,
|
||||
OP_EXTSH = 31<<26 | 922<<1 | 0<<10 | 0,
|
||||
OP_EXTSW = 31<<26 | 986<<1 | 0<<10 | 0,
|
||||
OP_MCRF = 19<<26 | 0<<1 | 0<<10 | 0,
|
||||
OP_MCRFS = 63<<26 | 64<<1 | 0<<10 | 0,
|
||||
OP_MCRXR = 31<<26 | 512<<1 | 0<<10 | 0,
|
||||
OP_MFCR = 31<<26 | 19<<1 | 0<<10 | 0,
|
||||
OP_MFFS = 63<<26 | 583<<1 | 0<<10 | 0,
|
||||
OP_MFMSR = 31<<26 | 83<<1 | 0<<10 | 0,
|
||||
OP_MFSPR = 31<<26 | 339<<1 | 0<<10 | 0,
|
||||
OP_MFSR = 31<<26 | 595<<1 | 0<<10 | 0,
|
||||
OP_MFSRIN = 31<<26 | 659<<1 | 0<<10 | 0,
|
||||
OP_MTCRF = 31<<26 | 144<<1 | 0<<10 | 0,
|
||||
OP_MTFSF = 63<<26 | 711<<1 | 0<<10 | 0,
|
||||
OP_MTFSFI = 63<<26 | 134<<1 | 0<<10 | 0,
|
||||
OP_MTMSR = 31<<26 | 146<<1 | 0<<10 | 0,
|
||||
OP_MTMSRD = 31<<26 | 178<<1 | 0<<10 | 0,
|
||||
OP_MTSPR = 31<<26 | 467<<1 | 0<<10 | 0,
|
||||
OP_MTSR = 31<<26 | 210<<1 | 0<<10 | 0,
|
||||
OP_MTSRIN = 31<<26 | 242<<1 | 0<<10 | 0,
|
||||
OP_MULLW = 31<<26 | 235<<1 | 0<<10 | 0,
|
||||
OP_MULLD = 31<<26 | 233<<1 | 0<<10 | 0,
|
||||
OP_OR = 31<<26 | 444<<1 | 0<<10 | 0,
|
||||
OP_ORI = 24<<26 | 0<<1 | 0<<10 | 0,
|
||||
OP_ORIS = 25<<26 | 0<<1 | 0<<10 | 0,
|
||||
OP_RLWINM = 21<<26 | 0<<1 | 0<<10 | 0,
|
||||
OP_SUBF = 31<<26 | 40<<1 | 0<<10 | 0,
|
||||
OP_RLDIC = 30<<26 | 4<<1 | 0<<10 | 0,
|
||||
OP_RLDICR = 30<<26 | 2<<1 | 0<<10 | 0,
|
||||
OP_RLDICL = 30<<26 | 0<<1 | 0<<10 | 0,
|
||||
};
|
||||
|
||||
int
|
||||
oclass(Addr *a)
|
||||
{
|
||||
return a->class - 1;
|
||||
}
|
||||
|
||||
// add R_ADDRPOWER relocation to symbol s for the two instructions o1 and o2.
|
||||
static void
|
||||
addaddrreloc(Link *ctxt, LSym *s, int *o1, int *o2)
|
||||
addaddrreloc(Link *ctxt, LSym *s, uint32 *o1, uint32 *o2)
|
||||
{
|
||||
Reloc *rel;
|
||||
|
||||
|
|
@ -1346,7 +1411,7 @@ getmask(uchar *m, uint32 v)
|
|||
int i;
|
||||
|
||||
m[0] = m[1] = 0;
|
||||
if(v != ~0U && v & (1<<31) && v & 1){ /* MB > ME */
|
||||
if(v != ~(uint32)0 && v & (1<<31) && v & 1){ /* MB > ME */
|
||||
if(getmask(m, ~v)){
|
||||
i = m[0]; m[0] = m[1]+1; m[1] = i-1;
|
||||
return 1;
|
||||
|
|
@ -1424,9 +1489,10 @@ high16adjusted(int32 d)
|
|||
}
|
||||
|
||||
static void
|
||||
asmout(Link *ctxt, Prog *p, Optab *o, int32 *out)
|
||||
asmout(Link *ctxt, Prog *p, Optab *o, uint32 *out)
|
||||
{
|
||||
int32 o1, o2, o3, o4, o5, v, t;
|
||||
uint32 o1, o2, o3, o4, o5;
|
||||
int32 v, t;
|
||||
vlong d;
|
||||
int r, a;
|
||||
uchar mask[2];
|
||||
|
|
@ -1694,7 +1760,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, int32 *out)
|
|||
r = p->reg;
|
||||
if(r == NREG)
|
||||
r = 0;
|
||||
switch(oclass(p->to)) {
|
||||
switch(oclass(&p->to)) {
|
||||
case C_CTR:
|
||||
o1 = OPVCC(19, 528, 0, 0);
|
||||
break;
|
||||
|
|
@ -1902,7 +1968,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, int32 *out)
|
|||
|
||||
case 33: /* fabs [frb,]frd; fmr. frb,frd */
|
||||
r = p->from.reg;
|
||||
if(oclass(p->from) == C_NONE)
|
||||
if(oclass(&p->from) == C_NONE)
|
||||
r = p->to.reg;
|
||||
o1 = AOP_RRR(oprrr(ctxt, p->as), p->to.reg, 0, r);
|
||||
break;
|
||||
|
|
@ -2034,7 +2100,7 @@ asmout(Link *ctxt, Prog *p, Optab *o, int32 *out)
|
|||
break;
|
||||
|
||||
case 54: /* mov msr,r1; mov r1, msr*/
|
||||
if(oclass(p->from) == C_REG){
|
||||
if(oclass(&p->from) == C_REG){
|
||||
if(p->as == AMOVD)
|
||||
o1 = AOP_RRR(OP_MTMSRD, p->from.reg, 0, 0);
|
||||
else
|
||||
|
|
|
|||
|
|
@ -83,18 +83,6 @@ Pconv(Fmt *fp)
|
|||
p = va_arg(fp->args, Prog*);
|
||||
bigP = p;
|
||||
|
||||
if(fp->flags & FmtSharp) {
|
||||
char *s = str;
|
||||
s += sprint(s, "%.5lld (%L) %A", p->pc, p->lineno, p->as);
|
||||
if(p->from.type != D_NONE)
|
||||
s += sprint(s, " from={%#D}", &p->from);
|
||||
if(p->reg)
|
||||
s += sprint(s, " reg=%d", p->reg);
|
||||
if(p->to.type != D_NONE)
|
||||
sprint(s, " to={%#D}", &p->to);
|
||||
return fmtstrcpy(fp, str);
|
||||
}
|
||||
|
||||
switch(p->as) {
|
||||
case ADATA:
|
||||
sprint(str, "%.5lld (%L) %A %D/%d,%D",
|
||||
|
|
@ -139,29 +127,6 @@ Dconv(Fmt *fp)
|
|||
a = va_arg(fp->args, Addr*);
|
||||
i = a->type;
|
||||
|
||||
if(fp->flags & FmtSharp) {
|
||||
char *s = str;
|
||||
s += sprint(s, "type=");
|
||||
if(i == D_NONE) {
|
||||
sprint(s, "NONE");
|
||||
goto brk;
|
||||
}
|
||||
if(i >= D_INDIR) {
|
||||
i -= D_INDIR;
|
||||
s += sprint(s, "INDIR+");
|
||||
}
|
||||
if(i >= 0 && i < D_LAST && dnames6[i] != nil)
|
||||
s += sprint(s, "%s ", dnames6[i]);
|
||||
else
|
||||
s += sprint(s, "%d ", i);
|
||||
s += sprint(s, "offset=%lld etype=%E width=%lld", a->offset, a->etype, a->width);
|
||||
if(a->sym != nil)
|
||||
s += sprint(s, " sym=%s", a->sym->name);
|
||||
if(a->type == D_BRANCH && a->u.branch != nil)
|
||||
sprint(s, " branch=%.5lld", a->u.branch->pc);
|
||||
goto brk;
|
||||
}
|
||||
|
||||
if(fp->flags & FmtLong) {
|
||||
if(i == D_CONST)
|
||||
sprint(str, "$%lld-%lld", a->offset&0xffffffffLL, a->offset>>32);
|
||||
|
|
|
|||
|
|
@ -84,28 +84,14 @@ static Prog* bigP;
|
|||
static int
|
||||
Pconv(Fmt *fp)
|
||||
{
|
||||
char str[STRINGSZ], *s;
|
||||
char str[STRINGSZ];
|
||||
Prog *p;
|
||||
int a;
|
||||
int a, ch;
|
||||
|
||||
p = va_arg(fp->args, Prog*);
|
||||
bigP = p;
|
||||
a = p->as;
|
||||
|
||||
if(fp->flags & FmtSharp) {
|
||||
s = str;
|
||||
s += sprint(s, "%.5lld (%L) %A", p->pc, p->lineno, a);
|
||||
if(p->from.type != D_NONE)
|
||||
s += sprint(s, " from={%#D}", &p->from);
|
||||
if(p->reg)
|
||||
s += sprint(s, " reg=%d", p->reg);
|
||||
if(p->from3.type != D_NONE)
|
||||
s += sprint(s, " from3={%#D}", &p->from3);
|
||||
if(p->to.type != D_NONE)
|
||||
sprint(s, " to={%#D}", &p->to);
|
||||
return fmtstrcpy(fp, str);
|
||||
}
|
||||
|
||||
if(a == ADATA || a == AINIT || a == ADYNT)
|
||||
sprint(str, "%.5lld (%L) %A %D/%d,%D", p->pc, p->lineno, a, &p->from, p->reg, &p->to);
|
||||
else if(a == ATEXT) {
|
||||
|
|
@ -119,26 +105,29 @@ Pconv(Fmt *fp)
|
|||
else
|
||||
sprint(str, "%.5lld (%L) %A %D,%D", p->pc, p->lineno, a, &p->from, &p->to);
|
||||
} else {
|
||||
s = str;
|
||||
if(p->mark & NOSCHED)
|
||||
s += sprint(s, "*");
|
||||
sprint(strchr(str, 0), "*");
|
||||
if(p->reg == NREG && p->from3.type == D_NONE)
|
||||
sprint(s, "%.5lld (%L) %A %D,%D", p->pc, p->lineno, a, &p->from, &p->to);
|
||||
sprint(strchr(str, 0), "%.5lld (%L) %A %D,%D", p->pc, p->lineno, a, &p->from, &p->to);
|
||||
else
|
||||
if(a != ATEXT && p->from.type == D_OREG) {
|
||||
sprint(s, "%.5lld (%L) %A %lld(R%d+R%d),%D", p->pc, p->lineno, a,
|
||||
sprint(strchr(str, 0), "%.5lld (%L) %A %lld(R%d+R%d),%D", p->pc, p->lineno, a,
|
||||
p->from.offset, p->from.reg, p->reg, &p->to);
|
||||
} else
|
||||
if(p->to.type == D_OREG) {
|
||||
sprint(s, "%.5lld (%L) %A %D,%lld(R%d+R%d)", p->pc, p->lineno, a,
|
||||
sprint(strchr(str, 0), "%.5lld (%L) %A %D,%lld(R%d+R%d)", p->pc, p->lineno, a,
|
||||
&p->from, p->to.offset, p->to.reg, p->reg);
|
||||
} else {
|
||||
s += sprint(s, "%.5lld (%L) %A %D", p->pc, p->lineno, a, &p->from);
|
||||
if(p->reg != NREG)
|
||||
s += sprint(s, ",%c%d", p->from.type==D_FREG?'F':'R', p->reg);
|
||||
sprint(strchr(str, 0), "%.5lld (%L) %A %D", p->pc, p->lineno, a, &p->from);
|
||||
if(p->reg != NREG) {
|
||||
ch = 'R';
|
||||
if(p->from.type == D_FREG)
|
||||
ch = 'F';
|
||||
sprint(strchr(str, 0), ",%c%d", ch, p->reg);
|
||||
}
|
||||
if(p->from3.type != D_NONE)
|
||||
s += sprint(s, ",%D", &p->from3);
|
||||
sprint(s, ",%D", &p->to);
|
||||
sprint(strchr(str, 0), ",%D", &p->from3);
|
||||
sprint(strchr(str, 0), ",%D", &p->to);
|
||||
}
|
||||
if(p->spadj != 0)
|
||||
return fmtprint(fp, "%s # spadj=%d", str, p->spadj);
|
||||
|
|
@ -168,32 +157,6 @@ Dconv(Fmt *fp)
|
|||
|
||||
a = va_arg(fp->args, Addr*);
|
||||
|
||||
if(fp->flags & FmtSharp) {
|
||||
char *s = str;
|
||||
if(a->type == D_NONE) {
|
||||
sprint(s, "type=NONE");
|
||||
goto ret;
|
||||
}
|
||||
if(a->type >= 0 && a->type < D_LAST && dnames9[a->type] != nil)
|
||||
s += sprint(s, "type=%s ", dnames9[a->type]);
|
||||
else
|
||||
s += sprint(s, "type=%d ", a->type);
|
||||
if(a->name >= 0 && a->name < D_LAST && dnames9[(int)a->name] != nil)
|
||||
s += sprint(s, "name=%s ", dnames9[(int)a->name]);
|
||||
else
|
||||
s += sprint(s, "name=%d ", a->name);
|
||||
s += sprint(s, "offset=%lld etype=%E width=%lld", a->offset, a->etype, a->width);
|
||||
if(a->class != 0)
|
||||
s += sprint(s, " class=%s", cnames9[(int)a->class]);
|
||||
if(a->reg != NREG)
|
||||
s += sprint(s, " reg=%d", a->reg);
|
||||
if(a->sym != nil)
|
||||
s += sprint(s, " sym=%s", a->sym->name);
|
||||
if(a->type == D_BRANCH && a->u.branch != nil)
|
||||
sprint(s, " branch=%.5lld", a->u.branch->pc);
|
||||
goto ret;
|
||||
}
|
||||
|
||||
if(fp->flags & FmtLong) {
|
||||
if(a->type == D_CONST)
|
||||
sprint(str, "$%d-%d", (int32)a->offset, (int32)(a->offset>>32));
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
#include "../cmd/5l/5.out.h"
|
||||
#include "../runtime/stack.h"
|
||||
|
||||
static Prog zprg = {
|
||||
static Prog zprg5 = {
|
||||
.as = AGOK,
|
||||
.scond = C_SCOND_NONE,
|
||||
.reg = NREG,
|
||||
|
|
@ -156,11 +156,11 @@ progedit(Link *ctxt, Prog *p)
|
|||
case AMOVF:
|
||||
if(p->from.type == D_FCONST && chipfloat5(ctxt, p->from.u.dval) < 0 &&
|
||||
(chipzero5(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
|
||||
int32 i32;
|
||||
uint32 i32;
|
||||
float32 f32;
|
||||
f32 = p->from.u.dval;
|
||||
memmove(&i32, &f32, 4);
|
||||
sprint(literal, "$f32.%08ux", (uint32)i32);
|
||||
sprint(literal, "$f32.%08ux", i32);
|
||||
s = linklookup(ctxt, literal, 0);
|
||||
if(s->type == 0) {
|
||||
s->type = SRODATA;
|
||||
|
|
@ -177,9 +177,9 @@ progedit(Link *ctxt, Prog *p)
|
|||
case AMOVD:
|
||||
if(p->from.type == D_FCONST && chipfloat5(ctxt, p->from.u.dval) < 0 &&
|
||||
(chipzero5(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
|
||||
int64 i64;
|
||||
uint64 i64;
|
||||
memmove(&i64, &p->from.u.dval, 8);
|
||||
sprint(literal, "$f64.%016llux", (uvlong)i64);
|
||||
sprint(literal, "$f64.%016llux", i64);
|
||||
s = linklookup(ctxt, literal, 0);
|
||||
if(s->type == 0) {
|
||||
s->type = SRODATA;
|
||||
|
|
@ -216,7 +216,7 @@ prg(void)
|
|||
Prog *p;
|
||||
|
||||
p = emallocz(sizeof(*p));
|
||||
*p = zprg;
|
||||
*p = zprg5;
|
||||
return p;
|
||||
}
|
||||
|
||||
|
|
@ -247,7 +247,7 @@ linkcase(Prog *casep)
|
|||
}
|
||||
|
||||
static void
|
||||
nocache(Prog *p)
|
||||
nocache5(Prog *p)
|
||||
{
|
||||
p->optab = 0;
|
||||
p->from.class = 0;
|
||||
|
|
@ -540,11 +540,11 @@ addstacksplit(Link *ctxt, LSym *cursym)
|
|||
break;
|
||||
|
||||
case ARET:
|
||||
nocache(p);
|
||||
nocache5(p);
|
||||
if(cursym->text->mark & LEAF) {
|
||||
if(!autosize) {
|
||||
p->as = AB;
|
||||
p->from = zprg.from;
|
||||
p->from = zprg5.from;
|
||||
if(p->to.sym) { // retjmp
|
||||
p->to.type = D_BRANCH;
|
||||
} else {
|
||||
|
|
@ -758,7 +758,7 @@ softfloat(Link *ctxt, LSym *cursym)
|
|||
*next = *p;
|
||||
|
||||
// BL _sfloat(SB)
|
||||
*p = zprg;
|
||||
*p = zprg5;
|
||||
p->link = next;
|
||||
p->as = ABL;
|
||||
p->to.type = D_BRANCH;
|
||||
|
|
|
|||
|
|
@ -241,6 +241,19 @@ progedit(Link *ctxt, Prog *p)
|
|||
|
||||
// Rewrite float constants to values stored in memory.
|
||||
switch(p->as) {
|
||||
case AMOVSS:
|
||||
// Convert AMOVSS $(0), Xx to AXORPS Xx, Xx
|
||||
if(p->from.type == D_FCONST)
|
||||
if(p->from.u.dval == 0)
|
||||
if(p->to.type >= D_X0)
|
||||
if(p->to.type <= D_X15) {
|
||||
p->as = AXORPS;
|
||||
p->from.type = p->to.type;
|
||||
p->from.index = p->to.index;
|
||||
break;
|
||||
}
|
||||
// fallthrough
|
||||
|
||||
case AFMOVF:
|
||||
case AFADDF:
|
||||
case AFSUBF:
|
||||
|
|
@ -250,7 +263,6 @@ progedit(Link *ctxt, Prog *p)
|
|||
case AFDIVRF:
|
||||
case AFCOMF:
|
||||
case AFCOMFP:
|
||||
case AMOVSS:
|
||||
case AADDSS:
|
||||
case ASUBSS:
|
||||
case AMULSS:
|
||||
|
|
@ -258,11 +270,11 @@ progedit(Link *ctxt, Prog *p)
|
|||
case ACOMISS:
|
||||
case AUCOMISS:
|
||||
if(p->from.type == D_FCONST) {
|
||||
int32 i32;
|
||||
uint32 i32;
|
||||
float32 f32;
|
||||
f32 = p->from.u.dval;
|
||||
memmove(&i32, &f32, 4);
|
||||
sprint(literal, "$f32.%08ux", (uint32)i32);
|
||||
sprint(literal, "$f32.%08ux", i32);
|
||||
s = linklookup(ctxt, literal, 0);
|
||||
if(s->type == 0) {
|
||||
s->type = SRODATA;
|
||||
|
|
@ -275,6 +287,19 @@ progedit(Link *ctxt, Prog *p)
|
|||
}
|
||||
break;
|
||||
|
||||
case AMOVSD:
|
||||
// Convert AMOVSD $(0), Xx to AXORPS Xx, Xx
|
||||
if(p->from.type == D_FCONST)
|
||||
if(p->from.u.dval == 0)
|
||||
if(p->to.type >= D_X0)
|
||||
if(p->to.type <= D_X15) {
|
||||
p->as = AXORPS;
|
||||
p->from.type = p->to.type;
|
||||
p->from.index = p->to.index;
|
||||
break;
|
||||
}
|
||||
// fallthrough
|
||||
|
||||
case AFMOVD:
|
||||
case AFADDD:
|
||||
case AFSUBD:
|
||||
|
|
@ -284,7 +309,6 @@ progedit(Link *ctxt, Prog *p)
|
|||
case AFDIVRD:
|
||||
case AFCOMD:
|
||||
case AFCOMDP:
|
||||
case AMOVSD:
|
||||
case AADDSD:
|
||||
case ASUBSD:
|
||||
case AMULSD:
|
||||
|
|
@ -292,9 +316,9 @@ progedit(Link *ctxt, Prog *p)
|
|||
case ACOMISD:
|
||||
case AUCOMISD:
|
||||
if(p->from.type == D_FCONST) {
|
||||
int64 i64;
|
||||
uint64 i64;
|
||||
memmove(&i64, &p->from.u.dval, 8);
|
||||
sprint(literal, "$f64.%016llux", (uvlong)i64);
|
||||
sprint(literal, "$f64.%016llux", i64);
|
||||
s = linklookup(ctxt, literal, 0);
|
||||
if(s->type == 0) {
|
||||
s->type = SRODATA;
|
||||
|
|
|
|||
|
|
@ -177,6 +177,19 @@ progedit(Link *ctxt, Prog *p)
|
|||
|
||||
// Rewrite float constants to values stored in memory.
|
||||
switch(p->as) {
|
||||
case AMOVSS:
|
||||
// Convert AMOVSS $(0), Xx to AXORPS Xx, Xx
|
||||
if(p->from.type == D_FCONST)
|
||||
if(p->from.u.dval == 0)
|
||||
if(p->to.type >= D_X0)
|
||||
if(p->to.type <= D_X7) {
|
||||
p->as = AXORPS;
|
||||
p->from.type = p->to.type;
|
||||
p->from.index = p->to.index;
|
||||
break;
|
||||
}
|
||||
// fallthrough
|
||||
|
||||
case AFMOVF:
|
||||
case AFADDF:
|
||||
case AFSUBF:
|
||||
|
|
@ -186,7 +199,6 @@ progedit(Link *ctxt, Prog *p)
|
|||
case AFDIVRF:
|
||||
case AFCOMF:
|
||||
case AFCOMFP:
|
||||
case AMOVSS:
|
||||
case AADDSS:
|
||||
case ASUBSS:
|
||||
case AMULSS:
|
||||
|
|
@ -194,11 +206,11 @@ progedit(Link *ctxt, Prog *p)
|
|||
case ACOMISS:
|
||||
case AUCOMISS:
|
||||
if(p->from.type == D_FCONST) {
|
||||
int32 i32;
|
||||
uint32 i32;
|
||||
float32 f32;
|
||||
f32 = p->from.u.dval;
|
||||
memmove(&i32, &f32, 4);
|
||||
sprint(literal, "$f32.%08ux", (uint32)i32);
|
||||
sprint(literal, "$f32.%08ux", i32);
|
||||
s = linklookup(ctxt, literal, 0);
|
||||
if(s->type == 0) {
|
||||
s->type = SRODATA;
|
||||
|
|
@ -211,6 +223,19 @@ progedit(Link *ctxt, Prog *p)
|
|||
}
|
||||
break;
|
||||
|
||||
case AMOVSD:
|
||||
// Convert AMOVSD $(0), Xx to AXORPS Xx, Xx
|
||||
if(p->from.type == D_FCONST)
|
||||
if(p->from.u.dval == 0)
|
||||
if(p->to.type >= D_X0)
|
||||
if(p->to.type <= D_X7) {
|
||||
p->as = AXORPS;
|
||||
p->from.type = p->to.type;
|
||||
p->from.index = p->to.index;
|
||||
break;
|
||||
}
|
||||
// fallthrough
|
||||
|
||||
case AFMOVD:
|
||||
case AFADDD:
|
||||
case AFSUBD:
|
||||
|
|
@ -220,7 +245,6 @@ progedit(Link *ctxt, Prog *p)
|
|||
case AFDIVRD:
|
||||
case AFCOMD:
|
||||
case AFCOMDP:
|
||||
case AMOVSD:
|
||||
case AADDSD:
|
||||
case ASUBSD:
|
||||
case AMULSD:
|
||||
|
|
@ -228,9 +252,9 @@ progedit(Link *ctxt, Prog *p)
|
|||
case ACOMISD:
|
||||
case AUCOMISD:
|
||||
if(p->from.type == D_FCONST) {
|
||||
int64 i64;
|
||||
uint64 i64;
|
||||
memmove(&i64, &p->from.u.dval, 8);
|
||||
sprint(literal, "$f64.%016llux", (uvlong)i64);
|
||||
sprint(literal, "$f64.%016llux", i64);
|
||||
s = linklookup(ctxt, literal, 0);
|
||||
if(s->type == 0) {
|
||||
s->type = SRODATA;
|
||||
|
|
|
|||
|
|
@ -118,11 +118,11 @@ progedit(Link *ctxt, Prog *p)
|
|||
switch(p->as) {
|
||||
case AFMOVS:
|
||||
if(p->from.type == D_FCONST) {
|
||||
int32 i32;
|
||||
uint32 i32;
|
||||
float32 f32;
|
||||
f32 = p->from.u.dval;
|
||||
memmove(&i32, &f32, 4);
|
||||
sprint(literal, "$f32.%08ux", (uint32)i32);
|
||||
sprint(literal, "$f32.%08ux", i32);
|
||||
s = linklookup(ctxt, literal, 0);
|
||||
s->size = 4;
|
||||
p->from.type = D_OREG;
|
||||
|
|
@ -133,9 +133,9 @@ progedit(Link *ctxt, Prog *p)
|
|||
break;
|
||||
case AFMOVD:
|
||||
if(p->from.type == D_FCONST) {
|
||||
int64 i64;
|
||||
uint64 i64;
|
||||
memmove(&i64, &p->from.u.dval, 8);
|
||||
sprint(literal, "$f64.%016llux", (uvlong)i64);
|
||||
sprint(literal, "$f64.%016llux", i64);
|
||||
s = linklookup(ctxt, literal, 0);
|
||||
s->size = 8;
|
||||
p->from.type = D_OREG;
|
||||
|
|
@ -414,7 +414,7 @@ addstacksplit(Link *ctxt, LSym *cursym)
|
|||
else
|
||||
if(autosize & 4)
|
||||
autosize += 4;
|
||||
p->to.offset = (p->to.offset & (0xffffffffull<<32)) | (uint32)(autosize-8);
|
||||
p->to.offset = ((uint64)p->to.offset & (0xffffffffull<<32)) | (uint32)(autosize-8);
|
||||
|
||||
if(!(p->reg & NOSPLIT))
|
||||
p = stacksplit(ctxt, p, autosize, !(cursym->text->reg&NEEDCTXT)); // emit split check
|
||||
|
|
@ -668,14 +668,15 @@ addstacksplit(Link *ctxt, LSym *cursym)
|
|||
}
|
||||
}
|
||||
|
||||
#if 0 // instruction scheduling
|
||||
/*
|
||||
// instruction scheduling
|
||||
if(debug['Q'] == 0)
|
||||
return;
|
||||
|
||||
curtext = nil;
|
||||
q = nil; /* p - 1 */
|
||||
q1 = firstp; /* top of block */
|
||||
o = 0; /* count of instructions */
|
||||
q = nil; // p - 1
|
||||
q1 = firstp; // top of block
|
||||
o = 0; // count of instructions
|
||||
for(p = firstp; p != nil; p = p1) {
|
||||
p1 = p->link;
|
||||
o++;
|
||||
|
|
@ -711,7 +712,7 @@ addstacksplit(Link *ctxt, LSym *cursym)
|
|||
}
|
||||
q = p;
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
}
|
||||
|
||||
static Prog*
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ void
|
|||
linkpatch(Link *ctxt, LSym *sym)
|
||||
{
|
||||
int32 c;
|
||||
char *name;
|
||||
Prog *p, *q;
|
||||
|
||||
ctxt->cursym = sym;
|
||||
|
|
@ -95,8 +96,10 @@ linkpatch(Link *ctxt, LSym *sym)
|
|||
q = q->link;
|
||||
}
|
||||
if(q == nil) {
|
||||
ctxt->diag("branch out of range (%#ux)\n%P [%s]",
|
||||
c, p, p->to.sym ? p->to.sym->name : "<nil>");
|
||||
name = "<nil>";
|
||||
if(p->to.sym)
|
||||
name = p->to.sym->name;
|
||||
ctxt->diag("branch out of range (%#ux)\n%P [%s]", c, p, name);
|
||||
p->to.type = ctxt->arch->D_NONE;
|
||||
}
|
||||
p->to.u.branch = q;
|
||||
|
|
|
|||
|
|
@ -1,835 +0,0 @@
|
|||
// cmd/9l/sched.c from Vita Nuova.
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// +build ignore
|
||||
|
||||
#include "l.h"
|
||||
|
||||
enum
|
||||
{
|
||||
E_ICC = 1<<0,
|
||||
E_FCC = 1<<1,
|
||||
E_MEM = 1<<2,
|
||||
E_MEMSP = 1<<3, /* uses offset and size */
|
||||
E_MEMSB = 1<<4, /* uses offset and size */
|
||||
E_LR = 1<<5,
|
||||
E_CR = 1<<6,
|
||||
E_CTR = 1<<7,
|
||||
E_XER = 1<<8,
|
||||
|
||||
E_CR0 = 0xF<<0,
|
||||
E_CR1 = 0xF<<4,
|
||||
|
||||
ANYMEM = E_MEM|E_MEMSP|E_MEMSB,
|
||||
ALL = ~0,
|
||||
};
|
||||
|
||||
typedef struct Sch Sch;
|
||||
typedef struct Dep Dep;
|
||||
|
||||
struct Dep
|
||||
{
|
||||
ulong ireg;
|
||||
ulong freg;
|
||||
ulong cc;
|
||||
ulong cr;
|
||||
};
|
||||
struct Sch
|
||||
{
|
||||
Prog p;
|
||||
Dep set;
|
||||
Dep used;
|
||||
long soffset;
|
||||
char size;
|
||||
char comp;
|
||||
};
|
||||
|
||||
void regused(Sch*, Prog*);
|
||||
int depend(Sch*, Sch*);
|
||||
int conflict(Sch*, Sch*);
|
||||
int offoverlap(Sch*, Sch*);
|
||||
void dumpbits(Sch*, Dep*);
|
||||
|
||||
void
|
||||
sched(Prog *p0, Prog *pe)
|
||||
{
|
||||
Prog *p, *q;
|
||||
Sch sch[NSCHED], *s, *t, *u, *se, stmp;
|
||||
|
||||
if(!debug['Q'])
|
||||
return;
|
||||
/*
|
||||
* build side structure
|
||||
*/
|
||||
s = sch;
|
||||
for(p=p0;; p=p->link) {
|
||||
memset(s, 0, sizeof(*s));
|
||||
s->p = *p;
|
||||
regused(s, p);
|
||||
if(debug['X']) {
|
||||
Bprint(&bso, "%P\tset", &s->p);
|
||||
dumpbits(s, &s->set);
|
||||
Bprint(&bso, "; used");
|
||||
dumpbits(s, &s->used);
|
||||
if(s->comp)
|
||||
Bprint(&bso, "; compound");
|
||||
if(s->p.mark & LOAD)
|
||||
Bprint(&bso, "; load");
|
||||
if(s->p.mark & BRANCH)
|
||||
Bprint(&bso, "; branch");
|
||||
if(s->p.mark & FCMP)
|
||||
Bprint(&bso, "; fcmp");
|
||||
Bprint(&bso, "\n");
|
||||
}
|
||||
s++;
|
||||
if(p == pe)
|
||||
break;
|
||||
}
|
||||
se = s;
|
||||
|
||||
for(s=se-1; s>=sch; s--) {
|
||||
|
||||
/*
|
||||
* load delay. interlocked.
|
||||
*/
|
||||
if(s->p.mark & LOAD) {
|
||||
if(s >= se-1)
|
||||
continue;
|
||||
if(!conflict(s, (s+1)))
|
||||
continue;
|
||||
/*
|
||||
* s is load, s+1 is immediate use of result
|
||||
* t is the trial instruction to insert between s and s+1
|
||||
*/
|
||||
for(t=s-1; t>=sch; t--) {
|
||||
if(t->p.mark & BRANCH)
|
||||
goto no2;
|
||||
if(t->p.mark & FCMP)
|
||||
if((s+1)->p.mark & BRANCH)
|
||||
goto no2;
|
||||
if(t->p.mark & LOAD)
|
||||
if(conflict(t, (s+1)))
|
||||
goto no2;
|
||||
for(u=t+1; u<=s; u++)
|
||||
if(depend(u, t))
|
||||
goto no2;
|
||||
goto out2;
|
||||
no2:;
|
||||
}
|
||||
if(debug['X'])
|
||||
Bprint(&bso, "?l%P\n", &s->p);
|
||||
continue;
|
||||
out2:
|
||||
if(debug['X']) {
|
||||
Bprint(&bso, "!l%P\n", &t->p);
|
||||
Bprint(&bso, "%P\n", &s->p);
|
||||
}
|
||||
stmp = *t;
|
||||
memmove(t, t+1, (uchar*)s - (uchar*)t);
|
||||
*s = stmp;
|
||||
s--;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* fop2 delay.
|
||||
*/
|
||||
if(s->p.mark & FCMP) {
|
||||
if(s >= se-1)
|
||||
continue;
|
||||
if(!((s+1)->p.mark & BRANCH))
|
||||
continue;
|
||||
/* t is the trial instruction to use */
|
||||
for(t=s-1; t>=sch; t--) {
|
||||
for(u=t+1; u<=s; u++)
|
||||
if(depend(u, t))
|
||||
goto no3;
|
||||
goto out3;
|
||||
no3:;
|
||||
}
|
||||
if(debug['X'])
|
||||
Bprint(&bso, "?f%P\n", &s->p);
|
||||
continue;
|
||||
out3:
|
||||
if(debug['X']) {
|
||||
Bprint(&bso, "!f%P\n", &t->p);
|
||||
Bprint(&bso, "%P\n", &s->p);
|
||||
}
|
||||
stmp = *t;
|
||||
memmove(t, t+1, (uchar*)s - (uchar*)t);
|
||||
*s = stmp;
|
||||
s--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* put it all back
|
||||
*/
|
||||
for(s=sch, p=p0; s<se; s++, p=q) {
|
||||
q = p->link;
|
||||
if(q != s->p.link) {
|
||||
*p = s->p;
|
||||
p->link = q;
|
||||
}
|
||||
}
|
||||
if(debug['X'])
|
||||
Bprint(&bso, "\n");
|
||||
}
|
||||
|
||||
void
|
||||
regused(Sch *s, Prog *realp)
|
||||
{
|
||||
int c, ar, ad, ld, sz, nr, upd;
|
||||
ulong m;
|
||||
Prog *p;
|
||||
|
||||
p = &s->p;
|
||||
s->comp = compound(p);
|
||||
if(s->comp) {
|
||||
s->set.ireg |= 1<<REGTMP;
|
||||
s->used.ireg |= 1<<REGTMP;
|
||||
}
|
||||
ar = 0; /* dest is really reference */
|
||||
ad = 0; /* source/dest is really address */
|
||||
ld = 0; /* opcode is load instruction */
|
||||
sz = 32*4; /* size of load/store for overlap computation */
|
||||
nr = 0; /* source/dest is not really reg */
|
||||
upd = 0; /* move with update; changes reg */
|
||||
|
||||
/*
|
||||
* flags based on opcode
|
||||
*/
|
||||
switch(p->as) {
|
||||
case ATEXT:
|
||||
curtext = realp;
|
||||
autosize = p->to.offset + 8;
|
||||
ad = 1;
|
||||
break;
|
||||
case ABL:
|
||||
s->set.cc |= E_LR;
|
||||
ar = 1;
|
||||
ad = 1;
|
||||
break;
|
||||
case ABR:
|
||||
ar = 1;
|
||||
ad = 1;
|
||||
break;
|
||||
case ACMP:
|
||||
case ACMPU:
|
||||
case ACMPW:
|
||||
case ACMPWU:
|
||||
s->set.cc |= E_ICC;
|
||||
if(p->reg == 0)
|
||||
s->set.cr |= E_CR0;
|
||||
else
|
||||
s->set.cr |= (0xF<<((p->reg&7)*4));
|
||||
ar = 1;
|
||||
break;
|
||||
case AFCMPO:
|
||||
case AFCMPU:
|
||||
s->set.cc |= E_FCC;
|
||||
if(p->reg == 0)
|
||||
s->set.cr |= E_CR0;
|
||||
else
|
||||
s->set.cr |= (0xF<<((p->reg&7)*4));
|
||||
ar = 1;
|
||||
break;
|
||||
case ACRAND:
|
||||
case ACRANDN:
|
||||
case ACREQV:
|
||||
case ACRNAND:
|
||||
case ACRNOR:
|
||||
case ACROR:
|
||||
case ACRORN:
|
||||
case ACRXOR:
|
||||
s->used.cr |= 1<<p->from.reg;
|
||||
s->set.cr |= 1<<p->to.reg;
|
||||
nr = 1;
|
||||
break;
|
||||
case ABCL: /* tricky */
|
||||
s->used.cc |= E_FCC|E_ICC;
|
||||
s->used.cr = ALL;
|
||||
s->set.cc |= E_LR;
|
||||
ar = 1;
|
||||
break;
|
||||
case ABC: /* tricky */
|
||||
s->used.cc |= E_FCC|E_ICC;
|
||||
s->used.cr = ALL;
|
||||
ar = 1;
|
||||
break;
|
||||
case ABEQ:
|
||||
case ABGE:
|
||||
case ABGT:
|
||||
case ABLE:
|
||||
case ABLT:
|
||||
case ABNE:
|
||||
case ABVC:
|
||||
case ABVS:
|
||||
s->used.cc |= E_ICC;
|
||||
s->used.cr |= E_CR0;
|
||||
ar = 1;
|
||||
break;
|
||||
case ALSW:
|
||||
case AMOVMW:
|
||||
/* could do better */
|
||||
sz = 32*4;
|
||||
ld = 1;
|
||||
break;
|
||||
case AMOVBU:
|
||||
case AMOVBZU:
|
||||
upd = 1;
|
||||
sz = 1;
|
||||
ld = 1;
|
||||
break;
|
||||
case AMOVB:
|
||||
case AMOVBZ:
|
||||
sz = 1;
|
||||
ld = 1;
|
||||
break;
|
||||
case AMOVHU:
|
||||
case AMOVHZU:
|
||||
upd = 1;
|
||||
sz = 2;
|
||||
ld = 1;
|
||||
break;
|
||||
case AMOVH:
|
||||
case AMOVHBR:
|
||||
case AMOVHZ:
|
||||
sz = 2;
|
||||
ld = 1;
|
||||
break;
|
||||
case AFMOVSU:
|
||||
case AMOVWU:
|
||||
case AMOVWZU:
|
||||
upd = 1;
|
||||
sz = 4;
|
||||
ld = 1;
|
||||
break;
|
||||
case AFMOVS:
|
||||
case AMOVW:
|
||||
case AMOVWZ:
|
||||
case AMOVWBR:
|
||||
case ALWAR:
|
||||
sz = 4;
|
||||
ld = 1;
|
||||
break;
|
||||
case AFMOVDU:
|
||||
upd = 1;
|
||||
sz = 8;
|
||||
ld = 1;
|
||||
break;
|
||||
case AFMOVD:
|
||||
sz = 8;
|
||||
ld = 1;
|
||||
break;
|
||||
case AFMOVDCC:
|
||||
sz = 8;
|
||||
ld = 1;
|
||||
s->set.cc |= E_FCC;
|
||||
s->set.cr |= E_CR1;
|
||||
break;
|
||||
case AMOVFL:
|
||||
case AMOVCRFS:
|
||||
case AMTFSB0:
|
||||
case AMTFSB0CC:
|
||||
case AMTFSB1:
|
||||
case AMTFSB1CC:
|
||||
s->set.ireg = ALL;
|
||||
s->set.freg = ALL;
|
||||
s->set.cc = ALL;
|
||||
s->set.cr = ALL;
|
||||
break;
|
||||
case AADDCC:
|
||||
case AADDVCC:
|
||||
case AADDCCC:
|
||||
case AADDCVCC:
|
||||
case AADDMECC:
|
||||
case AADDMEVCC:
|
||||
case AADDECC:
|
||||
case AADDEVCC:
|
||||
case AADDZECC:
|
||||
case AADDZEVCC:
|
||||
case AANDCC:
|
||||
case AANDNCC:
|
||||
case ACNTLZWCC:
|
||||
case ADIVWCC:
|
||||
case ADIVWVCC:
|
||||
case ADIVWUCC:
|
||||
case ADIVWUVCC:
|
||||
case AEQVCC:
|
||||
case AEXTSBCC:
|
||||
case AEXTSHCC:
|
||||
case AMULHWCC:
|
||||
case AMULHWUCC:
|
||||
case AMULLWCC:
|
||||
case AMULLWVCC:
|
||||
case ANANDCC:
|
||||
case ANEGCC:
|
||||
case ANEGVCC:
|
||||
case ANORCC:
|
||||
case AORCC:
|
||||
case AORNCC:
|
||||
case AREMCC:
|
||||
case AREMVCC:
|
||||
case AREMUCC:
|
||||
case AREMUVCC:
|
||||
case ARLWMICC:
|
||||
case ARLWNMCC:
|
||||
case ASLWCC:
|
||||
case ASRAWCC:
|
||||
case ASRWCC:
|
||||
case ASTWCCC:
|
||||
case ASUBCC:
|
||||
case ASUBVCC:
|
||||
case ASUBCCC:
|
||||
case ASUBCVCC:
|
||||
case ASUBMECC:
|
||||
case ASUBMEVCC:
|
||||
case ASUBECC:
|
||||
case ASUBEVCC:
|
||||
case ASUBZECC:
|
||||
case ASUBZEVCC:
|
||||
case AXORCC:
|
||||
s->set.cc |= E_ICC;
|
||||
s->set.cr |= E_CR0;
|
||||
break;
|
||||
case AFABSCC:
|
||||
case AFADDCC:
|
||||
case AFADDSCC:
|
||||
case AFCTIWCC:
|
||||
case AFCTIWZCC:
|
||||
case AFDIVCC:
|
||||
case AFDIVSCC:
|
||||
case AFMADDCC:
|
||||
case AFMADDSCC:
|
||||
case AFMSUBCC:
|
||||
case AFMSUBSCC:
|
||||
case AFMULCC:
|
||||
case AFMULSCC:
|
||||
case AFNABSCC:
|
||||
case AFNEGCC:
|
||||
case AFNMADDCC:
|
||||
case AFNMADDSCC:
|
||||
case AFNMSUBCC:
|
||||
case AFNMSUBSCC:
|
||||
case AFRSPCC:
|
||||
case AFSUBCC:
|
||||
case AFSUBSCC:
|
||||
s->set.cc |= E_FCC;
|
||||
s->set.cr |= E_CR1;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* flags based on 'to' field
|
||||
*/
|
||||
c = p->to.class;
|
||||
if(c == 0) {
|
||||
c = aclass(&p->to) + 1;
|
||||
p->to.class = c;
|
||||
}
|
||||
c--;
|
||||
switch(c) {
|
||||
default:
|
||||
print("unknown class %d %D\n", c, &p->to);
|
||||
|
||||
case C_NONE:
|
||||
case C_ZCON:
|
||||
case C_SCON:
|
||||
case C_UCON:
|
||||
case C_LCON:
|
||||
case C_ADDCON:
|
||||
case C_ANDCON:
|
||||
case C_SBRA:
|
||||
case C_LBRA:
|
||||
break;
|
||||
case C_CREG:
|
||||
c = p->to.reg;
|
||||
if(c == NREG)
|
||||
s->set.cr = ALL;
|
||||
else
|
||||
s->set.cr |= (0xF << ((p->from.reg&7)*4));
|
||||
s->set.cc = ALL;
|
||||
break;
|
||||
case C_SPR:
|
||||
case C_FPSCR:
|
||||
case C_MSR:
|
||||
case C_XER:
|
||||
s->set.ireg = ALL;
|
||||
s->set.freg = ALL;
|
||||
s->set.cc = ALL;
|
||||
s->set.cr = ALL;
|
||||
break;
|
||||
case C_LR:
|
||||
s->set.cc |= E_LR;
|
||||
break;
|
||||
case C_CTR:
|
||||
s->set.cc |= E_CTR;
|
||||
break;
|
||||
case C_ZOREG:
|
||||
case C_SOREG:
|
||||
case C_LOREG:
|
||||
c = p->to.reg;
|
||||
s->used.ireg |= 1<<c;
|
||||
if(upd)
|
||||
s->set.ireg |= 1<<c;
|
||||
if(ad)
|
||||
break;
|
||||
s->size = sz;
|
||||
s->soffset = regoff(&p->to);
|
||||
|
||||
m = ANYMEM;
|
||||
if(c == REGSB)
|
||||
m = E_MEMSB;
|
||||
if(c == REGSP)
|
||||
m = E_MEMSP;
|
||||
|
||||
if(ar)
|
||||
s->used.cc |= m;
|
||||
else
|
||||
s->set.cc |= m;
|
||||
break;
|
||||
case C_SACON:
|
||||
case C_LACON:
|
||||
s->used.ireg |= 1<<REGSP;
|
||||
if(upd)
|
||||
s->set.ireg |= 1<<c;
|
||||
break;
|
||||
case C_SECON:
|
||||
case C_LECON:
|
||||
s->used.ireg |= 1<<REGSB;
|
||||
if(upd)
|
||||
s->set.ireg |= 1<<c;
|
||||
break;
|
||||
case C_REG:
|
||||
if(nr)
|
||||
break;
|
||||
if(ar)
|
||||
s->used.ireg |= 1<<p->to.reg;
|
||||
else
|
||||
s->set.ireg |= 1<<p->to.reg;
|
||||
break;
|
||||
case C_FREG:
|
||||
if(ar)
|
||||
s->used.freg |= 1<<p->to.reg;
|
||||
else
|
||||
s->set.freg |= 1<<p->to.reg;
|
||||
break;
|
||||
case C_SAUTO:
|
||||
case C_LAUTO:
|
||||
s->used.ireg |= 1<<REGSP;
|
||||
if(upd)
|
||||
s->set.ireg |= 1<<c;
|
||||
if(ad)
|
||||
break;
|
||||
s->size = sz;
|
||||
s->soffset = regoff(&p->to);
|
||||
|
||||
if(ar)
|
||||
s->used.cc |= E_MEMSP;
|
||||
else
|
||||
s->set.cc |= E_MEMSP;
|
||||
break;
|
||||
case C_SEXT:
|
||||
case C_LEXT:
|
||||
s->used.ireg |= 1<<REGSB;
|
||||
if(upd)
|
||||
s->set.ireg |= 1<<c;
|
||||
if(ad)
|
||||
break;
|
||||
s->size = sz;
|
||||
s->soffset = regoff(&p->to);
|
||||
|
||||
if(ar)
|
||||
s->used.cc |= E_MEMSB;
|
||||
else
|
||||
s->set.cc |= E_MEMSB;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* flags based on 'from' field
|
||||
*/
|
||||
c = p->from.class;
|
||||
if(c == 0) {
|
||||
c = aclass(&p->from) + 1;
|
||||
p->from.class = c;
|
||||
}
|
||||
c--;
|
||||
switch(c) {
|
||||
default:
|
||||
print("unknown class %d %D\n", c, &p->from);
|
||||
|
||||
case C_NONE:
|
||||
case C_ZCON:
|
||||
case C_SCON:
|
||||
case C_UCON:
|
||||
case C_LCON:
|
||||
case C_ADDCON:
|
||||
case C_ANDCON:
|
||||
case C_SBRA:
|
||||
case C_LBRA:
|
||||
c = p->from.reg;
|
||||
if(c != NREG)
|
||||
s->used.ireg |= 1<<c;
|
||||
break;
|
||||
case C_CREG:
|
||||
c = p->from.reg;
|
||||
if(c == NREG)
|
||||
s->used.cr = ALL;
|
||||
else
|
||||
s->used.cr |= (0xF << ((p->from.reg&7)*4));
|
||||
s->used.cc = ALL;
|
||||
break;
|
||||
case C_SPR:
|
||||
case C_FPSCR:
|
||||
case C_MSR:
|
||||
case C_XER:
|
||||
s->set.ireg = ALL;
|
||||
s->set.freg = ALL;
|
||||
s->set.cc = ALL;
|
||||
s->set.cr = ALL;
|
||||
break;
|
||||
case C_LR:
|
||||
s->used.cc |= E_LR;
|
||||
break;
|
||||
case C_CTR:
|
||||
s->used.cc |= E_CTR;
|
||||
break;
|
||||
case C_ZOREG:
|
||||
case C_SOREG:
|
||||
case C_LOREG:
|
||||
c = p->from.reg;
|
||||
s->used.ireg |= 1<<c;
|
||||
if(ld)
|
||||
p->mark |= LOAD;
|
||||
if(ad)
|
||||
break;
|
||||
s->size = sz;
|
||||
s->soffset = regoff(&p->from);
|
||||
|
||||
m = ANYMEM;
|
||||
if(c == REGSB)
|
||||
m = E_MEMSB;
|
||||
if(c == REGSP)
|
||||
m = E_MEMSP;
|
||||
|
||||
s->used.cc |= m;
|
||||
break;
|
||||
case C_SACON:
|
||||
case C_LACON:
|
||||
s->used.ireg |= 1<<REGSP;
|
||||
break;
|
||||
case C_SECON:
|
||||
case C_LECON:
|
||||
s->used.ireg |= 1<<REGSB;
|
||||
break;
|
||||
case C_REG:
|
||||
if(nr)
|
||||
break;
|
||||
s->used.ireg |= 1<<p->from.reg;
|
||||
break;
|
||||
case C_FREG:
|
||||
s->used.freg |= 1<<p->from.reg;
|
||||
break;
|
||||
case C_SAUTO:
|
||||
case C_LAUTO:
|
||||
s->used.ireg |= 1<<REGSP;
|
||||
if(ld)
|
||||
p->mark |= LOAD;
|
||||
if(ad)
|
||||
break;
|
||||
s->size = sz;
|
||||
s->soffset = regoff(&p->from);
|
||||
|
||||
s->used.cc |= E_MEMSP;
|
||||
break;
|
||||
case C_SEXT:
|
||||
case C_LEXT:
|
||||
s->used.ireg |= 1<<REGSB;
|
||||
if(ld)
|
||||
p->mark |= LOAD;
|
||||
if(ad)
|
||||
break;
|
||||
s->size = sz;
|
||||
s->soffset = regoff(&p->from);
|
||||
|
||||
s->used.cc |= E_MEMSB;
|
||||
break;
|
||||
}
|
||||
|
||||
c = p->reg;
|
||||
if(c != NREG) {
|
||||
if(p->from.type == D_FREG || p->to.type == D_FREG)
|
||||
s->used.freg |= 1<<c;
|
||||
else
|
||||
s->used.ireg |= 1<<c;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* test to see if 2 instrictions can be
|
||||
* interchanged without changing semantics
|
||||
*/
|
||||
int
|
||||
depend(Sch *sa, Sch *sb)
|
||||
{
|
||||
ulong x;
|
||||
|
||||
if(sa->set.ireg & (sb->set.ireg|sb->used.ireg))
|
||||
return 1;
|
||||
if(sb->set.ireg & sa->used.ireg)
|
||||
return 1;
|
||||
|
||||
if(sa->set.freg & (sb->set.freg|sb->used.freg))
|
||||
return 1;
|
||||
if(sb->set.freg & sa->used.freg)
|
||||
return 1;
|
||||
|
||||
if(sa->set.cr & (sb->set.cr|sb->used.cr))
|
||||
return 1;
|
||||
if(sb->set.cr & sa->used.cr)
|
||||
return 1;
|
||||
|
||||
|
||||
x = (sa->set.cc & (sb->set.cc|sb->used.cc)) |
|
||||
(sb->set.cc & sa->used.cc);
|
||||
if(x) {
|
||||
/*
|
||||
* allow SB and SP to pass each other.
|
||||
* allow SB to pass SB iff doffsets are ok
|
||||
* anything else conflicts
|
||||
*/
|
||||
if(x != E_MEMSP && x != E_MEMSB)
|
||||
return 1;
|
||||
x = sa->set.cc | sb->set.cc |
|
||||
sa->used.cc | sb->used.cc;
|
||||
if(x & E_MEM)
|
||||
return 1;
|
||||
if(offoverlap(sa, sb))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
offoverlap(Sch *sa, Sch *sb)
|
||||
{
|
||||
|
||||
if(sa->soffset < sb->soffset) {
|
||||
if(sa->soffset+sa->size > sb->soffset)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
if(sb->soffset+sb->size > sa->soffset)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* test 2 adjacent instructions
|
||||
* and find out if inserted instructions
|
||||
* are desired to prevent stalls.
|
||||
* first instruction is a load instruction.
|
||||
*/
|
||||
int
|
||||
conflict(Sch *sa, Sch *sb)
|
||||
{
|
||||
|
||||
if(sa->set.ireg & sb->used.ireg)
|
||||
return 1;
|
||||
if(sa->set.freg & sb->used.freg)
|
||||
return 1;
|
||||
if(sa->set.cr & sb->used.cr)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
compound(Prog *p)
|
||||
{
|
||||
Optab *o;
|
||||
|
||||
o = oplook(p);
|
||||
if(o->size != 4)
|
||||
return 1;
|
||||
if(p->to.type == D_REG && p->to.reg == REGSB)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
dumpbits(Sch *s, Dep *d)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<32; i++)
|
||||
if(d->ireg & (1<<i))
|
||||
Bprint(&bso, " R%d", i);
|
||||
for(i=0; i<32; i++)
|
||||
if(d->freg & (1<<i))
|
||||
Bprint(&bso, " F%d", i);
|
||||
for(i=0; i<32; i++)
|
||||
if(d->cr & (1<<i))
|
||||
Bprint(&bso, " C%d", i);
|
||||
for(i=0; i<32; i++)
|
||||
switch(d->cc & (1<<i)) {
|
||||
default:
|
||||
break;
|
||||
case E_ICC:
|
||||
Bprint(&bso, " ICC");
|
||||
break;
|
||||
case E_FCC:
|
||||
Bprint(&bso, " FCC");
|
||||
break;
|
||||
case E_LR:
|
||||
Bprint(&bso, " LR");
|
||||
break;
|
||||
case E_CR:
|
||||
Bprint(&bso, " CR");
|
||||
break;
|
||||
case E_CTR:
|
||||
Bprint(&bso, " CTR");
|
||||
break;
|
||||
case E_XER:
|
||||
Bprint(&bso, " XER");
|
||||
break;
|
||||
case E_MEM:
|
||||
Bprint(&bso, " MEM%d", s->size);
|
||||
break;
|
||||
case E_MEMSB:
|
||||
Bprint(&bso, " SB%d", s->size);
|
||||
break;
|
||||
case E_MEMSP:
|
||||
Bprint(&bso, " SP%d", s->size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -57,7 +57,6 @@ static struct {
|
|||
{"solaris", Hsolaris},
|
||||
{"windows", Hwindows},
|
||||
{"windowsgui", Hwindows},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
int
|
||||
|
|
@ -65,7 +64,7 @@ headtype(char *name)
|
|||
{
|
||||
int i;
|
||||
|
||||
for(i=0; headers[i].name; i++)
|
||||
for(i=0; i < nelem(headers); i++)
|
||||
if(strcmp(name, headers[i].name) == 0)
|
||||
return headers[i].val;
|
||||
return -1;
|
||||
|
|
@ -77,7 +76,7 @@ headstr(int v)
|
|||
static char buf[20];
|
||||
int i;
|
||||
|
||||
for(i=0; headers[i].name; i++)
|
||||
for(i=0; i < nelem(headers); i++)
|
||||
if(v == headers[i].val)
|
||||
return headers[i].name;
|
||||
snprint(buf, sizeof buf, "%d", v);
|
||||
|
|
|
|||
|
|
@ -63,22 +63,19 @@ func New(out io.Writer, prefix string, flag int) *Logger {
|
|||
var std = New(os.Stderr, "", LstdFlags)
|
||||
|
||||
// Cheap integer to fixed-width decimal ASCII. Give a negative width to avoid zero-padding.
|
||||
// Knows the buffer has capacity.
|
||||
func itoa(buf *[]byte, i int, wid int) {
|
||||
var u uint = uint(i)
|
||||
if u == 0 && wid <= 1 {
|
||||
*buf = append(*buf, '0')
|
||||
return
|
||||
}
|
||||
|
||||
// Assemble decimal in reverse order.
|
||||
var b [32]byte
|
||||
bp := len(b)
|
||||
for ; u > 0 || wid > 0; u /= 10 {
|
||||
bp--
|
||||
var b [20]byte
|
||||
bp := len(b) - 1
|
||||
for i >= 10 || wid > 1 {
|
||||
wid--
|
||||
b[bp] = byte(u%10) + '0'
|
||||
q := i / 10
|
||||
b[bp] = byte('0' + i - q*10)
|
||||
bp--
|
||||
i = q
|
||||
}
|
||||
// i < 10
|
||||
b[bp] = byte('0' + i)
|
||||
*buf = append(*buf, b[bp:]...)
|
||||
}
|
||||
|
||||
|
|
@ -325,3 +322,14 @@ func Panicln(v ...interface{}) {
|
|||
std.Output(2, s)
|
||||
panic(s)
|
||||
}
|
||||
|
||||
// Output writes the output for a logging event. The string s contains
|
||||
// the text to print after the prefix specified by the flags of the
|
||||
// Logger. A newline is appended if the last character of s is not
|
||||
// already a newline. Calldepth is the count of the number of
|
||||
// frames to skip when computing the file name and line number
|
||||
// if Llongfile or Lshortfile is set; a value of 1 will print the details
|
||||
// for the caller of Output.
|
||||
func Output(calldepth int, s string) error {
|
||||
return std.Output(calldepth+1, s) // +1 for this frame.
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,3 +117,27 @@ func TestFlagAndPrefixSetting(t *testing.T) {
|
|||
t.Error("message did not match pattern")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkItoa(b *testing.B) {
|
||||
dst := make([]byte, 0, 64)
|
||||
for i := 0; i < b.N; i++ {
|
||||
dst = dst[0:0]
|
||||
itoa(&dst, 2015, 4) // year
|
||||
itoa(&dst, 1, 2) // month
|
||||
itoa(&dst, 30, 2) // day
|
||||
itoa(&dst, 12, 2) // hour
|
||||
itoa(&dst, 56, 2) // minute
|
||||
itoa(&dst, 0, 2) // second
|
||||
itoa(&dst, 987654, 6) // microsecond
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkPrintln(b *testing.B) {
|
||||
const testString = "test"
|
||||
var buf bytes.Buffer
|
||||
l := New(&buf, "", LstdFlags)
|
||||
for i := 0; i < b.N; i++ {
|
||||
buf.Reset()
|
||||
l.Println(testString)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ func mulWW_g(x, y Word) (z1, z0 Word) {
|
|||
|
||||
// z1<<_W + z0 = x*y + c
|
||||
func mulAddWWW_g(x, y, c Word) (z1, z0 Word) {
|
||||
z1, zz0 := mulWW(x, y)
|
||||
z1, zz0 := mulWW_g(x, y)
|
||||
if z0 = zz0 + c; z0 < zz0 {
|
||||
z1++
|
||||
}
|
||||
|
|
@ -154,21 +154,52 @@ func divWW_g(u1, u0, v Word) (q, r Word) {
|
|||
return q1*_B2 + q0, (un21*_B2 + un0 - q0*v) >> s
|
||||
}
|
||||
|
||||
// Keep for performance debugging.
|
||||
// Using addWW_g is likely slower.
|
||||
const use_addWW_g = false
|
||||
|
||||
// The resulting carry c is either 0 or 1.
|
||||
func addVV_g(z, x, y []Word) (c Word) {
|
||||
if use_addWW_g {
|
||||
for i := range z {
|
||||
c, z[i] = addWW_g(x[i], y[i], c)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
for i, xi := range x[:len(z)] {
|
||||
yi := y[i]
|
||||
zi := xi + yi + c
|
||||
z[i] = zi
|
||||
// see "Hacker's Delight", section 2-12 (overflow detection)
|
||||
c = (xi&yi | (xi|yi)&^zi) >> (_W - 1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// The resulting carry c is either 0 or 1.
|
||||
func subVV_g(z, x, y []Word) (c Word) {
|
||||
if use_addWW_g {
|
||||
for i := range z {
|
||||
c, z[i] = subWW_g(x[i], y[i], c)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
for i, xi := range x[:len(z)] {
|
||||
yi := y[i]
|
||||
zi := xi - yi - c
|
||||
z[i] = zi
|
||||
// see "Hacker's Delight", section 2-12 (overflow detection)
|
||||
c = (yi&^xi | (yi|^xi)&zi) >> (_W - 1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Argument y must be either 0 or 1.
|
||||
// The resulting carry c is either 0 or 1.
|
||||
func addVW_g(z, x []Word, y Word) (c Word) {
|
||||
if use_addWW_g {
|
||||
c = y
|
||||
for i := range z {
|
||||
c, z[i] = addWW_g(x[i], c, 0)
|
||||
|
|
@ -176,7 +207,17 @@ func addVW_g(z, x []Word, y Word) (c Word) {
|
|||
return
|
||||
}
|
||||
|
||||
c = y
|
||||
for i, xi := range x[:len(z)] {
|
||||
zi := xi + c
|
||||
z[i] = zi
|
||||
c = xi &^ zi >> (_W - 1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func subVW_g(z, x []Word, y Word) (c Word) {
|
||||
if use_addWW_g {
|
||||
c = y
|
||||
for i := range z {
|
||||
c, z[i] = subWW_g(x[i], c, 0)
|
||||
|
|
@ -184,6 +225,15 @@ func subVW_g(z, x []Word, y Word) (c Word) {
|
|||
return
|
||||
}
|
||||
|
||||
c = y
|
||||
for i, xi := range x[:len(z)] {
|
||||
zi := xi - c
|
||||
z[i] = zi
|
||||
c = (zi &^ xi) >> (_W - 1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func shlVU_g(z, x []Word, s uint) (c Word) {
|
||||
if n := len(z); n > 0 {
|
||||
ŝ := _W - s
|
||||
|
|
@ -222,6 +272,7 @@ func mulAddVWW_g(z, x []Word, y, r Word) (c Word) {
|
|||
return
|
||||
}
|
||||
|
||||
// TODO(gri) Remove use of addWW_g here and then we can remove addWW_g and subWW_g.
|
||||
func addMulVVW_g(z, x []Word, y Word) (c Word) {
|
||||
for i := range z {
|
||||
z1, z0 := mulAddWWW_g(x[i], y, z[i])
|
||||
|
|
|
|||
|
|
@ -37,15 +37,16 @@ TEXT ·addVV(SB),NOSPLIT,$0
|
|||
JMP E1
|
||||
|
||||
L1: MOVL (SI)(BX*4), AX
|
||||
RCRL $1, DX
|
||||
ADDL DX, DX // restore CF
|
||||
ADCL (CX)(BX*4), AX
|
||||
RCLL $1, DX
|
||||
SBBL DX, DX // save CF
|
||||
MOVL AX, (DI)(BX*4)
|
||||
ADDL $1, BX // i++
|
||||
|
||||
E1: CMPL BX, BP // i < n
|
||||
JL L1
|
||||
|
||||
NEGL DX
|
||||
MOVL DX, c+36(FP)
|
||||
RET
|
||||
|
||||
|
|
@ -62,15 +63,16 @@ TEXT ·subVV(SB),NOSPLIT,$0
|
|||
JMP E2
|
||||
|
||||
L2: MOVL (SI)(BX*4), AX
|
||||
RCRL $1, DX
|
||||
ADDL DX, DX // restore CF
|
||||
SBBL (CX)(BX*4), AX
|
||||
RCLL $1, DX
|
||||
SBBL DX, DX // save CF
|
||||
MOVL AX, (DI)(BX*4)
|
||||
ADDL $1, BX // i++
|
||||
|
||||
E2: CMPL BX, BP // i < n
|
||||
JL L2
|
||||
|
||||
NEGL DX
|
||||
MOVL DX, c+36(FP)
|
||||
RET
|
||||
|
||||
|
|
@ -86,8 +88,8 @@ TEXT ·addVW(SB),NOSPLIT,$0
|
|||
|
||||
L3: ADDL (SI)(BX*4), AX
|
||||
MOVL AX, (DI)(BX*4)
|
||||
RCLL $1, AX
|
||||
ANDL $1, AX
|
||||
SBBL AX, AX // save CF
|
||||
NEGL AX
|
||||
ADDL $1, BX // i++
|
||||
|
||||
E3: CMPL BX, BP // i < n
|
||||
|
|
@ -106,11 +108,11 @@ TEXT ·subVW(SB),NOSPLIT,$0
|
|||
MOVL $0, BX // i = 0
|
||||
JMP E4
|
||||
|
||||
L4: MOVL (SI)(BX*4), DX // TODO(gri) is there a reverse SUBL?
|
||||
L4: MOVL (SI)(BX*4), DX
|
||||
SUBL AX, DX
|
||||
MOVL DX, (DI)(BX*4)
|
||||
RCLL $1, AX
|
||||
ANDL $1, AX
|
||||
SBBL AX, AX // save CF
|
||||
NEGL AX
|
||||
ADDL $1, BX // i++
|
||||
|
||||
E4: CMPL BX, BP // i < n
|
||||
|
|
|
|||
|
|
@ -7,16 +7,6 @@
|
|||
// This file provides fast assembly versions for the elementary
|
||||
// arithmetic operations on vectors implemented in arith.go.
|
||||
|
||||
// Literal instruction for MOVQ $0, CX.
|
||||
// (MOVQ $0, reg is translated to XORQ reg, reg and clears CF.)
|
||||
#define ZERO_CX BYTE $0x48; \
|
||||
BYTE $0xc7; \
|
||||
BYTE $0xc1; \
|
||||
BYTE $0x00; \
|
||||
BYTE $0x00; \
|
||||
BYTE $0x00; \
|
||||
BYTE $0x00
|
||||
|
||||
// func mulWW(x, y Word) (z1, z0 Word)
|
||||
TEXT ·mulWW(SB),NOSPLIT,$0
|
||||
MOVQ x+0(FP), AX
|
||||
|
|
@ -35,6 +25,11 @@ TEXT ·divWW(SB),NOSPLIT,$0
|
|||
MOVQ DX, r+32(FP)
|
||||
RET
|
||||
|
||||
// The carry bit is saved with SBBQ Rx, Rx: if the carry was set, Rx is -1, otherwise it is 0.
|
||||
// It is restored with ADDQ Rx, Rx: if Rx was -1 the carry is set, otherwise it is cleared.
|
||||
// This is faster than using rotate instructions.
|
||||
//
|
||||
// CAUTION: Note that MOVQ $0, Rx is translated to XORQ Rx, Rx which clears the carry bit!
|
||||
|
||||
// func addVV(z, x, y []Word) (c Word)
|
||||
TEXT ·addVV(SB),NOSPLIT,$0
|
||||
|
|
@ -52,7 +47,7 @@ TEXT ·addVV(SB),NOSPLIT,$0
|
|||
|
||||
U1: // n >= 0
|
||||
// regular loop body unrolled 4x
|
||||
RCRQ $1, CX // CF = c
|
||||
ADDQ CX, CX // restore CF
|
||||
MOVQ 0(R8)(SI*8), R11
|
||||
MOVQ 8(R8)(SI*8), R12
|
||||
MOVQ 16(R8)(SI*8), R13
|
||||
|
|
@ -65,7 +60,7 @@ U1: // n >= 0
|
|||
MOVQ R12, 8(R10)(SI*8)
|
||||
MOVQ R13, 16(R10)(SI*8)
|
||||
MOVQ R14, 24(R10)(SI*8)
|
||||
RCLQ $1, CX // c = CF
|
||||
SBBQ CX, CX // save CF
|
||||
|
||||
ADDQ $4, SI // i += 4
|
||||
SUBQ $4, DI // n -= 4
|
||||
|
|
@ -75,17 +70,18 @@ V1: ADDQ $4, DI // n += 4
|
|||
JLE E1 // if n <= 0 goto E1
|
||||
|
||||
L1: // n > 0
|
||||
RCRQ $1, CX // CF = c
|
||||
ADDQ CX, CX // restore CF
|
||||
MOVQ 0(R8)(SI*8), R11
|
||||
ADCQ 0(R9)(SI*8), R11
|
||||
MOVQ R11, 0(R10)(SI*8)
|
||||
RCLQ $1, CX // c = CF
|
||||
SBBQ CX, CX // save CF
|
||||
|
||||
ADDQ $1, SI // i++
|
||||
SUBQ $1, DI // n--
|
||||
JG L1 // if n > 0 goto L1
|
||||
|
||||
E1: MOVQ CX, c+72(FP) // return c
|
||||
E1: NEGQ CX
|
||||
MOVQ CX, c+72(FP) // return c
|
||||
RET
|
||||
|
||||
|
||||
|
|
@ -106,7 +102,7 @@ TEXT ·subVV(SB),NOSPLIT,$0
|
|||
|
||||
U2: // n >= 0
|
||||
// regular loop body unrolled 4x
|
||||
RCRQ $1, CX // CF = c
|
||||
ADDQ CX, CX // restore CF
|
||||
MOVQ 0(R8)(SI*8), R11
|
||||
MOVQ 8(R8)(SI*8), R12
|
||||
MOVQ 16(R8)(SI*8), R13
|
||||
|
|
@ -119,7 +115,7 @@ U2: // n >= 0
|
|||
MOVQ R12, 8(R10)(SI*8)
|
||||
MOVQ R13, 16(R10)(SI*8)
|
||||
MOVQ R14, 24(R10)(SI*8)
|
||||
RCLQ $1, CX // c = CF
|
||||
SBBQ CX, CX // save CF
|
||||
|
||||
ADDQ $4, SI // i += 4
|
||||
SUBQ $4, DI // n -= 4
|
||||
|
|
@ -129,17 +125,18 @@ V2: ADDQ $4, DI // n += 4
|
|||
JLE E2 // if n <= 0 goto E2
|
||||
|
||||
L2: // n > 0
|
||||
RCRQ $1, CX // CF = c
|
||||
ADDQ CX, CX // restore CF
|
||||
MOVQ 0(R8)(SI*8), R11
|
||||
SBBQ 0(R9)(SI*8), R11
|
||||
MOVQ R11, 0(R10)(SI*8)
|
||||
RCLQ $1, CX // c = CF
|
||||
SBBQ CX, CX // save CF
|
||||
|
||||
ADDQ $1, SI // i++
|
||||
SUBQ $1, DI // n--
|
||||
JG L2 // if n > 0 goto L2
|
||||
|
||||
E2: MOVQ CX, c+72(FP) // return c
|
||||
E2: NEGQ CX
|
||||
MOVQ CX, c+72(FP) // return c
|
||||
RET
|
||||
|
||||
|
||||
|
|
@ -163,11 +160,11 @@ U3: // n >= 0
|
|||
MOVQ 16(R8)(SI*8), R13
|
||||
MOVQ 24(R8)(SI*8), R14
|
||||
ADDQ CX, R11
|
||||
ZERO_CX
|
||||
ADCQ $0, R12
|
||||
ADCQ $0, R13
|
||||
ADCQ $0, R14
|
||||
SETCS CX // c = CF
|
||||
SBBQ CX, CX // save CF
|
||||
NEGQ CX
|
||||
MOVQ R11, 0(R10)(SI*8)
|
||||
MOVQ R12, 8(R10)(SI*8)
|
||||
MOVQ R13, 16(R10)(SI*8)
|
||||
|
|
@ -183,8 +180,8 @@ V3: ADDQ $4, DI // n += 4
|
|||
L3: // n > 0
|
||||
ADDQ 0(R8)(SI*8), CX
|
||||
MOVQ CX, 0(R10)(SI*8)
|
||||
ZERO_CX
|
||||
RCLQ $1, CX // c = CF
|
||||
SBBQ CX, CX // save CF
|
||||
NEGQ CX
|
||||
|
||||
ADDQ $1, SI // i++
|
||||
SUBQ $1, DI // n--
|
||||
|
|
@ -215,11 +212,11 @@ U4: // n >= 0
|
|||
MOVQ 16(R8)(SI*8), R13
|
||||
MOVQ 24(R8)(SI*8), R14
|
||||
SUBQ CX, R11
|
||||
ZERO_CX
|
||||
SBBQ $0, R12
|
||||
SBBQ $0, R13
|
||||
SBBQ $0, R14
|
||||
SETCS CX // c = CF
|
||||
SBBQ CX, CX // save CF
|
||||
NEGQ CX
|
||||
MOVQ R11, 0(R10)(SI*8)
|
||||
MOVQ R12, 8(R10)(SI*8)
|
||||
MOVQ R13, 16(R10)(SI*8)
|
||||
|
|
@ -236,8 +233,8 @@ L4: // n > 0
|
|||
MOVQ 0(R8)(SI*8), R11
|
||||
SUBQ CX, R11
|
||||
MOVQ R11, 0(R10)(SI*8)
|
||||
ZERO_CX
|
||||
RCLQ $1, CX // c = CF
|
||||
SBBQ CX, CX // save CF
|
||||
NEGQ CX
|
||||
|
||||
ADDQ $1, SI // i++
|
||||
SUBQ $1, DI // n--
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@ func benchmarkFunVW(b *testing.B, f funVW, n int) {
|
|||
x := rndV(n)
|
||||
y := rndW()
|
||||
z := make([]Word, n)
|
||||
b.SetBytes(int64(n * _W))
|
||||
b.SetBytes(int64(n * _S))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
f(z, x, y)
|
||||
|
|
|
|||
|
|
@ -769,3 +769,55 @@ func BenchmarkExp3Power0x10000(b *testing.B) { ExpHelper(b, 3, 0x10000) }
|
|||
func BenchmarkExp3Power0x40000(b *testing.B) { ExpHelper(b, 3, 0x40000) }
|
||||
func BenchmarkExp3Power0x100000(b *testing.B) { ExpHelper(b, 3, 0x100000) }
|
||||
func BenchmarkExp3Power0x400000(b *testing.B) { ExpHelper(b, 3, 0x400000) }
|
||||
|
||||
func fibo(n int) nat {
|
||||
switch n {
|
||||
case 0:
|
||||
return nil
|
||||
case 1:
|
||||
return nat{1}
|
||||
}
|
||||
f0 := fibo(0)
|
||||
f1 := fibo(1)
|
||||
var f2 nat
|
||||
for i := 1; i < n; i++ {
|
||||
f2 = f2.add(f0, f1)
|
||||
f0, f1, f2 = f1, f2, f0
|
||||
}
|
||||
return f1
|
||||
}
|
||||
|
||||
var fiboNums = []string{
|
||||
"0",
|
||||
"55",
|
||||
"6765",
|
||||
"832040",
|
||||
"102334155",
|
||||
"12586269025",
|
||||
"1548008755920",
|
||||
"190392490709135",
|
||||
"23416728348467685",
|
||||
"2880067194370816120",
|
||||
"354224848179261915075",
|
||||
}
|
||||
|
||||
func TestFibo(t *testing.T) {
|
||||
for i, want := range fiboNums {
|
||||
n := i * 10
|
||||
got := fibo(n).decimalString()
|
||||
if got != want {
|
||||
t.Errorf("fibo(%d) failed: got %s want %s", n, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkFibo(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
fibo(1e0)
|
||||
fibo(1e1)
|
||||
fibo(1e2)
|
||||
fibo(1e3)
|
||||
fibo(1e4)
|
||||
fibo(1e5)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,6 +100,24 @@ var hopHeaders = []string{
|
|||
"Upgrade",
|
||||
}
|
||||
|
||||
type requestCanceler interface {
|
||||
CancelRequest(*http.Request)
|
||||
}
|
||||
|
||||
type runOnFirstRead struct {
|
||||
io.Reader
|
||||
|
||||
fn func() // Run before first Read, then set to nil
|
||||
}
|
||||
|
||||
func (c *runOnFirstRead) Read(bs []byte) (int, error) {
|
||||
if c.fn != nil {
|
||||
c.fn()
|
||||
c.fn = nil
|
||||
}
|
||||
return c.Reader.Read(bs)
|
||||
}
|
||||
|
||||
func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
transport := p.Transport
|
||||
if transport == nil {
|
||||
|
|
@ -109,6 +127,34 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|||
outreq := new(http.Request)
|
||||
*outreq = *req // includes shallow copies of maps, but okay
|
||||
|
||||
if closeNotifier, ok := rw.(http.CloseNotifier); ok {
|
||||
if requestCanceler, ok := transport.(requestCanceler); ok {
|
||||
reqDone := make(chan struct{})
|
||||
defer close(reqDone)
|
||||
|
||||
clientGone := closeNotifier.CloseNotify()
|
||||
|
||||
outreq.Body = struct {
|
||||
io.Reader
|
||||
io.Closer
|
||||
}{
|
||||
Reader: &runOnFirstRead{
|
||||
Reader: outreq.Body,
|
||||
fn: func() {
|
||||
go func() {
|
||||
select {
|
||||
case <-clientGone:
|
||||
requestCanceler.CancelRequest(outreq)
|
||||
case <-reqDone:
|
||||
}
|
||||
}()
|
||||
},
|
||||
},
|
||||
Closer: outreq.Body,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p.Director(outreq)
|
||||
outreq.Proto = "HTTP/1.1"
|
||||
outreq.ProtoMajor = 1
|
||||
|
|
|
|||
|
|
@ -8,9 +8,11 @@ package httputil
|
|||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
|
@ -211,3 +213,61 @@ func TestReverseProxyFlushInterval(t *testing.T) {
|
|||
t.Error("maxLatencyWriter flushLoop() never exited")
|
||||
}
|
||||
}
|
||||
|
||||
func TestReverseProxyCancellation(t *testing.T) {
|
||||
if runtime.GOOS == "plan9" {
|
||||
t.Skip("skipping test; see http://golang.org/issue/9554")
|
||||
}
|
||||
const backendResponse = "I am the backend"
|
||||
|
||||
reqInFlight := make(chan struct{})
|
||||
backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
close(reqInFlight)
|
||||
|
||||
select {
|
||||
case <-time.After(10 * time.Second):
|
||||
// Note: this should only happen in broken implementations, and the
|
||||
// closenotify case should be instantaneous.
|
||||
t.Log("Failed to close backend connection")
|
||||
t.Fail()
|
||||
case <-w.(http.CloseNotifier).CloseNotify():
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(backendResponse))
|
||||
}))
|
||||
|
||||
defer backend.Close()
|
||||
|
||||
backend.Config.ErrorLog = log.New(ioutil.Discard, "", 0)
|
||||
|
||||
backendURL, err := url.Parse(backend.URL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
proxyHandler := NewSingleHostReverseProxy(backendURL)
|
||||
|
||||
// Discards errors of the form:
|
||||
// http: proxy error: read tcp 127.0.0.1:44643: use of closed network connection
|
||||
proxyHandler.ErrorLog = log.New(ioutil.Discard, "", 0)
|
||||
|
||||
frontend := httptest.NewServer(proxyHandler)
|
||||
defer frontend.Close()
|
||||
|
||||
getReq, _ := http.NewRequest("GET", frontend.URL, nil)
|
||||
go func() {
|
||||
<-reqInFlight
|
||||
http.DefaultTransport.(*http.Transport).CancelRequest(getReq)
|
||||
}()
|
||||
res, err := http.DefaultClient.Do(getReq)
|
||||
if res != nil {
|
||||
t.Fatal("Non-nil response")
|
||||
}
|
||||
if err == nil {
|
||||
// This should be an error like:
|
||||
// Get http://127.0.0.1:58079: read tcp 127.0.0.1:58079:
|
||||
// use of closed network connection
|
||||
t.Fatal("DefaultClient.Do() returned nil error")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2384,18 +2384,24 @@ func TestRequestBodyCloseDoesntBlock(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestResponseWriterWriteStringAllocs(t *testing.T) {
|
||||
// test that ResponseWriter implements io.stringWriter.
|
||||
func TestResponseWriterWriteString(t *testing.T) {
|
||||
okc := make(chan bool, 1)
|
||||
ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) {
|
||||
if r.URL.Path == "/s" {
|
||||
io.WriteString(w, "Hello world")
|
||||
} else {
|
||||
w.Write([]byte("Hello world"))
|
||||
type stringWriter interface {
|
||||
WriteString(s string) (n int, err error)
|
||||
}
|
||||
_, ok := w.(stringWriter)
|
||||
okc <- ok
|
||||
}))
|
||||
before := testing.AllocsPerRun(50, func() { ht.rawResponse("GET / HTTP/1.0") })
|
||||
after := testing.AllocsPerRun(50, func() { ht.rawResponse("GET /s HTTP/1.0") })
|
||||
if int(after) >= int(before) {
|
||||
t.Errorf("WriteString allocs of %v >= Write allocs of %v", after, before)
|
||||
ht.rawResponse("GET / HTTP/1.0")
|
||||
select {
|
||||
case ok := <-okc:
|
||||
if !ok {
|
||||
t.Error("ResponseWriter did not implement io.stringWriter")
|
||||
}
|
||||
default:
|
||||
t.Error("handler was never called")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1530,6 +1530,7 @@ type gcProg struct {
|
|||
gc []byte
|
||||
size uintptr // size of type in bytes
|
||||
hasPtr bool
|
||||
lastZero uintptr // largest offset of a zero-byte field
|
||||
}
|
||||
|
||||
func (gc *gcProg) append(v byte) {
|
||||
|
|
@ -1542,6 +1543,9 @@ func (gc *gcProg) appendProg(t *rtype) {
|
|||
gc.align(uintptr(t.align))
|
||||
if !t.pointers() {
|
||||
gc.size += t.size
|
||||
if t.size == 0 {
|
||||
gc.lastZero = gc.size
|
||||
}
|
||||
return
|
||||
}
|
||||
switch t.Kind() {
|
||||
|
|
@ -1566,11 +1570,15 @@ func (gc *gcProg) appendProg(t *rtype) {
|
|||
gc.appendWord(bitsPointer)
|
||||
gc.appendWord(bitsPointer)
|
||||
case Struct:
|
||||
oldsize := gc.size
|
||||
c := t.NumField()
|
||||
for i := 0; i < c; i++ {
|
||||
gc.appendProg(t.Field(i).Type.common())
|
||||
}
|
||||
gc.align(uintptr(t.align))
|
||||
if gc.size > oldsize + t.size {
|
||||
panic("reflect: struct components are larger than the struct itself")
|
||||
}
|
||||
gc.size = oldsize + t.size
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1595,6 +1603,9 @@ func (gc *gcProg) finalize() (unsafe.Pointer, bool) {
|
|||
if gc.size == 0 {
|
||||
return nil, false
|
||||
}
|
||||
if gc.lastZero == gc.size {
|
||||
gc.size++
|
||||
}
|
||||
ptrsize := unsafe.Sizeof(uintptr(0))
|
||||
gc.align(ptrsize)
|
||||
nptr := gc.size / ptrsize
|
||||
|
|
|
|||
|
|
@ -732,7 +732,7 @@ func (v Value) Field(i int) Value {
|
|||
// Either flagIndir is set and v.ptr points at struct,
|
||||
// or flagIndir is not set and v.ptr is the actual struct data.
|
||||
// In the former case, we want v.ptr + offset.
|
||||
// In the latter case, we must be have field.offset = 0,
|
||||
// In the latter case, we must have field.offset = 0,
|
||||
// so v.ptr + field.offset is still okay.
|
||||
ptr := unsafe.Pointer(uintptr(v.ptr) + field.offset)
|
||||
return Value{typ, ptr, fl}
|
||||
|
|
|
|||
12
src/run.bash
12
src/run.bash
|
|
@ -118,6 +118,7 @@ export GOTRACEBACK=2
|
|||
go test -ldflags '-linkmode=auto' || exit 1
|
||||
# linkmode=internal fails on dragonfly since errno is a TLS relocation.
|
||||
[ "$GOHOSTOS" == dragonfly ] || go test -ldflags '-linkmode=internal' || exit 1
|
||||
# TODO(austin): Add linux-ppc64(le) once external linking works (issue #8912)
|
||||
case "$GOHOSTOS-$GOARCH" in
|
||||
openbsd-386 | openbsd-amd64)
|
||||
# test linkmode=external, but __thread not supported, so skip testtls.
|
||||
|
|
@ -180,17 +181,6 @@ linux-linux-amd64-1 | freebsd-freebsd-amd64-1 | darwin-darwin-amd64-1)
|
|||
fi
|
||||
esac
|
||||
|
||||
# This tests cgo -cdefs. That mode is not supported,
|
||||
# so it's okay if it doesn't work on some systems.
|
||||
# In particular, it works badly with clang on OS X.
|
||||
# It doesn't work at all now that we disallow C code
|
||||
# outside runtime. Once runtime has no C code it won't
|
||||
# even be necessary.
|
||||
# [ "$CGO_ENABLED" != 1 ] || [ "$GOOS" == darwin ] ||
|
||||
# (xcd ../misc/cgo/testcdefs
|
||||
# ./test.bash || exit 1
|
||||
# ) || exit $?
|
||||
|
||||
[ "$CGO_ENABLED" != 1 ] || [ "$GOOS" == darwin ] ||
|
||||
(xcd ../misc/cgo/testgodefs
|
||||
./test.bash || exit 1
|
||||
|
|
|
|||
16
src/run.rc
16
src/run.rc
|
|
@ -29,13 +29,25 @@ if not {
|
|||
GOROOT_FINAL = ()
|
||||
|
||||
echo '# Testing packages.'
|
||||
time go test std -short -timeout 120s
|
||||
time go test std -short -timeout 240s
|
||||
echo
|
||||
|
||||
# Temporary GCE builder hack until Plan 9 on GCE is fast enough.
|
||||
# See https://golang.org/issue/9491
|
||||
if(~ $GOTESTONLY std) {
|
||||
echo
|
||||
echo PARTIAL TESTS PASSED: std
|
||||
exit
|
||||
}
|
||||
|
||||
# We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
|
||||
# creation of first goroutines and first garbage collections in the parallel setting.
|
||||
# TODO(bradfitz,0intro): make this not be 15 minutes once Plan 9 runs quickly on GCE.
|
||||
# Linux does 63 seconds on GCE, but Plan 9 was failing with 8 minutes.
|
||||
# See issue 8393 and 9491.
|
||||
# TODO(bradfitz,0intro): remove -v once we see some a successful build.
|
||||
echo '# GOMAXPROCS=2 runtime -cpu=1,2,4'
|
||||
GOMAXPROCS=2 go test runtime -short -timeout 240s -cpu 1,2,4
|
||||
GOMAXPROCS=2 go test runtime -v -short -timeout 15m -cpu 1,2,4
|
||||
echo
|
||||
|
||||
echo '# sync -cpu=10'
|
||||
|
|
|
|||
|
|
@ -40,21 +40,45 @@ const (
|
|||
|
||||
type typeAlg struct {
|
||||
// function for hashing objects of this type
|
||||
// (ptr to object, size, seed) -> hash
|
||||
hash func(unsafe.Pointer, uintptr, uintptr) uintptr
|
||||
// (ptr to object, seed) -> hash
|
||||
hash func(unsafe.Pointer, uintptr) uintptr
|
||||
// function for comparing objects of this type
|
||||
// (ptr to object A, ptr to object B, size) -> ==?
|
||||
equal func(unsafe.Pointer, unsafe.Pointer, uintptr) bool
|
||||
// (ptr to object A, ptr to object B) -> ==?
|
||||
equal func(unsafe.Pointer, unsafe.Pointer) bool
|
||||
}
|
||||
|
||||
func memhash0(p unsafe.Pointer, h uintptr) uintptr {
|
||||
return h
|
||||
}
|
||||
func memhash8(p unsafe.Pointer, h uintptr) uintptr {
|
||||
return memhash(p, h, 1)
|
||||
}
|
||||
func memhash16(p unsafe.Pointer, h uintptr) uintptr {
|
||||
return memhash(p, h, 2)
|
||||
}
|
||||
func memhash32(p unsafe.Pointer, h uintptr) uintptr {
|
||||
return memhash(p, h, 4)
|
||||
}
|
||||
func memhash64(p unsafe.Pointer, h uintptr) uintptr {
|
||||
return memhash(p, h, 8)
|
||||
}
|
||||
func memhash128(p unsafe.Pointer, h uintptr) uintptr {
|
||||
return memhash(p, h, 16)
|
||||
}
|
||||
|
||||
// memhash_varlen is defined in assembly because it needs access
|
||||
// to the closure. It appears here to provide an argument
|
||||
// signature for the assembly routine.
|
||||
func memhash_varlen(p unsafe.Pointer, h uintptr) uintptr
|
||||
|
||||
var algarray = [alg_max]typeAlg{
|
||||
alg_MEM: {memhash, memequal},
|
||||
alg_MEM0: {memhash, memequal0},
|
||||
alg_MEM8: {memhash, memequal8},
|
||||
alg_MEM16: {memhash, memequal16},
|
||||
alg_MEM32: {memhash, memequal32},
|
||||
alg_MEM64: {memhash, memequal64},
|
||||
alg_MEM128: {memhash, memequal128},
|
||||
alg_MEM: {nil, nil}, // not used
|
||||
alg_MEM0: {memhash0, memequal0},
|
||||
alg_MEM8: {memhash8, memequal8},
|
||||
alg_MEM16: {memhash16, memequal16},
|
||||
alg_MEM32: {memhash32, memequal32},
|
||||
alg_MEM64: {memhash64, memequal64},
|
||||
alg_MEM128: {memhash128, memequal128},
|
||||
alg_NOEQ: {nil, nil},
|
||||
alg_NOEQ0: {nil, nil},
|
||||
alg_NOEQ8: {nil, nil},
|
||||
|
|
@ -75,14 +99,14 @@ var algarray = [alg_max]typeAlg{
|
|||
var useAeshash bool
|
||||
|
||||
// in asm_*.s
|
||||
func aeshash(p unsafe.Pointer, s, h uintptr) uintptr
|
||||
func aeshash32(p unsafe.Pointer, s, h uintptr) uintptr
|
||||
func aeshash64(p unsafe.Pointer, s, h uintptr) uintptr
|
||||
func aeshashstr(p unsafe.Pointer, s, h uintptr) uintptr
|
||||
func aeshash(p unsafe.Pointer, h, s uintptr) uintptr
|
||||
func aeshash32(p unsafe.Pointer, h uintptr) uintptr
|
||||
func aeshash64(p unsafe.Pointer, h uintptr) uintptr
|
||||
func aeshashstr(p unsafe.Pointer, h uintptr) uintptr
|
||||
|
||||
func strhash(a unsafe.Pointer, s, h uintptr) uintptr {
|
||||
func strhash(a unsafe.Pointer, h uintptr) uintptr {
|
||||
x := (*stringStruct)(a)
|
||||
return memhash(x.str, uintptr(x.len), h)
|
||||
return memhash(x.str, h, uintptr(x.len))
|
||||
}
|
||||
|
||||
// NOTE: Because NaN != NaN, a map can contain any
|
||||
|
|
@ -90,7 +114,7 @@ func strhash(a unsafe.Pointer, s, h uintptr) uintptr {
|
|||
// To avoid long hash chains, we assign a random number
|
||||
// as the hash value for a NaN.
|
||||
|
||||
func f32hash(p unsafe.Pointer, s, h uintptr) uintptr {
|
||||
func f32hash(p unsafe.Pointer, h uintptr) uintptr {
|
||||
f := *(*float32)(p)
|
||||
switch {
|
||||
case f == 0:
|
||||
|
|
@ -98,11 +122,11 @@ func f32hash(p unsafe.Pointer, s, h uintptr) uintptr {
|
|||
case f != f:
|
||||
return c1 * (c0 ^ h ^ uintptr(fastrand1())) // any kind of NaN
|
||||
default:
|
||||
return memhash(p, 4, h)
|
||||
return memhash(p, h, 4)
|
||||
}
|
||||
}
|
||||
|
||||
func f64hash(p unsafe.Pointer, s, h uintptr) uintptr {
|
||||
func f64hash(p unsafe.Pointer, h uintptr) uintptr {
|
||||
f := *(*float64)(p)
|
||||
switch {
|
||||
case f == 0:
|
||||
|
|
@ -110,21 +134,21 @@ func f64hash(p unsafe.Pointer, s, h uintptr) uintptr {
|
|||
case f != f:
|
||||
return c1 * (c0 ^ h ^ uintptr(fastrand1())) // any kind of NaN
|
||||
default:
|
||||
return memhash(p, 8, h)
|
||||
return memhash(p, h, 8)
|
||||
}
|
||||
}
|
||||
|
||||
func c64hash(p unsafe.Pointer, s, h uintptr) uintptr {
|
||||
func c64hash(p unsafe.Pointer, h uintptr) uintptr {
|
||||
x := (*[2]float32)(p)
|
||||
return f32hash(unsafe.Pointer(&x[1]), 4, f32hash(unsafe.Pointer(&x[0]), 4, h))
|
||||
return f32hash(unsafe.Pointer(&x[1]), f32hash(unsafe.Pointer(&x[0]), h))
|
||||
}
|
||||
|
||||
func c128hash(p unsafe.Pointer, s, h uintptr) uintptr {
|
||||
func c128hash(p unsafe.Pointer, h uintptr) uintptr {
|
||||
x := (*[2]float64)(p)
|
||||
return f64hash(unsafe.Pointer(&x[1]), 8, f64hash(unsafe.Pointer(&x[0]), 8, h))
|
||||
return f64hash(unsafe.Pointer(&x[1]), f64hash(unsafe.Pointer(&x[0]), h))
|
||||
}
|
||||
|
||||
func interhash(p unsafe.Pointer, s, h uintptr) uintptr {
|
||||
func interhash(p unsafe.Pointer, h uintptr) uintptr {
|
||||
a := (*iface)(p)
|
||||
tab := a.tab
|
||||
if tab == nil {
|
||||
|
|
@ -136,13 +160,13 @@ func interhash(p unsafe.Pointer, s, h uintptr) uintptr {
|
|||
panic(errorString("hash of unhashable type " + *t._string))
|
||||
}
|
||||
if isDirectIface(t) {
|
||||
return c1 * fn(unsafe.Pointer(&a.data), uintptr(t.size), h^c0)
|
||||
return c1 * fn(unsafe.Pointer(&a.data), h^c0)
|
||||
} else {
|
||||
return c1 * fn(a.data, uintptr(t.size), h^c0)
|
||||
return c1 * fn(a.data, h^c0)
|
||||
}
|
||||
}
|
||||
|
||||
func nilinterhash(p unsafe.Pointer, s, h uintptr) uintptr {
|
||||
func nilinterhash(p unsafe.Pointer, h uintptr) uintptr {
|
||||
a := (*eface)(p)
|
||||
t := a._type
|
||||
if t == nil {
|
||||
|
|
@ -153,9 +177,9 @@ func nilinterhash(p unsafe.Pointer, s, h uintptr) uintptr {
|
|||
panic(errorString("hash of unhashable type " + *t._string))
|
||||
}
|
||||
if isDirectIface(t) {
|
||||
return c1 * fn(unsafe.Pointer(&a.data), uintptr(t.size), h^c0)
|
||||
return c1 * fn(unsafe.Pointer(&a.data), h^c0)
|
||||
} else {
|
||||
return c1 * fn(a.data, uintptr(t.size), h^c0)
|
||||
return c1 * fn(a.data, h^c0)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -166,47 +190,47 @@ func memequal(p, q unsafe.Pointer, size uintptr) bool {
|
|||
return memeq(p, q, size)
|
||||
}
|
||||
|
||||
func memequal0(p, q unsafe.Pointer, size uintptr) bool {
|
||||
func memequal0(p, q unsafe.Pointer) bool {
|
||||
return true
|
||||
}
|
||||
func memequal8(p, q unsafe.Pointer, size uintptr) bool {
|
||||
func memequal8(p, q unsafe.Pointer) bool {
|
||||
return *(*int8)(p) == *(*int8)(q)
|
||||
}
|
||||
func memequal16(p, q unsafe.Pointer, size uintptr) bool {
|
||||
func memequal16(p, q unsafe.Pointer) bool {
|
||||
return *(*int16)(p) == *(*int16)(q)
|
||||
}
|
||||
func memequal32(p, q unsafe.Pointer, size uintptr) bool {
|
||||
func memequal32(p, q unsafe.Pointer) bool {
|
||||
return *(*int32)(p) == *(*int32)(q)
|
||||
}
|
||||
func memequal64(p, q unsafe.Pointer, size uintptr) bool {
|
||||
func memequal64(p, q unsafe.Pointer) bool {
|
||||
return *(*int64)(p) == *(*int64)(q)
|
||||
}
|
||||
func memequal128(p, q unsafe.Pointer, size uintptr) bool {
|
||||
func memequal128(p, q unsafe.Pointer) bool {
|
||||
return *(*[2]int64)(p) == *(*[2]int64)(q)
|
||||
}
|
||||
func f32equal(p, q unsafe.Pointer, size uintptr) bool {
|
||||
func f32equal(p, q unsafe.Pointer) bool {
|
||||
return *(*float32)(p) == *(*float32)(q)
|
||||
}
|
||||
func f64equal(p, q unsafe.Pointer, size uintptr) bool {
|
||||
func f64equal(p, q unsafe.Pointer) bool {
|
||||
return *(*float64)(p) == *(*float64)(q)
|
||||
}
|
||||
func c64equal(p, q unsafe.Pointer, size uintptr) bool {
|
||||
func c64equal(p, q unsafe.Pointer) bool {
|
||||
return *(*complex64)(p) == *(*complex64)(q)
|
||||
}
|
||||
func c128equal(p, q unsafe.Pointer, size uintptr) bool {
|
||||
func c128equal(p, q unsafe.Pointer) bool {
|
||||
return *(*complex128)(p) == *(*complex128)(q)
|
||||
}
|
||||
func strequal(p, q unsafe.Pointer, size uintptr) bool {
|
||||
func strequal(p, q unsafe.Pointer) bool {
|
||||
return *(*string)(p) == *(*string)(q)
|
||||
}
|
||||
func interequal(p, q unsafe.Pointer, size uintptr) bool {
|
||||
func interequal(p, q unsafe.Pointer) bool {
|
||||
return ifaceeq(*(*interface {
|
||||
f()
|
||||
})(p), *(*interface {
|
||||
f()
|
||||
})(q))
|
||||
}
|
||||
func nilinterequal(p, q unsafe.Pointer, size uintptr) bool {
|
||||
func nilinterequal(p, q unsafe.Pointer) bool {
|
||||
return efaceeq(*(*interface{})(p), *(*interface{})(q))
|
||||
}
|
||||
func efaceeq(p, q interface{}) bool {
|
||||
|
|
@ -224,9 +248,9 @@ func efaceeq(p, q interface{}) bool {
|
|||
panic(errorString("comparing uncomparable type " + *t._string))
|
||||
}
|
||||
if isDirectIface(t) {
|
||||
return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)), uintptr(t.size))
|
||||
return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)))
|
||||
}
|
||||
return eq(x.data, y.data, uintptr(t.size))
|
||||
return eq(x.data, y.data)
|
||||
}
|
||||
func ifaceeq(p, q interface {
|
||||
f()
|
||||
|
|
@ -246,37 +270,37 @@ func ifaceeq(p, q interface {
|
|||
panic(errorString("comparing uncomparable type " + *t._string))
|
||||
}
|
||||
if isDirectIface(t) {
|
||||
return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)), uintptr(t.size))
|
||||
return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)))
|
||||
}
|
||||
return eq(x.data, y.data, uintptr(t.size))
|
||||
return eq(x.data, y.data)
|
||||
}
|
||||
|
||||
// Testing adapters for hash quality tests (see hash_test.go)
|
||||
func stringHash(s string, seed uintptr) uintptr {
|
||||
return algarray[alg_STRING].hash(noescape(unsafe.Pointer(&s)), unsafe.Sizeof(s), seed)
|
||||
return algarray[alg_STRING].hash(noescape(unsafe.Pointer(&s)), seed)
|
||||
}
|
||||
|
||||
func bytesHash(b []byte, seed uintptr) uintptr {
|
||||
s := (*sliceStruct)(unsafe.Pointer(&b))
|
||||
return algarray[alg_MEM].hash(s.array, uintptr(s.len), seed)
|
||||
return memhash(s.array, seed, uintptr(s.len))
|
||||
}
|
||||
|
||||
func int32Hash(i uint32, seed uintptr) uintptr {
|
||||
return algarray[alg_MEM32].hash(noescape(unsafe.Pointer(&i)), 4, seed)
|
||||
return algarray[alg_MEM32].hash(noescape(unsafe.Pointer(&i)), seed)
|
||||
}
|
||||
|
||||
func int64Hash(i uint64, seed uintptr) uintptr {
|
||||
return algarray[alg_MEM64].hash(noescape(unsafe.Pointer(&i)), 8, seed)
|
||||
return algarray[alg_MEM64].hash(noescape(unsafe.Pointer(&i)), seed)
|
||||
}
|
||||
|
||||
func efaceHash(i interface{}, seed uintptr) uintptr {
|
||||
return algarray[alg_NILINTER].hash(noescape(unsafe.Pointer(&i)), unsafe.Sizeof(i), seed)
|
||||
return algarray[alg_NILINTER].hash(noescape(unsafe.Pointer(&i)), seed)
|
||||
}
|
||||
|
||||
func ifaceHash(i interface {
|
||||
F()
|
||||
}, seed uintptr) uintptr {
|
||||
return algarray[alg_INTER].hash(noescape(unsafe.Pointer(&i)), unsafe.Sizeof(i), seed)
|
||||
return algarray[alg_INTER].hash(noescape(unsafe.Pointer(&i)), seed)
|
||||
}
|
||||
|
||||
// Testing adapter for memclr
|
||||
|
|
@ -301,12 +325,8 @@ func init() {
|
|||
cpuid_ecx&(1<<9) != 0 && // sse3 (pshufb)
|
||||
cpuid_ecx&(1<<19) != 0 { // sse4.1 (pinsr{d,q})
|
||||
useAeshash = true
|
||||
algarray[alg_MEM].hash = aeshash
|
||||
algarray[alg_MEM8].hash = aeshash
|
||||
algarray[alg_MEM16].hash = aeshash
|
||||
algarray[alg_MEM32].hash = aeshash32
|
||||
algarray[alg_MEM64].hash = aeshash64
|
||||
algarray[alg_MEM128].hash = aeshash
|
||||
algarray[alg_STRING].hash = aeshashstr
|
||||
// Initialize with random data so hash collisions will be hard to engineer.
|
||||
getRandomData(aeskeysched[:])
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ const (
|
|||
thechar = '9'
|
||||
_BigEndian = 1
|
||||
_CacheLineSize = 64
|
||||
_RuntimeGogoBytes = 64
|
||||
_RuntimeGogoBytes = 72
|
||||
_PhysPageSize = 65536
|
||||
_PCQuantum = 4
|
||||
_Int64Align = 8
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ const (
|
|||
thechar = '9'
|
||||
_BigEndian = 0
|
||||
_CacheLineSize = 64
|
||||
_RuntimeGogoBytes = 64
|
||||
_RuntimeGogoBytes = 72
|
||||
_PhysPageSize = 65536
|
||||
_PCQuantum = 4
|
||||
_Int64Align = 8
|
||||
|
|
|
|||
|
|
@ -451,7 +451,7 @@ TEXT runtime·cas(SB), NOSPLIT, $0-13
|
|||
MOVL new+8(FP), CX
|
||||
LOCK
|
||||
CMPXCHGL CX, 0(BX)
|
||||
SETEQ , ret+12(FP)
|
||||
SETEQ ret+12(FP)
|
||||
RET
|
||||
|
||||
TEXT runtime·casuintptr(SB), NOSPLIT, $0-13
|
||||
|
|
@ -482,7 +482,7 @@ TEXT runtime·cas64(SB), NOSPLIT, $0-21
|
|||
MOVL new_hi+16(FP), CX
|
||||
LOCK
|
||||
CMPXCHG8B 0(BP)
|
||||
SETEQ , ret+20(FP)
|
||||
SETEQ ret+20(FP)
|
||||
RET
|
||||
|
||||
// bool casp(void **p, void *old, void *new)
|
||||
|
|
@ -498,7 +498,7 @@ TEXT runtime·casp1(SB), NOSPLIT, $0-13
|
|||
MOVL new+8(FP), CX
|
||||
LOCK
|
||||
CMPXCHGL CX, 0(BX)
|
||||
SETEQ , ret+12(FP)
|
||||
SETEQ ret+12(FP)
|
||||
RET
|
||||
|
||||
// uint32 xadd(uint32 volatile *val, int32 delta)
|
||||
|
|
@ -887,23 +887,42 @@ TEXT runtime·emptyfunc(SB),0,$0-0
|
|||
TEXT runtime·abort(SB),NOSPLIT,$0-0
|
||||
INT $0x3
|
||||
|
||||
// memhash_varlen(p unsafe.Pointer, h seed) uintptr
|
||||
// redirects to memhash(p, h, size) using the size
|
||||
// stored in the closure.
|
||||
TEXT runtime·memhash_varlen(SB),NOSPLIT,$16-12
|
||||
GO_ARGS
|
||||
NO_LOCAL_POINTERS
|
||||
MOVL p+0(FP), AX
|
||||
MOVL h+4(FP), BX
|
||||
MOVL 4(DX), CX
|
||||
MOVL AX, 0(SP)
|
||||
MOVL BX, 4(SP)
|
||||
MOVL CX, 8(SP)
|
||||
CALL runtime·memhash(SB)
|
||||
MOVL 12(SP), AX
|
||||
MOVL AX, ret+8(FP)
|
||||
RET
|
||||
|
||||
// hash function using AES hardware instructions
|
||||
TEXT runtime·aeshash(SB),NOSPLIT,$0-16
|
||||
MOVL p+0(FP), AX // ptr to data
|
||||
MOVL s+4(FP), CX // size
|
||||
MOVL s+8(FP), CX // size
|
||||
LEAL ret+12(FP), DX
|
||||
JMP runtime·aeshashbody(SB)
|
||||
|
||||
TEXT runtime·aeshashstr(SB),NOSPLIT,$0-16
|
||||
TEXT runtime·aeshashstr(SB),NOSPLIT,$0-12
|
||||
MOVL p+0(FP), AX // ptr to string object
|
||||
// s+4(FP) is ignored, it is always sizeof(String)
|
||||
MOVL 4(AX), CX // length of string
|
||||
MOVL (AX), AX // string data
|
||||
LEAL ret+8(FP), DX
|
||||
JMP runtime·aeshashbody(SB)
|
||||
|
||||
// AX: data
|
||||
// CX: length
|
||||
TEXT runtime·aeshashbody(SB),NOSPLIT,$0-16
|
||||
MOVL h+8(FP), X6 // seed to low 64 bits of xmm6
|
||||
// DX: address to put return value
|
||||
TEXT runtime·aeshashbody(SB),NOSPLIT,$0-0
|
||||
MOVL h+4(FP), X6 // seed to low 64 bits of xmm6
|
||||
PINSRD $2, CX, X6 // size to high 64 bits of xmm6
|
||||
PSHUFHW $0, X6, X6 // replace size with its low 2 bytes repeated 4 times
|
||||
MOVO runtime·aeskeysched(SB), X7
|
||||
|
|
@ -934,7 +953,7 @@ aes0to15:
|
|||
AESENC X6, X0
|
||||
AESENC X7, X0
|
||||
AESENC X7, X0
|
||||
MOVL X0, ret+12(FP)
|
||||
MOVL X0, (DX)
|
||||
RET
|
||||
|
||||
endofpage:
|
||||
|
|
@ -947,13 +966,13 @@ endofpage:
|
|||
AESENC X6, X0
|
||||
AESENC X7, X0
|
||||
AESENC X7, X0
|
||||
MOVL X0, ret+12(FP)
|
||||
MOVL X0, (DX)
|
||||
RET
|
||||
|
||||
aes0:
|
||||
// return input seed
|
||||
MOVL h+8(FP), AX
|
||||
MOVL AX, ret+12(FP)
|
||||
MOVL h+4(FP), AX
|
||||
MOVL AX, (DX)
|
||||
RET
|
||||
|
||||
aes16:
|
||||
|
|
@ -961,7 +980,7 @@ aes16:
|
|||
AESENC X6, X0
|
||||
AESENC X7, X0
|
||||
AESENC X7, X0
|
||||
MOVL X0, ret+12(FP)
|
||||
MOVL X0, (DX)
|
||||
RET
|
||||
|
||||
|
||||
|
|
@ -980,7 +999,7 @@ aes17to32:
|
|||
|
||||
// combine results
|
||||
PXOR X1, X0
|
||||
MOVL X0, ret+12(FP)
|
||||
MOVL X0, (DX)
|
||||
RET
|
||||
|
||||
aes33to64:
|
||||
|
|
@ -1005,7 +1024,7 @@ aes33to64:
|
|||
PXOR X2, X0
|
||||
PXOR X3, X1
|
||||
PXOR X1, X0
|
||||
MOVL X0, ret+12(FP)
|
||||
MOVL X0, (DX)
|
||||
RET
|
||||
|
||||
aes65plus:
|
||||
|
|
@ -1059,29 +1078,27 @@ aesloop:
|
|||
PXOR X2, X0
|
||||
PXOR X3, X1
|
||||
PXOR X1, X0
|
||||
MOVL X0, ret+12(FP)
|
||||
MOVL X0, (DX)
|
||||
RET
|
||||
|
||||
TEXT runtime·aeshash32(SB),NOSPLIT,$0-16
|
||||
TEXT runtime·aeshash32(SB),NOSPLIT,$0-12
|
||||
MOVL p+0(FP), AX // ptr to data
|
||||
// s+4(FP) is ignored, it is always sizeof(int32)
|
||||
MOVL h+8(FP), X0 // seed
|
||||
MOVL h+4(FP), X0 // seed
|
||||
PINSRD $1, (AX), X0 // data
|
||||
AESENC runtime·aeskeysched+0(SB), X0
|
||||
AESENC runtime·aeskeysched+16(SB), X0
|
||||
AESENC runtime·aeskeysched+32(SB), X0
|
||||
MOVL X0, ret+12(FP)
|
||||
MOVL X0, ret+8(FP)
|
||||
RET
|
||||
|
||||
TEXT runtime·aeshash64(SB),NOSPLIT,$0-16
|
||||
TEXT runtime·aeshash64(SB),NOSPLIT,$0-12
|
||||
MOVL p+0(FP), AX // ptr to data
|
||||
// s+4(FP) is ignored, it is always sizeof(int64)
|
||||
MOVQ (AX), X0 // data
|
||||
PINSRD $2, h+8(FP), X0 // seed
|
||||
PINSRD $2, h+4(FP), X0 // seed
|
||||
AESENC runtime·aeskeysched+0(SB), X0
|
||||
AESENC runtime·aeskeysched+16(SB), X0
|
||||
AESENC runtime·aeskeysched+32(SB), X0
|
||||
MOVL X0, ret+12(FP)
|
||||
MOVL X0, ret+8(FP)
|
||||
RET
|
||||
|
||||
// simple mask to get rid of data in the high part of the register.
|
||||
|
|
@ -1260,6 +1277,20 @@ TEXT runtime·memeq(SB),NOSPLIT,$0-13
|
|||
MOVB AX, ret+12(FP)
|
||||
RET
|
||||
|
||||
// memequal_varlen(a, b unsafe.Pointer) bool
|
||||
TEXT runtime·memequal_varlen(SB),NOSPLIT,$0-9
|
||||
MOVL a+0(FP), SI
|
||||
MOVL b+4(FP), DI
|
||||
CMPL SI, DI
|
||||
JEQ eq
|
||||
MOVL 4(DX), BX // compiler stores size at offset 4 in the closure
|
||||
CALL runtime·memeqbody(SB)
|
||||
MOVB AX, ret+8(FP)
|
||||
RET
|
||||
eq:
|
||||
MOVB $1, ret+8(FP)
|
||||
RET
|
||||
|
||||
// eqstring tests whether two strings are equal.
|
||||
// See runtime_test.go:eqstring_generic for
|
||||
// equivalent Go code.
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue