diff --git a/doc/asm.html b/doc/asm.html
index f2f8fad576..debb1e2fc6 100644
--- a/doc/asm.html
+++ b/doc/asm.html
@@ -740,6 +740,7 @@ The ARM64 port is in an experimental state.
R18 is the "platform register", reserved on the Apple platform.
+To prevent accidental misuse, the register is named R18_PLATFORM.
R27 and R28 are reserved by the compiler and linker.
R29 is the frame pointer.
R30 is the link register.
diff --git a/misc/cgo/test/cgo_test.go b/misc/cgo/test/cgo_test.go
index ccacc50fe1..ae856a37d6 100644
--- a/misc/cgo/test/cgo_test.go
+++ b/misc/cgo/test/cgo_test.go
@@ -92,6 +92,7 @@ func Test25143(t *testing.T) { test25143(t) }
func Test23356(t *testing.T) { test23356(t) }
func Test26066(t *testing.T) { test26066(t) }
func Test26213(t *testing.T) { test26213(t) }
+func Test27660(t *testing.T) { test27660(t) }
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
func BenchmarkGoString(b *testing.B) { benchGoString(b) }
diff --git a/misc/cgo/test/test27660.go b/misc/cgo/test/test27660.go
new file mode 100644
index 0000000000..8c23b7dc58
--- /dev/null
+++ b/misc/cgo/test/test27660.go
@@ -0,0 +1,54 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Stress the interaction between the race detector and cgo in an
+// attempt to reproduce the memory corruption described in #27660.
+// The bug was very timing sensitive; at the time of writing this
+// test would only trigger the bug about once out of every five runs.
+
+package cgotest
+
+// #include
+import "C"
+
+import (
+ "context"
+ "math/rand"
+ "runtime"
+ "sync"
+ "testing"
+ "time"
+)
+
+func test27660(t *testing.T) {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ ints := make([]int, 100)
+ locks := make([]sync.Mutex, 100)
+ // Slowly create threads so that ThreadSanitizer is forced to
+ // frequently resize its SyncClocks.
+ for i := 0; i < 100; i++ {
+ go func() {
+ for ctx.Err() == nil {
+ // Sleep in C for long enough that it is likely that the runtime
+ // will retake this goroutine's currently wired P.
+ C.usleep(1000 /* 1ms */)
+ runtime.Gosched() // avoid starvation (see #28701)
+ }
+ }()
+ go func() {
+ // Trigger lots of synchronization and memory reads/writes to
+ // increase the likelihood that the race described in #27660
+ // results in corruption of ThreadSanitizer's internal state
+ // and thus an assertion failure or segfault.
+ for ctx.Err() == nil {
+ j := rand.Intn(100)
+ locks[j].Lock()
+ ints[j]++
+ locks[j].Unlock()
+ }
+ }()
+ time.Sleep(time.Millisecond)
+ }
+}
diff --git a/misc/nacl/testzip.proto b/misc/nacl/testzip.proto
index 7f524cac48..c2afa1020a 100644
--- a/misc/nacl/testzip.proto
+++ b/misc/nacl/testzip.proto
@@ -50,6 +50,9 @@ go src=..
google
pprof
internal
+ binutils
+ testdata
+ +
driver
testdata
+
diff --git a/misc/wasm/wasm_exec.js b/misc/wasm/wasm_exec.js
index e47663783e..440bba104c 100644
--- a/misc/wasm/wasm_exec.js
+++ b/misc/wasm/wasm_exec.js
@@ -79,6 +79,10 @@
console.warn("exit code:", code);
}
};
+ this._exitPromise = new Promise((resolve) => {
+ this._resolveExitPromise = resolve;
+ });
+ this._pendingCallback = null;
this._callbackTimeouts = new Map();
this._nextCallbackTimeoutID = 1;
@@ -194,6 +198,11 @@
const timeOrigin = Date.now() - performance.now();
this.importObject = {
go: {
+ // Go's SP does not change as long as no Go code is running. Some operations (e.g. calls, getters and setters)
+ // may trigger a synchronous callback to Go. This makes Go code get executed in the middle of the imported
+ // function. A goroutine can switch to a new stack if the current stack is too small (see morestack function).
+ // This changes the SP, thus we have to update the SP used by the imported function.
+
// func wasmExit(code int32)
"runtime.wasmExit": (sp) => {
const code = mem().getInt32(sp + 8, true);
@@ -229,7 +238,7 @@
const id = this._nextCallbackTimeoutID;
this._nextCallbackTimeoutID++;
this._callbackTimeouts.set(id, setTimeout(
- () => { this._resolveCallbackPromise(); },
+ () => { this._resume(); },
getInt64(sp + 8) + 1, // setTimeout has been seen to fire up to 1 millisecond early
));
mem().setInt32(sp + 16, id, true);
@@ -254,7 +263,9 @@
// func valueGet(v ref, p string) ref
"syscall/js.valueGet": (sp) => {
- storeValue(sp + 32, Reflect.get(loadValue(sp + 8), loadString(sp + 16)));
+ const result = Reflect.get(loadValue(sp + 8), loadString(sp + 16));
+ sp = this._inst.exports.getsp(); // see comment above
+ storeValue(sp + 32, result);
},
// func valueSet(v ref, p string, x ref)
@@ -278,7 +289,9 @@
const v = loadValue(sp + 8);
const m = Reflect.get(v, loadString(sp + 16));
const args = loadSliceOfValues(sp + 32);
- storeValue(sp + 56, Reflect.apply(m, v, args));
+ const result = Reflect.apply(m, v, args);
+ sp = this._inst.exports.getsp(); // see comment above
+ storeValue(sp + 56, result);
mem().setUint8(sp + 64, 1);
} catch (err) {
storeValue(sp + 56, err);
@@ -291,7 +304,9 @@
try {
const v = loadValue(sp + 8);
const args = loadSliceOfValues(sp + 16);
- storeValue(sp + 40, Reflect.apply(v, undefined, args));
+ const result = Reflect.apply(v, undefined, args);
+ sp = this._inst.exports.getsp(); // see comment above
+ storeValue(sp + 40, result);
mem().setUint8(sp + 48, 1);
} catch (err) {
storeValue(sp + 40, err);
@@ -304,7 +319,9 @@
try {
const v = loadValue(sp + 8);
const args = loadSliceOfValues(sp + 16);
- storeValue(sp + 40, Reflect.construct(v, args));
+ const result = Reflect.construct(v, args);
+ sp = this._inst.exports.getsp(); // see comment above
+ storeValue(sp + 40, result);
mem().setUint8(sp + 48, 1);
} catch (err) {
storeValue(sp + 40, err);
@@ -355,7 +372,6 @@
this,
];
this._refs = new Map();
- this._callbackShutdown = false;
this.exited = false;
const mem = new DataView(this._inst.exports.mem.buffer)
@@ -390,42 +406,30 @@
offset += 8;
});
- while (true) {
- const callbackPromise = new Promise((resolve) => {
- this._resolveCallbackPromise = () => {
- if (this.exited) {
- throw new Error("bad callback: Go program has already exited");
- }
- setTimeout(resolve, 0); // make sure it is asynchronous
- };
- });
- this._inst.exports.run(argc, argv);
- if (this.exited) {
- break;
- }
- await callbackPromise;
+ this._inst.exports.run(argc, argv);
+ if (this.exited) {
+ this._resolveExitPromise();
+ }
+ await this._exitPromise;
+ }
+
+ _resume() {
+ if (this.exited) {
+ throw new Error("bad callback: Go program has already exited");
+ }
+ this._inst.exports.resume();
+ if (this.exited) {
+ this._resolveExitPromise();
}
}
- static _makeCallbackHelper(id, pendingCallbacks, go) {
+ _makeCallbackHelper(id) {
+ const go = this;
return function () {
- pendingCallbacks.push({ id: id, args: arguments });
- go._resolveCallbackPromise();
- };
- }
-
- static _makeEventCallbackHelper(preventDefault, stopPropagation, stopImmediatePropagation, fn) {
- return function (event) {
- if (preventDefault) {
- event.preventDefault();
- }
- if (stopPropagation) {
- event.stopPropagation();
- }
- if (stopImmediatePropagation) {
- event.stopImmediatePropagation();
- }
- fn(event);
+ const cb = { id: id, this: this, args: arguments };
+ go._pendingCallback = cb;
+ go._resume();
+ return cb.result;
};
}
}
@@ -444,8 +448,8 @@
process.on("exit", (code) => { // Node.js exits if no callback is pending
if (code === 0 && !go.exited) {
// deadlock, make Go print error and stack traces
- go._callbackShutdown = true;
- go._inst.exports.run();
+ go._pendingCallback = { id: 0 };
+ go._resume();
}
});
return go.run(result.instance);
diff --git a/src/bufio/bufio_test.go b/src/bufio/bufio_test.go
index c829d2b064..34d70312f7 100644
--- a/src/bufio/bufio_test.go
+++ b/src/bufio/bufio_test.go
@@ -550,7 +550,7 @@ func TestWriter(t *testing.T) {
t.Errorf("%s: %d bytes written", context, len(written))
}
for l := 0; l < len(written); l++ {
- if written[i] != data[i] {
+ if written[l] != data[l] {
t.Errorf("wrong bytes written")
t.Errorf("want=%q", data[0:len(written)])
t.Errorf("have=%q", written)
diff --git a/src/bytes/bytes.go b/src/bytes/bytes.go
index 6492db088a..daf4a32f26 100644
--- a/src/bytes/bytes.go
+++ b/src/bytes/bytes.go
@@ -12,6 +12,13 @@ import (
"unicode/utf8"
)
+// Equal returns a boolean reporting whether a and b
+// are the same length and contain the same bytes.
+// A nil argument is equivalent to an empty slice.
+func Equal(a, b []byte) bool {
+ return bytealg.Equal(a, b)
+}
+
func equalPortable(a, b []byte) bool {
if len(a) != len(b) {
return false
@@ -24,6 +31,13 @@ func equalPortable(a, b []byte) bool {
return true
}
+// Compare returns an integer comparing two byte slices lexicographically.
+// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
+// A nil argument is equivalent to an empty slice.
+func Compare(a, b []byte) int {
+ return bytealg.Compare(a, b)
+}
+
// explode splits s into a slice of UTF-8 sequences, one per Unicode code point (still slices of bytes),
// up to a maximum of n byte slices. Invalid UTF-8 sequences are chopped into individual bytes.
func explode(s []byte, n int) [][]byte {
@@ -83,6 +97,11 @@ func ContainsRune(b []byte, r rune) bool {
return IndexRune(b, r) >= 0
}
+// IndexByte returns the index of the first instance of c in b, or -1 if c is not present in b.
+func IndexByte(b []byte, c byte) int {
+ return bytealg.IndexByte(b, c)
+}
+
func indexBytePortable(s []byte, c byte) int {
for i, b := range s {
if b == c {
diff --git a/src/bytes/bytes_decl.go b/src/bytes/bytes_decl.go
deleted file mode 100644
index af0f8b179f..0000000000
--- a/src/bytes/bytes_decl.go
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2010 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 bytes
-
-//go:noescape
-
-// IndexByte returns the index of the first instance of c in b, or -1 if c is not present in b.
-func IndexByte(b []byte, c byte) int // in internal/bytealg
-
-//go:noescape
-
-// Equal returns a boolean reporting whether a and b
-// are the same length and contain the same bytes.
-// A nil argument is equivalent to an empty slice.
-func Equal(a, b []byte) bool // in internal/bytealg
-
-//go:noescape
-
-// Compare returns an integer comparing two byte slices lexicographically.
-// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
-// A nil argument is equivalent to an empty slice.
-func Compare(a, b []byte) int // in internal/bytealg
diff --git a/src/cmd/addr2line/main.go b/src/cmd/addr2line/main.go
index 267f4170a8..018802940b 100644
--- a/src/cmd/addr2line/main.go
+++ b/src/cmd/addr2line/main.go
@@ -61,6 +61,7 @@ func main() {
if err != nil {
log.Fatal(err)
}
+ defer f.Close()
tab, err := f.PCLineTable()
if err != nil {
diff --git a/src/cmd/asm/internal/arch/arch.go b/src/cmd/asm/internal/arch/arch.go
index ecea6ba97d..eaa5cb8958 100644
--- a/src/cmd/asm/internal/arch/arch.go
+++ b/src/cmd/asm/internal/arch/arch.go
@@ -258,6 +258,9 @@ func archArm64() *Arch {
for i := arm64.REG_R0; i <= arm64.REG_R31; i++ {
register[obj.Rconv(i)] = int16(i)
}
+ // Rename R18 to R18_PLATFORM to avoid accidental use.
+ register["R18_PLATFORM"] = register["R18"]
+ delete(register, "R18")
for i := arm64.REG_F0; i <= arm64.REG_F31; i++ {
register[obj.Rconv(i)] = int16(i)
}
diff --git a/src/cmd/asm/internal/asm/operand_test.go b/src/cmd/asm/internal/asm/operand_test.go
index df60b71ebd..69393b6b20 100644
--- a/src/cmd/asm/internal/asm/operand_test.go
+++ b/src/cmd/asm/internal/asm/operand_test.go
@@ -607,6 +607,7 @@ var arm64OperandTests = []operandTest{
{"R0", "R0"},
{"R10", "R10"},
{"R11", "R11"},
+ {"R18_PLATFORM", "R18"},
{"$4503601774854144.0", "$(4503601774854144.0)"},
{"$runtime·badsystemstack(SB)", "$runtime.badsystemstack(SB)"},
{"ZR", "ZR"},
diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s
index 12c7adbd04..d025543e6d 100644
--- a/src/cmd/asm/internal/asm/testdata/arm64.s
+++ b/src/cmd/asm/internal/asm/testdata/arm64.s
@@ -47,8 +47,8 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
ADD R2.SXTX<<1, RSP, RSP // ffe7228b
ADD ZR.SXTX<<1, R2, R3 // 43e43f8b
ADDW R2.SXTW, R10, R12 // 4cc1220b
- ADD R18.UXTX, R14, R17 // d161328b
- ADDSW R18.UXTW, R14, R17 // d141322b
+ ADD R19.UXTX, R14, R17 // d161338b
+ ADDSW R19.UXTW, R14, R17 // d141332b
ADDS R12.SXTX, R3, R1 // 61e02cab
SUB R19.UXTH<<4, R2, R21 // 553033cb
SUBW R1.UXTX<<1, R3, R2 // 6264214b
@@ -144,7 +144,7 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
MOVD (R2)(R6.SXTW), R4 // 44c866f8
MOVD (R3)(R6), R5 // MOVD (R3)(R6*1), R5 // 656866f8
MOVD (R2)(R6), R4 // MOVD (R2)(R6*1), R4 // 446866f8
- MOVWU (R19)(R18<<2), R18 // 727a72b8
+ MOVWU (R19)(R20<<2), R20 // 747a74b8
MOVD (R2)(R6<<3), R4 // 447866f8
MOVD (R3)(R7.SXTX<<3), R8 // 68f867f8
MOVWU (R5)(R4.UXTW), R10 // aa4864b8
@@ -154,7 +154,7 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
MOVHU (R1)(R2<<1), R5 // 25786278
MOVB (R9)(R3.UXTW), R6 // 2649a338
MOVB (R10)(R6), R15 // MOVB (R10)(R6*1), R15 // 4f69a638
- MOVH (R5)(R7.SXTX<<1), R18 // b2f8a778
+ MOVH (R5)(R7.SXTX<<1), R19 // b3f8a778
MOVH (R8)(R4<<1), R10 // 0a79a478
MOVW (R9)(R8.SXTW<<2), R19 // 33d9a8b8
MOVW (R1)(R4.SXTX), R11 // 2be8a4b8
@@ -195,6 +195,11 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
CMPW $27745, R2 // 3b8c8d525f001b6b
CMNW $0x3fffffc0, R2 // CMNW $1073741760, R2 // fb5f1a325f001b2b
CMPW $0xffff0, R1 // CMPW $1048560, R1 // fb3f1c323f001b6b
+ CMP $0xffffffffffa0, R3 // CMP $281474976710560, R3 // fb0b80921b00e0f27f001beb
+ CMP $0xf4240, R1 // CMP $1000000, R1 // 1b4888d2fb01a0f23f001beb
+ ADD $0x186a0, R2, R5 // ADD $100000, R2, R5 // 45801a91a5604091
+ SUB $0xe7791f700, R3, R1 // SUB $62135596800, R3, R1 // 1be09ed23bf2aef2db01c0f261001bcb
+ CMP $3343198598084851058, R3 // 5bae8ed2db8daef23badcdf2bbcce5f27f001beb
ADD $0x3fffffffc000, R5 // ADD $70368744161280, R5 // fb7f72b2a5001b8b
// LTYPE1 imsr ',' spreg ','
// {
@@ -222,6 +227,13 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
EOR $(1<<63), R1 // EOR $-9223372036854775808, R1 // 210041d2
EOR $(1<<63-1), R1 // EOR $9223372036854775807, R1 // 21f840d2
+ ANDW $0x3ff00000, R2 // ANDW $1072693248, R2 // 42240c12
+ BICW $0x3ff00000, R2 // BICW $1072693248, R2 // 42540212
+ ORRW $0x3ff00000, R2 // ORRW $1072693248, R2 // 42240c32
+ ORNW $0x3ff00000, R2 // ORNW $1072693248, R2 // 42540232
+ EORW $0x3ff00000, R2 // EORW $1072693248, R2 // 42240c52
+ EONW $0x3ff00000, R2 // EONW $1072693248, R2 // 42540252
+
AND $0x22220000, R3, R4 // AND $572653568, R3, R4 // 5b44a4d264001b8a
ORR $0x22220000, R3, R4 // ORR $572653568, R3, R4 // 5b44a4d264001baa
EOR $0x22220000, R3, R4 // EOR $572653568, R3, R4 // 5b44a4d264001bca
@@ -233,12 +245,21 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
EOR $0xe03fffffffffffff, R20, R22 // EOR $-2287828610704211969, R20, R22 // 96e243d2
TSTW $0x600000006, R1 // TSTW $25769803782, R1 // 3f041f72
+ TST $0x4900000049, R0 // TST $313532612681, R0 // 3b0980d23b09c0f21f001bea
+ ORR $0x170000, R2, R1 // ORR $1507328, R2, R1 // fb02a0d241001baa
+ AND $0xff00ff, R2 // AND $16711935, R2 // fb1f80d2fb1fa0f242001b8a
+ AND $0xff00ffff, R1 // AND $4278255615, R1 // fbff9fd21be0bff221001b8a
ANDS $0xffff, R2 // ANDS $65535, R2 // 423c40f2
AND $0x7fffffff, R3 // AND $2147483647, R3 // 63784092
ANDS $0x0ffffffff80000000, R2 // ANDS $-2147483648, R2 // 428061f2
AND $0xfffff, R2 // AND $1048575, R2 // 424c4092
ANDW $0xf00fffff, R1 // ANDW $4027580415, R1 // 215c0412
ANDSW $0xff00ffff, R1 // ANDSW $4278255615, R1 // 215c0872
+ TST $0x11223344, R2 // TST $287454020, R2 // 9b6886d25b24a2f25f001bea
+ TSTW $0xa000, R3 // TSTW $40960, R3 // 1b0094527f001b6a
+ BICW $0xa000, R3 // BICW $40960, R3 // 1b00945263003b0a
+ ORRW $0x1b000, R2, R3 // ORRW $110592, R2, R3 // 1b0096523b00a07243001b2a
+ TSTW $0x500000, R1 // TSTW $5242880, R1 // 1b0aa0523f001b6a
TSTW $0xff00ff, R1 // TSTW $16711935, R1 // 3f9c0072
AND $8, R0, RSP // 1f007d92
@@ -249,13 +270,20 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
EON $8, R0, RSP // 1ff87cd2
MOVD $0x3fffffffc000, R0 // MOVD $70368744161280, R0 // e07f72b2
+ MOVW $1000000, R4 // 04488852e401a072
MOVW $0xaaaa0000, R1 // MOVW $2863267840, R1 // 4155b552
MOVW $0xaaaaffff, R1 // MOVW $2863333375, R1 // a1aaaa12
MOVW $0xaaaa, R1 // MOVW $43690, R1 // 41559552
MOVW $0xffffaaaa, R1 // MOVW $4294945450, R1 // a1aa8a12
MOVW $0xffff0000, R1 // MOVW $4294901760, R1 // e1ffbf52
MOVD $0xffff00000000000, R1 // MOVD $1152903912420802560, R1 // e13f54b2
+ MOVD $0x1111000000001111, R1 // MOVD $1229764173248860433, R1 // 212282d22122e2f2
+ MOVD $0x1111ffff1111ffff, R1 // MOVD $1230045644216991743, R1 // c1ddbd922122e2f2
+ MOVD $0x1111222233334444, R1 // MOVD $1229801703532086340, R1 // 818888d26166a6f24144c4f22122e2f2
+ MOVD $0xaaaaffff, R1 // MOVD $2863333375, R1 // e1ff9fd24155b5f2
MOVD $0x11110000, R1 // MOVD $286326784, R1 // 2122a2d2
+ MOVD $0xaaaa0000aaaa1111, R1 // MOVD $-6149102338357718767, R1 // 212282d24155b5f24155f5f2
+ MOVD $0x1111ffff1111aaaa, R1 // MOVD $1230045644216969898, R1 // a1aa8a922122a2f22122e2f2
MOVD $0, R1 // 010080d2
MOVD $-1, R1 // 01008092
MOVD $0x210000, R0 // MOVD $2162688, R0 // 2004a0d2
diff --git a/src/cmd/asm/internal/asm/testdata/arm64enc.s b/src/cmd/asm/internal/asm/testdata/arm64enc.s
index 432ab74493..a2850e2e46 100644
--- a/src/cmd/asm/internal/asm/testdata/arm64enc.s
+++ b/src/cmd/asm/internal/asm/testdata/arm64enc.s
@@ -56,7 +56,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
BFXILW $3, R27, $23, R14 // 6e670333
BFXIL $26, R8, $16, R20 // 14a55ab3
BICW R7@>15, R5, R16 // b03ce70a
- BIC R12@>13, R12, R18 // 9235ec8a
+ BIC R12@>13, R12, R19 // 9335ec8a
BICSW R25->20, R3, R20 // 7450b96a
BICS R19->12, R1, R23 // 3730b3ea
BICS R19, R1, R23 // 370033ea
@@ -76,7 +76,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
CCMN LE, R30, R12, $6 // c6d34cba
CCMPW VS, R29, $15, $7 // a76b4f7a
CCMP LE, R7, $19, $3 // e3d853fa
- CCMPW HS, R18, R6, $0 // 4022467a
+ CCMPW HS, R19, R6, $0 // 6022467a
CCMP LT, R30, R6, $7 // c7b346fa
CCMN MI, ZR, R1, $4 // e44341ba
CSINCW HS, ZR, R27, R14 // ee279b1a
@@ -118,7 +118,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
CRC32H R3, R21, R27 // bb46c31a
CRC32W R22, R30, R9 // c94bd61a
CRC32X R20, R4, R15 // 8f4cd49a
- CRC32CB R18, R27, R22 // 7653d21a
+ CRC32CB R19, R27, R22 // 7653d31a
CRC32CH R21, R0, R20 // 1454d51a
CRC32CW R9, R3, R21 // 7558c91a
CRC32CX R11, R0, R24 // 185ccb9a
@@ -133,7 +133,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
CSINVW AL, R23, R21, R5 // e5e2955a
CSINV LO, R2, R11, R14 // 4e308bda
CSNEGW HS, R16, R29, R10 // 0a269d5a
- CSNEG NE, R21, R18, R11 // ab1692da
+ CSNEG NE, R21, R19, R11 // ab1693da
//TODO DC
DCPS1 $11378 // 418ea5d4
DCPS2 $10699 // 6239a5d4
@@ -185,23 +185,23 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
MOVBU.P 42(R2), R12 // 4ca44238
MOVBU.W -27(R2), R14 // 4e5c5e38
MOVBU 2916(R24), R3 // 03936d39
- MOVBU (R18)(R14<<0), R23 // 577a6e38
+ MOVBU (R19)(R14<<0), R23 // 777a6e38
MOVBU (R2)(R8.SXTX), R19 // 53e86838
MOVBU (R27)(R23), R14 // MOVBU (R27)(R23*1), R14 // 6e6b7738
MOVHU.P 107(R14), R13 // cdb54678
MOVHU.W 192(R3), R2 // 620c4c78
- MOVHU 6844(R4), R18 // 92787579
+ MOVHU 6844(R4), R19 // 93787579
MOVHU (R5)(R25.SXTW), R15 // afc87978
- //TODO MOVBW.P 77(R18), R11 // 4bd6c438
+ //TODO MOVBW.P 77(R19), R11 // 6bd6c438
MOVB.P 36(RSP), R27 // fb478238
- //TODO MOVBW.W -57(R18), R13 // 4d7edc38
+ //TODO MOVBW.W -57(R19), R13 // 6d7edc38
MOVB.W -178(R16), R24 // 18ee9438
//TODO MOVBW 430(R8), R22 // 16b9c639
MOVB 997(R9), R23 // 37958f39
//TODO MOVBW (R2<<1)(R21), R15 // af7ae238
//TODO MOVBW (R26)(R0), R21 // 1568fa38
MOVB (R5)(R15), R16 // MOVB (R5)(R15*1), R16 // b068af38
- MOVB (R18)(R26.SXTW), R19 // 53caba38
+ MOVB (R19)(R26.SXTW), R19 // 73caba38
MOVB (R29)(R30), R14 // MOVB (R29)(R30*1), R14 // ae6bbe38
//TODO MOVHW.P 218(R22), R25 // d9a6cd78
MOVH.P 179(R23), R5 // e5368b78
@@ -212,7 +212,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
//TODO MOVHW (R22)(R24.SXTX), R4 // c4eaf878
MOVH (R26)(R30.UXTW<<1), ZR // 5f5bbe78
MOVW.P -58(R16), R2 // 02669cb8
- MOVW.W -216(R18), R8 // 488e92b8
+ MOVW.W -216(R19), R8 // 688e92b8
MOVW 4764(R23), R10 // ea9e92b9
MOVW (R8)(R3.UXTW), R17 // 1149a3b8
//TODO LDTR -0x1e(R3), R4 // 64285eb8
@@ -297,7 +297,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
RET // c0035fd6
REVW R8, R10 // 0a09c05a
REV R1, R2 // 220cc0da
- REV16W R21, R18 // b206c05a
+ REV16W R21, R19 // b306c05a
REV16 R25, R4 // 2407c0da
REV32 R27, R21 // 750bc0da
EXTRW $27, R4, R25, R19 // 336f8413
@@ -308,7 +308,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
ROR R0, R23, R2 // e22ec09a
SBCW R4, R8, R24 // 1801045a
SBC R25, R10, R26 // 5a0119da
- SBCSW R27, R18, R18 // 52021b7a
+ SBCSW R27, R19, R19 // 73021b7a
SBCS R5, R9, R5 // 250105fa
SBFIZW $9, R10, $18, R22 // 56451713
SBFIZ $6, R11, $15, R20 // 74397a93
@@ -337,7 +337,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
//TODO STNPW 44(R1), R3, R10 // 2a8c0528
//TODO STNP 0x108(R3), ZR, R7 // 67fc10a8
LDP.P -384(R3), (R22, R26) // 7668e8a8
- LDP.W 280(R8), (R18, R11) // 12add1a9
+ LDP.W 280(R8), (R19, R11) // 13add1a9
STP.P (R22, R27), 352(R0) // 166c96a8
STP.W (R17, R11), 96(R8) // 112d86a9
MOVW.P R20, -28(R1) // 34441eb8
@@ -360,22 +360,22 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
MOVB R2, (R29)(R26) // MOVB R2, (R29)(R26*1) // a26b3a38
MOVH R11, -80(R23) // eb021b78
MOVH R11, (R27)(R14.SXTW<<1) // 6bdb2e78
- MOVB R18, (R0)(R4) // MOVB R18, (R0)(R4*1) // 12682438
+ MOVB R19, (R0)(R4) // MOVB R19, (R0)(R4*1) // 13682438
MOVB R1, (R6)(R4) // MOVB R1, (R6)(R4*1) // c1682438
MOVH R3, (R11)(R13<<1) // 63792d78
//TODO STTR 55(R4), R29 // 9d7803b8
//TODO STTR 124(R5), R25 // b9c807f8
//TODO STTRB -28(R23), R16 // f04a1e38
- //TODO STTRH 9(R10), R18 // 52990078
+ //TODO STTRH 9(R10), R19 // 53990078
STXP (R1, R2), (R3), R10 // 61082ac8
STXP (R1, R2), (RSP), R10 // e10b2ac8
STXPW (R1, R2), (R3), R10 // 61082a88
STXPW (R1, R2), (RSP), R10 // e10b2a88
- STXRW R2, (R19), R18 // 627e1288
+ STXRW R2, (R19), R20 // 627e1488
STXR R15, (R21), R13 // af7e0dc8
STXRB R7, (R9), R24 // 277d1808
STXRH R12, (R3), R8 // 6c7c0848
- SUBW R20.UXTW<<2, R23, R18 // f24a344b
+ SUBW R20.UXTW<<2, R23, R19 // f34a344b
SUB R5.SXTW<<2, R1, R26 // 3ac825cb
SUB $(1923<<12), R4, R27 // SUB $7876608, R4, R27 // 9b0c5ed1
SUBW $(1923<<12), R4, R27 // SUBW $7876608, R4, R27 // 9b0c5e51
@@ -410,12 +410,12 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
UBFXW $3, R7, $20, R15 // ef580353
UBFX $33, R17, $25, R5 // 25e661d3
UDIVW R8, R21, R15 // af0ac81a
- UDIV R2, R18, R21 // 550ac29a
+ UDIV R2, R19, R21 // 750ac29a
UMADDL R0, R20, R17, R17 // 3152a09b
UMSUBL R22, R4, R3, R7 // 6790b69b
- UMNEGL R3, R18, R1 // 41fea39b
+ UMNEGL R3, R19, R1 // 61fea39b
UMULH R24, R20, R24 // 987ed89b
- UMULL R18, R22, R19 // d37eb29b
+ UMULL R19, R22, R19 // d37eb39b
UXTBW R2, R6 // 461c0053
UXTHW R7, R20 // f43c0053
VCNT V0.B8, V0.B8 // 0058200e
@@ -471,7 +471,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
//TODO FCVTAS F27, R7 // 6703241e
//TODO FCVTAS F19, R26 // 7a02249e
//TODO FCVTAS F4, R0 // 8000641e
- //TODO FCVTAS F3, R18 // 7200649e
+ //TODO FCVTAS F3, R19 // 7300649e
//TODO FCVTAU F18, F28 // 5cca217e
//TODO VFCVTAU V30.S4, V27.S4 // dbcb216e
//TODO FCVTAU F0, R2 // 0200251e
@@ -482,16 +482,16 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
//TODO VFCVTL2 V15.H8, V25.S4 // f979214e
//TODO FCVTMS F21, F28 // bcba215e
//TODO VFCVTMS V5.D2, V2.D2 // a2b8614e
- //TODO FCVTMS F31, R18 // f203301e
+ //TODO FCVTMS F31, R19 // f303301e
//TODO FCVTMS F23, R16 // f002309e
//TODO FCVTMS F16, R22 // 1602701e
//TODO FCVTMS F14, R19 // d301709e
//TODO FCVTMU F14, F8 // c8b9217e
//TODO VFCVTMU V7.D2, V1.D2 // e1b8616e
//TODO FCVTMU F2, R0 // 4000311e
- //TODO FCVTMU F23, R18 // f202319e
+ //TODO FCVTMU F23, R19 // f302319e
//TODO FCVTMU F16, R17 // 1102711e
- //TODO FCVTMU F12, R18 // 9201719e
+ //TODO FCVTMU F12, R19 // 9301719e
//TODO VFCVTN V23.D2, V26.S2 // fa6a610e
//TODO VFCVTN2 V2.D2, V31.S4 // 5f68614e
//TODO FCVTNS F3, F27 // 7ba8215e
@@ -540,7 +540,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
//TODO FCVTZU $14, F24, R20 // 14cb191e
//TODO FCVTZU $6, F25, R17 // 31eb199e
//TODO FCVTZU $5, F17, R10 // 2aee591e
- //TODO FCVTZU $6, F7, R18 // f2e8599e
+ //TODO FCVTZU $6, F7, R19 // f3e8599e
FCVTZUSW F2, R9 // 4900391e
FCVTZUS F12, R29 // 9d01399e
FCVTZUDW F27, R22 // 7603791e
@@ -682,11 +682,11 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
VLD1.P (R19)(R4), [V24.B8, V25.B8] // VLD1.P (R19)(R4*1), [V24.B8, V25.B8] // 78a2c40c
VLD1.P (R20)(R8), [V7.H8, V8.H8, V9.H8] // VLD1.P (R20)(R8*1), [V7.H8, V8.H8, V9.H8] // 8766c84c
VLD1.P 32(R30), [V5.B8, V6.B8, V7.B8, V8.B8] // c523df0c
- VLD1 (R18), V14.B[15] // 4e1e404d
+ VLD1 (R19), V14.B[15] // 6e1e404d
VLD1 (R29), V0.H[1] // a04b400d
VLD1 (R27), V2.S[0] // 6283400d
VLD1 (R21), V5.D[1] // a586404d
- VLD1.P 1(R18), V10.B[14] // 4a1adf4d
+ VLD1.P 1(R19), V10.B[14] // 6a1adf4d
VLD1.P (R3)(R14), V16.B[11] // VLD1.P (R3)(R14*1), V16.B[11] // 700cce4d
VLD1.P 2(R1), V28.H[2] // 3c50df0d
VLD1.P (R13)(R20), V9.H[2] // VLD1.P (R13)(R20*1), V9.H[2] // a951d40d
diff --git a/src/cmd/asm/internal/lex/input.go b/src/cmd/asm/internal/lex/input.go
index 5186635fe7..a43953b515 100644
--- a/src/cmd/asm/internal/lex/input.go
+++ b/src/cmd/asm/internal/lex/input.go
@@ -139,7 +139,7 @@ func (in *Input) Text() string {
return in.text
}
-// hash processes a # preprocessor directive. It returns true iff it completes.
+// hash processes a # preprocessor directive. It reports whether it completes.
func (in *Input) hash() bool {
// We have a '#'; it must be followed by a known word (define, include, etc.).
tok := in.Stack.Next()
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
index 157cd94d65..08d64130df 100644
--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -827,6 +827,10 @@ The directives are:
possibly version in the dynamic library, and the optional ""
names the specific library where the symbol should be found.
+ On AIX, the library pattern is slightly different. It must be
+ "lib.a/obj.o" with obj.o the member of this library exporting
+ this symbol.
+
In the , # or @ can be used to introduce a symbol version.
Examples:
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index a93ff365b0..c203873b13 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -246,7 +246,22 @@ func (p *Package) writeDefs() {
init := gccgoInit.String()
if init != "" {
- fmt.Fprintln(fc, "static void init(void) __attribute__ ((constructor));")
+ // The init function does nothing but simple
+ // assignments, so it won't use much stack space, so
+ // it's OK to not split the stack. Splitting the stack
+ // can run into a bug in clang (as of 2018-11-09):
+ // this is a leaf function, and when clang sees a leaf
+ // function it won't emit the split stack prologue for
+ // the function. However, if this function refers to a
+ // non-split-stack function, which will happen if the
+ // cgo code refers to a C function not compiled with
+ // -fsplit-stack, then the linker will think that it
+ // needs to adjust the split stack prologue, but there
+ // won't be one. Marking the function explicitly
+ // no_split_stack works around this problem by telling
+ // the linker that it's OK if there is no split stack
+ // prologue.
+ fmt.Fprintln(fc, "static void init(void) __attribute__ ((constructor, no_split_stack));")
fmt.Fprintln(fc, "static void init(void) {")
fmt.Fprint(fc, init)
fmt.Fprintln(fc, "}")
diff --git a/src/cmd/compile/fmt_test.go b/src/cmd/compile/fmt_test.go
index 6dfdea1a34..05d13b58a5 100644
--- a/src/cmd/compile/fmt_test.go
+++ b/src/cmd/compile/fmt_test.go
@@ -587,6 +587,7 @@ var knownFormats = map[string]string{
"*cmd/compile/internal/types.Sym %S": "",
"*cmd/compile/internal/types.Sym %p": "",
"*cmd/compile/internal/types.Sym %v": "",
+ "*cmd/compile/internal/types.Type %#L": "",
"*cmd/compile/internal/types.Type %#v": "",
"*cmd/compile/internal/types.Type %+v": "",
"*cmd/compile/internal/types.Type %-S": "",
@@ -598,6 +599,7 @@ var knownFormats = map[string]string{
"*cmd/compile/internal/types.Type %v": "",
"*cmd/internal/obj.Addr %v": "",
"*cmd/internal/obj.LSym %v": "",
+ "*math/big.Float %f": "",
"*math/big.Int %#x": "",
"*math/big.Int %s": "",
"*math/big.Int %v": "",
@@ -658,6 +660,7 @@ var knownFormats = map[string]string{
"cmd/compile/internal/ssa.rbrank %d": "",
"cmd/compile/internal/ssa.regMask %d": "",
"cmd/compile/internal/ssa.register %d": "",
+ "cmd/compile/internal/syntax.Error %q": "",
"cmd/compile/internal/syntax.Expr %#v": "",
"cmd/compile/internal/syntax.Node %T": "",
"cmd/compile/internal/syntax.Operator %s": "",
@@ -705,33 +708,34 @@ var knownFormats = map[string]string{
"interface{} %v": "",
"map[*cmd/compile/internal/gc.Node]*cmd/compile/internal/ssa.Value %v": "",
"map[cmd/compile/internal/ssa.ID]uint32 %v": "",
- "reflect.Type %s": "",
- "rune %#U": "",
- "rune %c": "",
- "string %-*s": "",
- "string %-16s": "",
- "string %-6s": "",
- "string %.*s": "",
- "string %q": "",
- "string %s": "",
- "string %v": "",
- "time.Duration %d": "",
- "time.Duration %v": "",
- "uint %04x": "",
- "uint %5d": "",
- "uint %d": "",
- "uint %x": "",
- "uint16 %d": "",
- "uint16 %v": "",
- "uint16 %x": "",
- "uint32 %#x": "",
- "uint32 %d": "",
- "uint32 %v": "",
- "uint32 %x": "",
- "uint64 %08x": "",
- "uint64 %d": "",
- "uint64 %x": "",
- "uint8 %d": "",
- "uint8 %x": "",
- "uintptr %d": "",
+ "math/big.Accuracy %s": "",
+ "reflect.Type %s": "",
+ "rune %#U": "",
+ "rune %c": "",
+ "string %-*s": "",
+ "string %-16s": "",
+ "string %-6s": "",
+ "string %.*s": "",
+ "string %q": "",
+ "string %s": "",
+ "string %v": "",
+ "time.Duration %d": "",
+ "time.Duration %v": "",
+ "uint %04x": "",
+ "uint %5d": "",
+ "uint %d": "",
+ "uint %x": "",
+ "uint16 %d": "",
+ "uint16 %v": "",
+ "uint16 %x": "",
+ "uint32 %#x": "",
+ "uint32 %d": "",
+ "uint32 %v": "",
+ "uint32 %x": "",
+ "uint64 %08x": "",
+ "uint64 %d": "",
+ "uint64 %x": "",
+ "uint8 %d": "",
+ "uint8 %x": "",
+ "uintptr %d": "",
}
diff --git a/src/cmd/compile/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go
index 325bf4aa0e..4e9f11c8b3 100644
--- a/src/cmd/compile/internal/gc/builtin.go
+++ b/src/cmd/compile/internal/gc/builtin.go
@@ -51,110 +51,105 @@ var runtimeDecls = [...]struct {
{"decoderune", funcTag, 50},
{"countrunes", funcTag, 51},
{"convI2I", funcTag, 52},
- {"convT2E", funcTag, 53},
- {"convT2E16", funcTag, 52},
- {"convT2E32", funcTag, 52},
- {"convT2E64", funcTag, 52},
- {"convT2Estring", funcTag, 52},
- {"convT2Eslice", funcTag, 52},
- {"convT2Enoptr", funcTag, 53},
- {"convT2I", funcTag, 53},
- {"convT2I16", funcTag, 52},
- {"convT2I32", funcTag, 52},
- {"convT2I64", funcTag, 52},
- {"convT2Istring", funcTag, 52},
- {"convT2Islice", funcTag, 52},
- {"convT2Inoptr", funcTag, 53},
+ {"convT16", funcTag, 54},
+ {"convT32", funcTag, 54},
+ {"convT64", funcTag, 54},
+ {"convTstring", funcTag, 54},
+ {"convTslice", funcTag, 54},
+ {"convT2E", funcTag, 55},
+ {"convT2Enoptr", funcTag, 55},
+ {"convT2I", funcTag, 55},
+ {"convT2Inoptr", funcTag, 55},
{"assertE2I", funcTag, 52},
- {"assertE2I2", funcTag, 54},
+ {"assertE2I2", funcTag, 56},
{"assertI2I", funcTag, 52},
- {"assertI2I2", funcTag, 54},
- {"panicdottypeE", funcTag, 55},
- {"panicdottypeI", funcTag, 55},
- {"panicnildottype", funcTag, 56},
- {"ifaceeq", funcTag, 59},
- {"efaceeq", funcTag, 59},
- {"fastrand", funcTag, 61},
- {"makemap64", funcTag, 63},
- {"makemap", funcTag, 64},
- {"makemap_small", funcTag, 65},
- {"mapaccess1", funcTag, 66},
- {"mapaccess1_fast32", funcTag, 67},
- {"mapaccess1_fast64", funcTag, 67},
- {"mapaccess1_faststr", funcTag, 67},
- {"mapaccess1_fat", funcTag, 68},
- {"mapaccess2", funcTag, 69},
- {"mapaccess2_fast32", funcTag, 70},
- {"mapaccess2_fast64", funcTag, 70},
- {"mapaccess2_faststr", funcTag, 70},
- {"mapaccess2_fat", funcTag, 71},
- {"mapassign", funcTag, 66},
- {"mapassign_fast32", funcTag, 67},
- {"mapassign_fast32ptr", funcTag, 67},
- {"mapassign_fast64", funcTag, 67},
- {"mapassign_fast64ptr", funcTag, 67},
- {"mapassign_faststr", funcTag, 67},
- {"mapiterinit", funcTag, 72},
- {"mapdelete", funcTag, 72},
- {"mapdelete_fast32", funcTag, 73},
- {"mapdelete_fast64", funcTag, 73},
- {"mapdelete_faststr", funcTag, 73},
- {"mapiternext", funcTag, 74},
- {"mapclear", funcTag, 75},
- {"makechan64", funcTag, 77},
- {"makechan", funcTag, 78},
- {"chanrecv1", funcTag, 80},
- {"chanrecv2", funcTag, 81},
- {"chansend1", funcTag, 83},
+ {"assertI2I2", funcTag, 56},
+ {"panicdottypeE", funcTag, 57},
+ {"panicdottypeI", funcTag, 57},
+ {"panicnildottype", funcTag, 58},
+ {"ifaceeq", funcTag, 60},
+ {"efaceeq", funcTag, 60},
+ {"fastrand", funcTag, 62},
+ {"makemap64", funcTag, 64},
+ {"makemap", funcTag, 65},
+ {"makemap_small", funcTag, 66},
+ {"mapaccess1", funcTag, 67},
+ {"mapaccess1_fast32", funcTag, 68},
+ {"mapaccess1_fast64", funcTag, 68},
+ {"mapaccess1_faststr", funcTag, 68},
+ {"mapaccess1_fat", funcTag, 69},
+ {"mapaccess2", funcTag, 70},
+ {"mapaccess2_fast32", funcTag, 71},
+ {"mapaccess2_fast64", funcTag, 71},
+ {"mapaccess2_faststr", funcTag, 71},
+ {"mapaccess2_fat", funcTag, 72},
+ {"mapassign", funcTag, 67},
+ {"mapassign_fast32", funcTag, 68},
+ {"mapassign_fast32ptr", funcTag, 68},
+ {"mapassign_fast64", funcTag, 68},
+ {"mapassign_fast64ptr", funcTag, 68},
+ {"mapassign_faststr", funcTag, 68},
+ {"mapiterinit", funcTag, 73},
+ {"mapdelete", funcTag, 73},
+ {"mapdelete_fast32", funcTag, 74},
+ {"mapdelete_fast64", funcTag, 74},
+ {"mapdelete_faststr", funcTag, 74},
+ {"mapiternext", funcTag, 75},
+ {"mapclear", funcTag, 76},
+ {"makechan64", funcTag, 78},
+ {"makechan", funcTag, 79},
+ {"chanrecv1", funcTag, 81},
+ {"chanrecv2", funcTag, 82},
+ {"chansend1", funcTag, 84},
{"closechan", funcTag, 23},
- {"writeBarrier", varTag, 85},
- {"typedmemmove", funcTag, 86},
- {"typedmemclr", funcTag, 87},
- {"typedslicecopy", funcTag, 88},
- {"selectnbsend", funcTag, 89},
- {"selectnbrecv", funcTag, 90},
- {"selectnbrecv2", funcTag, 92},
- {"selectsetpc", funcTag, 56},
- {"selectgo", funcTag, 93},
+ {"writeBarrier", varTag, 86},
+ {"typedmemmove", funcTag, 87},
+ {"typedmemclr", funcTag, 88},
+ {"typedslicecopy", funcTag, 89},
+ {"selectnbsend", funcTag, 90},
+ {"selectnbrecv", funcTag, 91},
+ {"selectnbrecv2", funcTag, 93},
+ {"selectsetpc", funcTag, 58},
+ {"selectgo", funcTag, 94},
{"block", funcTag, 5},
- {"makeslice", funcTag, 94},
- {"makeslice64", funcTag, 95},
- {"growslice", funcTag, 97},
- {"memmove", funcTag, 98},
- {"memclrNoHeapPointers", funcTag, 99},
- {"memclrHasPointers", funcTag, 99},
- {"memequal", funcTag, 100},
- {"memequal8", funcTag, 101},
- {"memequal16", funcTag, 101},
- {"memequal32", funcTag, 101},
- {"memequal64", funcTag, 101},
- {"memequal128", funcTag, 101},
- {"int64div", funcTag, 102},
- {"uint64div", funcTag, 103},
- {"int64mod", funcTag, 102},
- {"uint64mod", funcTag, 103},
- {"float64toint64", funcTag, 104},
- {"float64touint64", funcTag, 105},
- {"float64touint32", funcTag, 106},
- {"int64tofloat64", funcTag, 107},
- {"uint64tofloat64", funcTag, 108},
- {"uint32tofloat64", funcTag, 109},
- {"complex128div", funcTag, 110},
- {"racefuncenter", funcTag, 111},
+ {"makeslice", funcTag, 95},
+ {"makeslice64", funcTag, 96},
+ {"growslice", funcTag, 98},
+ {"memmove", funcTag, 99},
+ {"memclrNoHeapPointers", funcTag, 100},
+ {"memclrHasPointers", funcTag, 100},
+ {"memequal", funcTag, 101},
+ {"memequal8", funcTag, 102},
+ {"memequal16", funcTag, 102},
+ {"memequal32", funcTag, 102},
+ {"memequal64", funcTag, 102},
+ {"memequal128", funcTag, 102},
+ {"int64div", funcTag, 103},
+ {"uint64div", funcTag, 104},
+ {"int64mod", funcTag, 103},
+ {"uint64mod", funcTag, 104},
+ {"float64toint64", funcTag, 105},
+ {"float64touint64", funcTag, 106},
+ {"float64touint32", funcTag, 107},
+ {"int64tofloat64", funcTag, 108},
+ {"uint64tofloat64", funcTag, 109},
+ {"uint32tofloat64", funcTag, 110},
+ {"complex128div", funcTag, 111},
+ {"racefuncenter", funcTag, 112},
{"racefuncenterfp", funcTag, 5},
{"racefuncexit", funcTag, 5},
- {"raceread", funcTag, 111},
- {"racewrite", funcTag, 111},
- {"racereadrange", funcTag, 112},
- {"racewriterange", funcTag, 112},
- {"msanread", funcTag, 112},
- {"msanwrite", funcTag, 112},
+ {"raceread", funcTag, 112},
+ {"racewrite", funcTag, 112},
+ {"racereadrange", funcTag, 113},
+ {"racewriterange", funcTag, 113},
+ {"msanread", funcTag, 113},
+ {"msanwrite", funcTag, 113},
{"support_popcnt", varTag, 11},
{"support_sse41", varTag, 11},
}
func runtimeTypes() []*types.Type {
- var typs [113]*types.Type
+ var typs [114]*types.Type
typs[0] = types.Bytetype
typs[1] = types.NewPtr(typs[0])
typs[2] = types.Types[TANY]
@@ -208,65 +203,66 @@ func runtimeTypes() []*types.Type {
typs[50] = functype(nil, []*Node{anonfield(typs[21]), anonfield(typs[32])}, []*Node{anonfield(typs[40]), anonfield(typs[32])})
typs[51] = functype(nil, []*Node{anonfield(typs[21])}, []*Node{anonfield(typs[32])})
typs[52] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2])})
- typs[53] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, []*Node{anonfield(typs[2])})
- typs[54] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2]), anonfield(typs[11])})
- typs[55] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil)
- typs[56] = functype(nil, []*Node{anonfield(typs[1])}, nil)
- typs[57] = types.NewPtr(typs[47])
- typs[58] = types.Types[TUNSAFEPTR]
- typs[59] = functype(nil, []*Node{anonfield(typs[57]), anonfield(typs[58]), anonfield(typs[58])}, []*Node{anonfield(typs[11])})
- typs[60] = types.Types[TUINT32]
- typs[61] = functype(nil, nil, []*Node{anonfield(typs[60])})
- typs[62] = types.NewMap(typs[2], typs[2])
- typs[63] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[3])}, []*Node{anonfield(typs[62])})
- typs[64] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[32]), anonfield(typs[3])}, []*Node{anonfield(typs[62])})
- typs[65] = functype(nil, nil, []*Node{anonfield(typs[62])})
- typs[66] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[62]), anonfield(typs[3])}, []*Node{anonfield(typs[3])})
- typs[67] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[62]), anonfield(typs[2])}, []*Node{anonfield(typs[3])})
- typs[68] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[62]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3])})
- typs[69] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[62]), anonfield(typs[3])}, []*Node{anonfield(typs[3]), anonfield(typs[11])})
- typs[70] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[62]), anonfield(typs[2])}, []*Node{anonfield(typs[3]), anonfield(typs[11])})
- typs[71] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[62]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3]), anonfield(typs[11])})
- typs[72] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[62]), anonfield(typs[3])}, nil)
- typs[73] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[62]), anonfield(typs[2])}, nil)
- typs[74] = functype(nil, []*Node{anonfield(typs[3])}, nil)
- typs[75] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[62])}, nil)
- typs[76] = types.NewChan(typs[2], types.Cboth)
- typs[77] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[76])})
- typs[78] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[32])}, []*Node{anonfield(typs[76])})
- typs[79] = types.NewChan(typs[2], types.Crecv)
- typs[80] = functype(nil, []*Node{anonfield(typs[79]), anonfield(typs[3])}, nil)
- typs[81] = functype(nil, []*Node{anonfield(typs[79]), anonfield(typs[3])}, []*Node{anonfield(typs[11])})
- typs[82] = types.NewChan(typs[2], types.Csend)
- typs[83] = functype(nil, []*Node{anonfield(typs[82]), anonfield(typs[3])}, nil)
- typs[84] = types.NewArray(typs[0], 3)
- typs[85] = tostruct([]*Node{namedfield("enabled", typs[11]), namedfield("pad", typs[84]), namedfield("needed", typs[11]), namedfield("cgo", typs[11]), namedfield("alignme", typs[17])})
- typs[86] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil)
- typs[87] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, nil)
- typs[88] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2]), anonfield(typs[2])}, []*Node{anonfield(typs[32])})
- typs[89] = functype(nil, []*Node{anonfield(typs[82]), anonfield(typs[3])}, []*Node{anonfield(typs[11])})
- typs[90] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[79])}, []*Node{anonfield(typs[11])})
- typs[91] = types.NewPtr(typs[11])
- typs[92] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[91]), anonfield(typs[79])}, []*Node{anonfield(typs[11])})
- typs[93] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[32])}, []*Node{anonfield(typs[32]), anonfield(typs[11])})
- typs[94] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[32]), anonfield(typs[32])}, []*Node{anonfield(typs[58])})
- typs[95] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[58])})
- typs[96] = types.NewSlice(typs[2])
- typs[97] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[96]), anonfield(typs[32])}, []*Node{anonfield(typs[96])})
- typs[98] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[47])}, nil)
- typs[99] = functype(nil, []*Node{anonfield(typs[58]), anonfield(typs[47])}, nil)
- typs[100] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[47])}, []*Node{anonfield(typs[11])})
- typs[101] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[11])})
- typs[102] = functype(nil, []*Node{anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[15])})
- typs[103] = functype(nil, []*Node{anonfield(typs[17]), anonfield(typs[17])}, []*Node{anonfield(typs[17])})
- typs[104] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[15])})
- typs[105] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[17])})
- typs[106] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[60])})
- typs[107] = functype(nil, []*Node{anonfield(typs[15])}, []*Node{anonfield(typs[13])})
- typs[108] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[13])})
- typs[109] = functype(nil, []*Node{anonfield(typs[60])}, []*Node{anonfield(typs[13])})
- typs[110] = functype(nil, []*Node{anonfield(typs[19]), anonfield(typs[19])}, []*Node{anonfield(typs[19])})
- typs[111] = functype(nil, []*Node{anonfield(typs[47])}, nil)
- typs[112] = functype(nil, []*Node{anonfield(typs[47]), anonfield(typs[47])}, nil)
+ typs[53] = types.Types[TUNSAFEPTR]
+ typs[54] = functype(nil, []*Node{anonfield(typs[2])}, []*Node{anonfield(typs[53])})
+ typs[55] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, []*Node{anonfield(typs[2])})
+ typs[56] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2]), anonfield(typs[11])})
+ typs[57] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil)
+ typs[58] = functype(nil, []*Node{anonfield(typs[1])}, nil)
+ typs[59] = types.NewPtr(typs[47])
+ typs[60] = functype(nil, []*Node{anonfield(typs[59]), anonfield(typs[53]), anonfield(typs[53])}, []*Node{anonfield(typs[11])})
+ typs[61] = types.Types[TUINT32]
+ typs[62] = functype(nil, nil, []*Node{anonfield(typs[61])})
+ typs[63] = types.NewMap(typs[2], typs[2])
+ typs[64] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[3])}, []*Node{anonfield(typs[63])})
+ typs[65] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[32]), anonfield(typs[3])}, []*Node{anonfield(typs[63])})
+ typs[66] = functype(nil, nil, []*Node{anonfield(typs[63])})
+ typs[67] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[63]), anonfield(typs[3])}, []*Node{anonfield(typs[3])})
+ typs[68] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[63]), anonfield(typs[2])}, []*Node{anonfield(typs[3])})
+ typs[69] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[63]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3])})
+ typs[70] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[63]), anonfield(typs[3])}, []*Node{anonfield(typs[3]), anonfield(typs[11])})
+ typs[71] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[63]), anonfield(typs[2])}, []*Node{anonfield(typs[3]), anonfield(typs[11])})
+ typs[72] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[63]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3]), anonfield(typs[11])})
+ typs[73] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[63]), anonfield(typs[3])}, nil)
+ typs[74] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[63]), anonfield(typs[2])}, nil)
+ typs[75] = functype(nil, []*Node{anonfield(typs[3])}, nil)
+ typs[76] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[63])}, nil)
+ typs[77] = types.NewChan(typs[2], types.Cboth)
+ typs[78] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[77])})
+ typs[79] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[32])}, []*Node{anonfield(typs[77])})
+ typs[80] = types.NewChan(typs[2], types.Crecv)
+ typs[81] = functype(nil, []*Node{anonfield(typs[80]), anonfield(typs[3])}, nil)
+ typs[82] = functype(nil, []*Node{anonfield(typs[80]), anonfield(typs[3])}, []*Node{anonfield(typs[11])})
+ typs[83] = types.NewChan(typs[2], types.Csend)
+ typs[84] = functype(nil, []*Node{anonfield(typs[83]), anonfield(typs[3])}, nil)
+ typs[85] = types.NewArray(typs[0], 3)
+ typs[86] = tostruct([]*Node{namedfield("enabled", typs[11]), namedfield("pad", typs[85]), namedfield("needed", typs[11]), namedfield("cgo", typs[11]), namedfield("alignme", typs[17])})
+ typs[87] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil)
+ typs[88] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, nil)
+ typs[89] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2]), anonfield(typs[2])}, []*Node{anonfield(typs[32])})
+ typs[90] = functype(nil, []*Node{anonfield(typs[83]), anonfield(typs[3])}, []*Node{anonfield(typs[11])})
+ typs[91] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[80])}, []*Node{anonfield(typs[11])})
+ typs[92] = types.NewPtr(typs[11])
+ typs[93] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[92]), anonfield(typs[80])}, []*Node{anonfield(typs[11])})
+ typs[94] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[32])}, []*Node{anonfield(typs[32]), anonfield(typs[11])})
+ typs[95] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[32]), anonfield(typs[32])}, []*Node{anonfield(typs[53])})
+ typs[96] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[53])})
+ typs[97] = types.NewSlice(typs[2])
+ typs[98] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[97]), anonfield(typs[32])}, []*Node{anonfield(typs[97])})
+ typs[99] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[47])}, nil)
+ typs[100] = functype(nil, []*Node{anonfield(typs[53]), anonfield(typs[47])}, nil)
+ typs[101] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[47])}, []*Node{anonfield(typs[11])})
+ typs[102] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[11])})
+ typs[103] = functype(nil, []*Node{anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[15])})
+ typs[104] = functype(nil, []*Node{anonfield(typs[17]), anonfield(typs[17])}, []*Node{anonfield(typs[17])})
+ typs[105] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[15])})
+ typs[106] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[17])})
+ typs[107] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[61])})
+ typs[108] = functype(nil, []*Node{anonfield(typs[15])}, []*Node{anonfield(typs[13])})
+ typs[109] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[13])})
+ typs[110] = functype(nil, []*Node{anonfield(typs[61])}, []*Node{anonfield(typs[13])})
+ typs[111] = functype(nil, []*Node{anonfield(typs[19]), anonfield(typs[19])}, []*Node{anonfield(typs[19])})
+ typs[112] = functype(nil, []*Node{anonfield(typs[47])}, nil)
+ typs[113] = functype(nil, []*Node{anonfield(typs[47]), anonfield(typs[47])}, nil)
return typs[:]
}
diff --git a/src/cmd/compile/internal/gc/builtin/runtime.go b/src/cmd/compile/internal/gc/builtin/runtime.go
index e6d174bc4b..1eaf332e50 100644
--- a/src/cmd/compile/internal/gc/builtin/runtime.go
+++ b/src/cmd/compile/internal/gc/builtin/runtime.go
@@ -61,23 +61,23 @@ func slicestringcopy(to any, fr any) int
func decoderune(string, int) (retv rune, retk int)
func countrunes(string) int
-// interface conversions
+// Non-empty-interface to non-empty-interface conversion.
func convI2I(typ *byte, elem any) (ret any)
+// Specialized type-to-interface conversion.
+// These return only a data pointer.
+func convT16(val any) unsafe.Pointer // val must be uint16-like (same size and alignment as a uint16)
+func convT32(val any) unsafe.Pointer // val must be uint32-like (same size and alignment as a uint32)
+func convT64(val any) unsafe.Pointer // val must be uint64-like (same size and alignment as a uint64 and contains no pointers)
+func convTstring(val any) unsafe.Pointer // val must be a string
+func convTslice(val any) unsafe.Pointer // val must be a slice
+
+// Type to empty-interface conversion.
func convT2E(typ *byte, elem *any) (ret any)
-func convT2E16(typ *byte, val any) (ret any)
-func convT2E32(typ *byte, val any) (ret any)
-func convT2E64(typ *byte, val any) (ret any)
-func convT2Estring(typ *byte, val any) (ret any) // val must be a string
-func convT2Eslice(typ *byte, val any) (ret any) // val must be a slice
func convT2Enoptr(typ *byte, elem *any) (ret any)
+// Type to non-empty-interface conversion.
func convT2I(tab *byte, elem *any) (ret any)
-func convT2I16(tab *byte, val any) (ret any)
-func convT2I32(tab *byte, val any) (ret any)
-func convT2I64(tab *byte, val any) (ret any)
-func convT2Istring(tab *byte, val any) (ret any) // val must be a string
-func convT2Islice(tab *byte, val any) (ret any) // val must be a slice
func convT2Inoptr(tab *byte, elem *any) (ret any)
// interface type assertions x.(T)
diff --git a/src/cmd/compile/internal/gc/closure.go b/src/cmd/compile/internal/gc/closure.go
index ec19f5c112..5123df8e9d 100644
--- a/src/cmd/compile/internal/gc/closure.go
+++ b/src/cmd/compile/internal/gc/closure.go
@@ -314,7 +314,7 @@ func transformclosure(xfunc *Node) {
lineno = lno
}
-// hasemptycvars returns true iff closure clo has an
+// hasemptycvars reports whether closure clo has an
// empty list of captured vars.
func hasemptycvars(clo *Node) bool {
xfunc := clo.Func.Closure
diff --git a/src/cmd/compile/internal/gc/dwinl.go b/src/cmd/compile/internal/gc/dwinl.go
index 51251c9139..ade76f40f8 100644
--- a/src/cmd/compile/internal/gc/dwinl.go
+++ b/src/cmd/compile/internal/gc/dwinl.go
@@ -300,7 +300,7 @@ func beginRange(calls []dwarf.InlCall, p *obj.Prog, ii int, imap map[int]int) *d
}
callIdx, found := imap[ii]
if !found {
- Fatalf("internal error: can't find inlIndex %d in imap for prog at %d\n", ii, p.Pc)
+ Fatalf("can't find inlIndex %d in imap for prog at %d\n", ii, p.Pc)
}
call := &calls[callIdx]
diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go
index 0f4b6c9936..16b81e6a88 100644
--- a/src/cmd/compile/internal/gc/fmt.go
+++ b/src/cmd/compile/internal/gc/fmt.go
@@ -1114,6 +1114,7 @@ var opprec = []int{
OSLICEARR: 8,
OSLICE3: 8,
OSLICE3ARR: 8,
+ OSLICEHEADER: 8,
ODOTINTER: 8,
ODOTMETH: 8,
ODOTPTR: 8,
@@ -1393,6 +1394,12 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
}
fmt.Fprint(s, "]")
+ case OSLICEHEADER:
+ if n.List.Len() != 2 {
+ Fatalf("bad OSLICEHEADER list length %d", n.List.Len())
+ }
+ mode.Fprintf(s, "sliceheader{%v,%v,%v}", n.Left, n.List.First(), n.List.Second())
+
case OCOPY, OCOMPLEX:
mode.Fprintf(s, "%#v(%v, %v)", n.Op, n.Left, n.Right)
diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go
index cfd695097f..471746ed7d 100644
--- a/src/cmd/compile/internal/gc/go.go
+++ b/src/cmd/compile/internal/gc/go.go
@@ -147,7 +147,6 @@ var asmhdr string
var simtype [NTYPE]types.EType
var (
- isforw [NTYPE]bool
isInt [NTYPE]bool
isFloat [NTYPE]bool
isComplex [NTYPE]bool
diff --git a/src/cmd/compile/internal/gc/gsubr.go b/src/cmd/compile/internal/gc/gsubr.go
index f39ffc7365..16602b9988 100644
--- a/src/cmd/compile/internal/gc/gsubr.go
+++ b/src/cmd/compile/internal/gc/gsubr.go
@@ -185,24 +185,6 @@ func (pp *Progs) settext(fn *Node) {
ptxt.From.Type = obj.TYPE_MEM
ptxt.From.Name = obj.NAME_EXTERN
ptxt.From.Sym = fn.Func.lsym
-
- p := pp.Prog(obj.AFUNCDATA)
- Addrconst(&p.From, objabi.FUNCDATA_ArgsPointerMaps)
- p.To.Type = obj.TYPE_MEM
- p.To.Name = obj.NAME_EXTERN
- p.To.Sym = &fn.Func.lsym.Func.GCArgs
-
- p = pp.Prog(obj.AFUNCDATA)
- Addrconst(&p.From, objabi.FUNCDATA_LocalsPointerMaps)
- p.To.Type = obj.TYPE_MEM
- p.To.Name = obj.NAME_EXTERN
- p.To.Sym = &fn.Func.lsym.Func.GCLocals
-
- p = pp.Prog(obj.AFUNCDATA)
- Addrconst(&p.From, objabi.FUNCDATA_RegPointerMaps)
- p.To.Type = obj.TYPE_MEM
- p.To.Name = obj.NAME_EXTERN
- p.To.Sym = &fn.Func.lsym.Func.GCRegs
}
func (f *Func) initLSym() {
diff --git a/src/cmd/compile/internal/gc/iexport.go b/src/cmd/compile/internal/gc/iexport.go
index d21378df4a..e77ca9a6c1 100644
--- a/src/cmd/compile/internal/gc/iexport.go
+++ b/src/cmd/compile/internal/gc/iexport.go
@@ -909,7 +909,7 @@ func (w *exportWriter) mpfloat(f *big.Float, typ *types.Type) {
manti, acc := mant.Int(nil)
if acc != big.Exact {
- Fatalf("exporter: internal error")
+ Fatalf("mantissa scaling failed for %f (%s)", f, acc)
}
w.mpint(manti, typ)
if manti.Sign() != 0 {
diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go
index 0b91d49188..b26758a77e 100644
--- a/src/cmd/compile/internal/gc/inl.go
+++ b/src/cmd/compile/internal/gc/inl.go
@@ -38,9 +38,10 @@ import (
const (
inlineMaxBudget = 80
inlineExtraAppendCost = 0
- inlineExtraCallCost = inlineMaxBudget // default is do not inline, -l=4 enables by using 1 instead.
- inlineExtraPanicCost = 1 // do not penalize inlining panics.
- inlineExtraThrowCost = inlineMaxBudget // with current (2018-05/1.11) code, inlining runtime.throw does not help.
+ // default is to inline if there's at most one call. -l=4 overrides this by using 1 instead.
+ inlineExtraCallCost = inlineMaxBudget * 3 / 4
+ inlineExtraPanicCost = 1 // do not penalize inlining panics.
+ inlineExtraThrowCost = inlineMaxBudget // with current (2018-05/1.11) code, inlining runtime.throw does not help.
inlineBigFunctionNodes = 5000 // Functions with this many nodes are considered "big".
inlineBigFunctionMaxCost = 20 // Max cost of inlinee when inlining into a "big" function.
@@ -141,6 +142,13 @@ func caninl(fn *Node) {
return
}
+ // If marked as "go:uintptrescapes", don't inline, since the
+ // escape information is lost during inlining.
+ if fn.Func.Pragma&UintptrEscapes != 0 {
+ reason = "marked as having an escaping uintptr argument"
+ return
+ }
+
// The nowritebarrierrec checker currently works at function
// granularity, so inlining yeswritebarrierrec functions can
// confuse it (#22342). As a workaround, disallow inlining
diff --git a/src/cmd/compile/internal/gc/inl_test.go b/src/cmd/compile/internal/gc/inl_test.go
index ac86cda2b8..5a8c19e2cb 100644
--- a/src/cmd/compile/internal/gc/inl_test.go
+++ b/src/cmd/compile/internal/gc/inl_test.go
@@ -55,6 +55,7 @@ func TestIntendedInlining(t *testing.T) {
"isDirectIface",
"itabHashFunc",
"noescape",
+ "pcvalueCacheKey",
"readUnaligned32",
"readUnaligned64",
"releasem",
diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go
index 3b302a5124..bd68ebffff 100644
--- a/src/cmd/compile/internal/gc/lex.go
+++ b/src/cmd/compile/internal/gc/lex.go
@@ -114,6 +114,14 @@ func (p *noder) pragcgo(pos syntax.Pos, text string) {
case len(f) == 3 && !isQuoted(f[1]) && !isQuoted(f[2]):
case len(f) == 4 && !isQuoted(f[1]) && !isQuoted(f[2]) && isQuoted(f[3]):
f[3] = strings.Trim(f[3], `"`)
+ if objabi.GOOS == "aix" && f[3] != "" {
+ // On Aix, library pattern must be "lib.a/object.o"
+ n := strings.Split(f[3], "/")
+ if len(n) != 2 || !strings.HasSuffix(n[0], ".a") || !strings.HasSuffix(n[1], ".o") {
+ p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_dynamic local [remote ["lib.a/object.o"]]`})
+ return
+ }
+ }
default:
p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_dynamic local [remote ["library"]]`})
return
diff --git a/src/cmd/compile/internal/gc/lex_test.go b/src/cmd/compile/internal/gc/lex_test.go
index fecf570fa1..e05726c9f3 100644
--- a/src/cmd/compile/internal/gc/lex_test.go
+++ b/src/cmd/compile/internal/gc/lex_test.go
@@ -7,6 +7,7 @@ package gc
import (
"cmd/compile/internal/syntax"
"reflect"
+ "runtime"
"testing"
)
@@ -49,10 +50,12 @@ func TestPragmaFields(t *testing.T) {
}
func TestPragcgo(t *testing.T) {
- var tests = []struct {
+ type testStruct struct {
in string
want []string
- }{
+ }
+
+ var tests = []testStruct{
{`go:cgo_export_dynamic local`, []string{`cgo_export_dynamic`, `local`}},
{`go:cgo_export_dynamic local remote`, []string{`cgo_export_dynamic`, `local`, `remote`}},
{`go:cgo_export_dynamic local' remote'`, []string{`cgo_export_dynamic`, `local'`, `remote'`}},
@@ -61,8 +64,6 @@ func TestPragcgo(t *testing.T) {
{`go:cgo_export_static local' remote'`, []string{`cgo_export_static`, `local'`, `remote'`}},
{`go:cgo_import_dynamic local`, []string{`cgo_import_dynamic`, `local`}},
{`go:cgo_import_dynamic local remote`, []string{`cgo_import_dynamic`, `local`, `remote`}},
- {`go:cgo_import_dynamic local remote "library"`, []string{`cgo_import_dynamic`, `local`, `remote`, `library`}},
- {`go:cgo_import_dynamic local' remote' "lib rary"`, []string{`cgo_import_dynamic`, `local'`, `remote'`, `lib rary`}},
{`go:cgo_import_static local`, []string{`cgo_import_static`, `local`}},
{`go:cgo_import_static local'`, []string{`cgo_import_static`, `local'`}},
{`go:cgo_dynamic_linker "/path/"`, []string{`cgo_dynamic_linker`, `/path/`}},
@@ -71,17 +72,50 @@ func TestPragcgo(t *testing.T) {
{`go:cgo_ldflag "a rg"`, []string{`cgo_ldflag`, `a rg`}},
}
+ if runtime.GOOS != "aix" {
+ tests = append(tests, []testStruct{
+ {`go:cgo_import_dynamic local remote "library"`, []string{`cgo_import_dynamic`, `local`, `remote`, `library`}},
+ {`go:cgo_import_dynamic local' remote' "lib rary"`, []string{`cgo_import_dynamic`, `local'`, `remote'`, `lib rary`}},
+ }...)
+ } else {
+ // cgo_import_dynamic with a library is slightly different on AIX
+ // as the library field must follow the pattern [libc.a/object.o].
+ tests = append(tests, []testStruct{
+ {`go:cgo_import_dynamic local remote "lib.a/obj.o"`, []string{`cgo_import_dynamic`, `local`, `remote`, `lib.a/obj.o`}},
+ // This test must fail.
+ {`go:cgo_import_dynamic local' remote' "library"`, []string{`: usage: //go:cgo_import_dynamic local [remote ["lib.a/object.o"]]`}},
+ }...)
+
+ }
+
var p noder
var nopos syntax.Pos
for _, tt := range tests {
- p.pragcgobuf = nil
- p.pragcgo(nopos, tt.in)
- got := p.pragcgobuf
- want := [][]string{tt.want}
- if !reflect.DeepEqual(got, want) {
- t.Errorf("pragcgo(%q) = %q; want %q", tt.in, got, want)
- continue
+ p.err = make(chan syntax.Error)
+ gotch := make(chan [][]string)
+ go func() {
+ p.pragcgobuf = nil
+ p.pragcgo(nopos, tt.in)
+ if p.pragcgobuf != nil {
+ gotch <- p.pragcgobuf
+ }
+ }()
+
+ select {
+ case e := <-p.err:
+ want := tt.want[0]
+ if e.Error() != want {
+ t.Errorf("pragcgo(%q) = %q; want %q", tt.in, e, want)
+ continue
+ }
+ case got := <-gotch:
+ want := [][]string{tt.want}
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("pragcgo(%q) = %q; want %q", tt.in, got, want)
+ continue
+ }
}
+
}
}
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
index 8e1b3b8fca..cdc461aac1 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -229,6 +229,9 @@ func Main(archInit func(*Arch)) {
flag.BoolVar(&flag_race, "race", false, "enable race detector")
}
objabi.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s'])
+ if enableTrace {
+ flag.BoolVar(&trace, "t", false, "trace type-checking")
+ }
flag.StringVar(&pathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths")
flag.BoolVar(&Debug_vlog, "v", false, "increase debug verbosity")
objabi.Flagcount("w", "debug type checking", &Debug['w'])
@@ -488,13 +491,17 @@ func Main(archInit func(*Arch)) {
// Phase 1: const, type, and names and types of funcs.
// This will gather all the information about types
// and methods but doesn't depend on any of it.
+ //
+ // We also defer type alias declarations until phase 2
+ // to avoid cycles like #18640.
+ // TODO(gri) Remove this again once we have a fix for #25838.
defercheckwidth()
// Don't use range--typecheck can add closures to xtop.
timings.Start("fe", "typecheck", "top1")
for i := 0; i < len(xtop); i++ {
n := xtop[i]
- if op := n.Op; op != ODCL && op != OAS && op != OAS2 {
+ if op := n.Op; op != ODCL && op != OAS && op != OAS2 && (op != ODCLTYPE || !n.Left.Name.Param.Alias) {
xtop[i] = typecheck(n, Etop)
}
}
@@ -506,7 +513,7 @@ func Main(archInit func(*Arch)) {
timings.Start("fe", "typecheck", "top2")
for i := 0; i < len(xtop); i++ {
n := xtop[i]
- if op := n.Op; op == ODCL || op == OAS || op == OAS2 {
+ if op := n.Op; op == ODCL || op == OAS || op == OAS2 || op == ODCLTYPE && n.Left.Name.Param.Alias {
xtop[i] = typecheck(n, Etop)
}
}
diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go
index a9dd092b67..5630e12ace 100644
--- a/src/cmd/compile/internal/gc/obj.go
+++ b/src/cmd/compile/internal/gc/obj.go
@@ -273,22 +273,18 @@ func dumpglobls() {
}
// addGCLocals adds gcargs, gclocals, gcregs, and stack object symbols to Ctxt.Data.
-// It takes care not to add any duplicates.
-// Though the object file format handles duplicates efficiently,
-// storing only a single copy of the data,
-// failure to remove these duplicates adds a few percent to object file size.
+//
+// This is done during the sequential phase after compilation, since
+// global symbols can't be declared during parallel compilation.
func addGCLocals() {
- seen := make(map[string]bool)
for _, s := range Ctxt.Text {
if s.Func == nil {
continue
}
- for _, gcsym := range []*obj.LSym{&s.Func.GCArgs, &s.Func.GCLocals, &s.Func.GCRegs} {
- if seen[gcsym.Name] {
- continue
+ for _, gcsym := range []*obj.LSym{s.Func.GCArgs, s.Func.GCLocals, s.Func.GCRegs} {
+ if gcsym != nil && !gcsym.OnList() {
+ ggloblsym(gcsym, int32(len(gcsym.P)), obj.RODATA|obj.DUPOK)
}
- Ctxt.Data = append(Ctxt.Data, gcsym)
- seen[gcsym.Name] = true
}
if x := s.Func.StackObjects; x != nil {
ggloblsym(x, int32(len(x.P)), obj.RODATA|obj.LOCAL)
diff --git a/src/cmd/compile/internal/gc/op_string.go b/src/cmd/compile/internal/gc/op_string.go
index 83283c72c6..34c3249d90 100644
--- a/src/cmd/compile/internal/gc/op_string.go
+++ b/src/cmd/compile/internal/gc/op_string.go
@@ -4,9 +4,9 @@ package gc
import "strconv"
-const _Op_name = "XXXNAMENONAMETYPEPACKLITERALADDSUBORXORADDSTRADDRANDANDAPPENDARRAYBYTESTRARRAYBYTESTRTMPARRAYRUNESTRSTRARRAYBYTESTRARRAYBYTETMPSTRARRAYRUNEASAS2AS2FUNCAS2RECVAS2MAPRAS2DOTTYPEASOPCALLCALLFUNCCALLMETHCALLINTERCALLPARTCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDCLFIELDDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTINDINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMULDIVMODLSHRSHANDANDNOTNEWNOTCOMPLUSMINUSORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICEHEADERSLICE3SLICE3ARRRECOVERRECVRUNESTRSELRECVSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFBLOCKBREAKCASEXCASECONTINUEDEFEREMPTYFALLFORFORUNTILGOTOIFLABELPROCRANGERETURNSELECTSWITCHTYPESWTCHANTMAPTSTRUCTTINTERTFUNCTARRAYDDDDDDARGINLCALLEFACEITABIDATASPTRCLOSUREVARCFUNCCHECKNILVARDEFVARKILLVARLIVEINDREGSPRETJMPGETGEND"
+const _Op_name = "XXXNAMENONAMETYPEPACKLITERALADDSUBORXORADDSTRADDRANDANDAPPENDARRAYBYTESTRARRAYBYTESTRTMPARRAYRUNESTRSTRARRAYBYTESTRARRAYBYTETMPSTRARRAYRUNEASAS2AS2FUNCAS2RECVAS2MAPRAS2DOTTYPEASOPCALLCALLFUNCCALLMETHCALLINTERCALLPARTCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDCLFIELDDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTINDINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMULDIVMODLSHRSHANDANDNOTNEWNOTCOMPLUSMINUSORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECVRUNESTRSELRECVSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFBLOCKBREAKCASEXCASECONTINUEDEFEREMPTYFALLFORFORUNTILGOTOIFLABELPROCRANGERETURNSELECTSWITCHTYPESWTCHANTMAPTSTRUCTTINTERTFUNCTARRAYDDDDDDARGINLCALLEFACEITABIDATASPTRCLOSUREVARCFUNCCHECKNILVARDEFVARKILLVARLIVEINDREGSPRETJMPGETGEND"
-var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 36, 39, 45, 49, 55, 61, 73, 88, 100, 112, 127, 139, 141, 144, 151, 158, 165, 175, 179, 183, 191, 199, 208, 216, 219, 224, 231, 238, 244, 253, 261, 269, 275, 279, 288, 295, 299, 302, 309, 317, 325, 332, 338, 341, 347, 354, 362, 366, 373, 381, 383, 385, 387, 389, 391, 393, 396, 401, 409, 412, 421, 424, 428, 436, 443, 452, 455, 458, 461, 464, 467, 470, 476, 479, 482, 485, 489, 494, 498, 503, 508, 514, 519, 523, 528, 536, 544, 555, 561, 570, 577, 581, 588, 595, 603, 607, 611, 615, 622, 629, 637, 643, 648, 653, 657, 662, 670, 675, 680, 684, 687, 695, 699, 701, 706, 710, 715, 721, 727, 733, 739, 744, 748, 755, 761, 766, 772, 775, 781, 788, 793, 797, 802, 806, 816, 821, 829, 835, 842, 849, 857, 863, 867, 870}
+var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 36, 39, 45, 49, 55, 61, 73, 88, 100, 112, 127, 139, 141, 144, 151, 158, 165, 175, 179, 183, 191, 199, 208, 216, 219, 224, 231, 238, 244, 253, 261, 269, 275, 279, 288, 295, 299, 302, 309, 317, 325, 332, 338, 341, 347, 354, 362, 366, 373, 381, 383, 385, 387, 389, 391, 393, 396, 401, 409, 412, 421, 424, 428, 436, 443, 452, 455, 458, 461, 464, 467, 470, 476, 479, 482, 485, 489, 494, 498, 503, 508, 514, 519, 523, 528, 536, 544, 550, 559, 570, 577, 581, 588, 595, 603, 607, 611, 615, 622, 629, 637, 643, 648, 653, 657, 662, 670, 675, 680, 684, 687, 695, 699, 701, 706, 710, 715, 721, 727, 733, 739, 744, 748, 755, 761, 766, 772, 775, 781, 788, 793, 797, 802, 806, 816, 821, 829, 835, 842, 849, 857, 863, 867, 870}
func (i Op) String() string {
if i >= Op(len(_Op_index)-1) {
diff --git a/src/cmd/compile/internal/gc/plive.go b/src/cmd/compile/internal/gc/plive.go
index a38c33647e..2c31d5feb9 100644
--- a/src/cmd/compile/internal/gc/plive.go
+++ b/src/cmd/compile/internal/gc/plive.go
@@ -1019,7 +1019,7 @@ func (lv *Liveness) epilogue() {
live := lv.livevars[index]
if v.Op.IsCall() && live.regs != 0 {
lv.printDebug()
- v.Fatalf("internal error: %v register %s recorded as live at call", lv.fn.Func.Nname, live.regs.niceString(lv.f.Config))
+ v.Fatalf("%v register %s recorded as live at call", lv.fn.Func.Nname, live.regs.niceString(lv.f.Config))
}
index++
}
@@ -1038,7 +1038,7 @@ func (lv *Liveness) epilogue() {
// input parameters.
for j, n := range lv.vars {
if n.Class() != PPARAM && lv.stackMaps[0].Get(int32(j)) {
- Fatalf("internal error: %v %L recorded as live on entry", lv.fn.Func.Nname, n)
+ lv.f.Fatalf("%v %L recorded as live on entry", lv.fn.Func.Nname, n)
}
}
// Check that no registers are live at function entry.
@@ -1047,7 +1047,7 @@ func (lv *Liveness) epilogue() {
// so it doesn't appear live at entry.
if regs := lv.regMaps[0]; regs != 0 {
lv.printDebug()
- lv.f.Fatalf("internal error: %v register %s recorded as live on entry", lv.fn.Func.Nname, regs.niceString(lv.f.Config))
+ lv.f.Fatalf("%v register %s recorded as live on entry", lv.fn.Func.Nname, regs.niceString(lv.f.Config))
}
}
@@ -1461,7 +1461,7 @@ func (lv *Liveness) printDebug() {
// first word dumped is the total number of bitmaps. The second word is the
// length of the bitmaps. All bitmaps are assumed to be of equal length. The
// remaining bytes are the raw bitmaps.
-func (lv *Liveness) emit(argssym, livesym, regssym *obj.LSym) {
+func (lv *Liveness) emit() (argsSym, liveSym, regsSym *obj.LSym) {
// Size args bitmaps to be just large enough to hold the largest pointer.
// First, find the largest Xoffset node we care about.
// (Nodes without pointers aren't in lv.vars; see livenessShouldTrack.)
@@ -1489,13 +1489,16 @@ func (lv *Liveness) emit(argssym, livesym, regssym *obj.LSym) {
// This would require shifting all bitmaps.
maxLocals := lv.stkptrsize
+ // Temporary symbols for encoding bitmaps.
+ var argsSymTmp, liveSymTmp, regsSymTmp obj.LSym
+
args := bvalloc(int32(maxArgs / int64(Widthptr)))
- aoff := duint32(argssym, 0, uint32(len(lv.stackMaps))) // number of bitmaps
- aoff = duint32(argssym, aoff, uint32(args.n)) // number of bits in each bitmap
+ aoff := duint32(&argsSymTmp, 0, uint32(len(lv.stackMaps))) // number of bitmaps
+ aoff = duint32(&argsSymTmp, aoff, uint32(args.n)) // number of bits in each bitmap
locals := bvalloc(int32(maxLocals / int64(Widthptr)))
- loff := duint32(livesym, 0, uint32(len(lv.stackMaps))) // number of bitmaps
- loff = duint32(livesym, loff, uint32(locals.n)) // number of bits in each bitmap
+ loff := duint32(&liveSymTmp, 0, uint32(len(lv.stackMaps))) // number of bitmaps
+ loff = duint32(&liveSymTmp, loff, uint32(locals.n)) // number of bits in each bitmap
for _, live := range lv.stackMaps {
args.Clear()
@@ -1503,13 +1506,13 @@ func (lv *Liveness) emit(argssym, livesym, regssym *obj.LSym) {
lv.pointerMap(live, lv.vars, args, locals)
- aoff = dbvec(argssym, aoff, args)
- loff = dbvec(livesym, loff, locals)
+ aoff = dbvec(&argsSymTmp, aoff, args)
+ loff = dbvec(&liveSymTmp, loff, locals)
}
regs := bvalloc(lv.usedRegs())
- roff := duint32(regssym, 0, uint32(len(lv.regMaps))) // number of bitmaps
- roff = duint32(regssym, roff, uint32(regs.n)) // number of bits in each bitmap
+ roff := duint32(®sSymTmp, 0, uint32(len(lv.regMaps))) // number of bitmaps
+ roff = duint32(®sSymTmp, roff, uint32(regs.n)) // number of bits in each bitmap
if regs.n > 32 {
// Our uint32 conversion below won't work.
Fatalf("GP registers overflow uint32")
@@ -1519,25 +1522,29 @@ func (lv *Liveness) emit(argssym, livesym, regssym *obj.LSym) {
for _, live := range lv.regMaps {
regs.Clear()
regs.b[0] = uint32(live)
- roff = dbvec(regssym, roff, regs)
+ roff = dbvec(®sSymTmp, roff, regs)
}
}
// Give these LSyms content-addressable names,
// so that they can be de-duplicated.
// This provides significant binary size savings.
- // It is safe to rename these LSyms because
- // they are tracked separately from ctxt.hash.
- argssym.Name = fmt.Sprintf("gclocals·%x", md5.Sum(argssym.P))
- livesym.Name = fmt.Sprintf("gclocals·%x", md5.Sum(livesym.P))
- regssym.Name = fmt.Sprintf("gclocals·%x", md5.Sum(regssym.P))
+ //
+ // These symbols will be added to Ctxt.Data by addGCLocals
+ // after parallel compilation is done.
+ makeSym := func(tmpSym *obj.LSym) *obj.LSym {
+ return Ctxt.LookupInit(fmt.Sprintf("gclocals·%x", md5.Sum(tmpSym.P)), func(lsym *obj.LSym) {
+ lsym.P = tmpSym.P
+ })
+ }
+ return makeSym(&argsSymTmp), makeSym(&liveSymTmp), makeSym(®sSymTmp)
}
// Entry pointer for liveness analysis. Solves for the liveness of
// pointer variables in the function and emits a runtime data
// structure read by the garbage collector.
// Returns a map from GC safe points to their corresponding stack map index.
-func liveness(e *ssafn, f *ssa.Func) LivenessMap {
+func liveness(e *ssafn, f *ssa.Func, pp *Progs) LivenessMap {
// Construct the global liveness state.
vars, idx := getvariables(e.curfn)
lv := newliveness(e.curfn, f, vars, idx, e.stkptrsize)
@@ -1577,7 +1584,25 @@ func liveness(e *ssafn, f *ssa.Func) LivenessMap {
// Emit the live pointer map data structures
if ls := e.curfn.Func.lsym; ls != nil {
- lv.emit(&ls.Func.GCArgs, &ls.Func.GCLocals, &ls.Func.GCRegs)
+ ls.Func.GCArgs, ls.Func.GCLocals, ls.Func.GCRegs = lv.emit()
+
+ p := pp.Prog(obj.AFUNCDATA)
+ Addrconst(&p.From, objabi.FUNCDATA_ArgsPointerMaps)
+ p.To.Type = obj.TYPE_MEM
+ p.To.Name = obj.NAME_EXTERN
+ p.To.Sym = ls.Func.GCArgs
+
+ p = pp.Prog(obj.AFUNCDATA)
+ Addrconst(&p.From, objabi.FUNCDATA_LocalsPointerMaps)
+ p.To.Type = obj.TYPE_MEM
+ p.To.Name = obj.NAME_EXTERN
+ p.To.Sym = ls.Func.GCLocals
+
+ p = pp.Prog(obj.AFUNCDATA)
+ Addrconst(&p.From, objabi.FUNCDATA_RegPointerMaps)
+ p.To.Type = obj.TYPE_MEM
+ p.To.Name = obj.NAME_EXTERN
+ p.To.Sym = ls.Func.GCRegs
}
return lv.livenessMap
}
diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go
index d1835b51c4..605401f090 100644
--- a/src/cmd/compile/internal/gc/reflect.go
+++ b/src/cmd/compile/internal/gc/reflect.go
@@ -812,7 +812,7 @@ func dcommontype(lsym *obj.LSym, t *types.Type) int {
sptrWeak := true
var sptr *obj.LSym
- if !t.IsPtr() || t.PtrBase != nil {
+ if !t.IsPtr() || t.IsPtrElem() {
tptr := types.NewPtr(t)
if t.Sym != nil || methods(tptr) != nil {
sptrWeak = false
@@ -1137,7 +1137,7 @@ func dtypesym(t *types.Type) *obj.LSym {
return lsym
}
// TODO(mdempsky): Investigate whether this can happen.
- if isforw[tbase.Etype] {
+ if tbase.Etype == TFORW {
return lsym
}
}
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index 4607cf1912..b0ccd01752 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -5051,7 +5051,7 @@ func genssa(f *ssa.Func, pp *Progs) {
e := f.Frontend().(*ssafn)
- s.livenessMap = liveness(e, f)
+ s.livenessMap = liveness(e, f, pp)
emitStackObjects(e, pp)
// Remember where each block starts.
diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go
index 0fe6defe99..e29a3d7657 100644
--- a/src/cmd/compile/internal/gc/syntax.go
+++ b/src/cmd/compile/internal/gc/syntax.go
@@ -929,7 +929,7 @@ type nodeQueue struct {
head, tail int
}
-// empty returns true if q contains no Nodes.
+// empty reports whether q contains no Nodes.
func (q *nodeQueue) empty() bool {
return q.head == q.tail
}
diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go
index 6ee52eae84..e6a8ed4bda 100644
--- a/src/cmd/compile/internal/gc/typecheck.go
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -12,6 +12,50 @@ import (
"strings"
)
+// To enable tracing support (-t flag), set enableTrace to true.
+const enableTrace = false
+
+var trace bool
+var traceIndent []byte
+
+func tracePrint(title string, n *Node) func(np **Node) {
+ indent := traceIndent
+
+ // guard against nil
+ var pos, op string
+ var tc uint8
+ if n != nil {
+ pos = linestr(n.Pos)
+ op = n.Op.String()
+ tc = n.Typecheck()
+ }
+
+ fmt.Printf("%s: %s%s %p %s %v tc=%d\n", pos, indent, title, n, op, n, tc)
+ traceIndent = append(traceIndent, ". "...)
+
+ return func(np **Node) {
+ traceIndent = traceIndent[:len(traceIndent)-2]
+
+ // if we have a result, use that
+ if np != nil {
+ n = *np
+ }
+
+ // guard against nil
+ // use outer pos, op so we don't get empty pos/op if n == nil (nicer output)
+ var tc uint8
+ var typ *types.Type
+ if n != nil {
+ pos = linestr(n.Pos)
+ op = n.Op.String()
+ tc = n.Typecheck()
+ typ = n.Type
+ }
+
+ fmt.Printf("%s: %s=> %p %s %v tc=%d type=%#L\n", pos, indent, n, op, n, tc, typ)
+ }
+}
+
const (
Etop = 1 << iota // evaluated at statement level
Erv // evaluated in value context
@@ -31,11 +75,16 @@ const (
var typecheckdefstack []*Node
// resolve ONONAME to definition, if any.
-func resolve(n *Node) *Node {
+func resolve(n *Node) (res *Node) {
if n == nil || n.Op != ONONAME {
return n
}
+ // only trace if there's work to do
+ if enableTrace && trace {
+ defer tracePrint("resolve", n)(&res)
+ }
+
if n.Sym.Pkg != localpkg {
if inimport {
Fatalf("recursive inimport")
@@ -150,7 +199,7 @@ var typecheck_tcstack []*Node
// typecheck type checks node n.
// The result of typecheck MUST be assigned back to n, e.g.
// n.Left = typecheck(n.Left, top)
-func typecheck(n *Node, top int) *Node {
+func typecheck(n *Node, top int) (res *Node) {
// cannot type check until all the source has been parsed
if !typecheckok {
Fatalf("early typecheck")
@@ -160,6 +209,11 @@ func typecheck(n *Node, top int) *Node {
return nil
}
+ // only trace if there's work to do
+ if enableTrace && trace {
+ defer tracePrint("typecheck", n)(&res)
+ }
+
lno := setlineno(n)
// Skip over parens.
@@ -201,8 +255,16 @@ func typecheck(n *Node, top int) *Node {
// since it would expand indefinitely when aliases
// are substituted.
cycle := cycleFor(n)
- for _, n := range cycle {
- if n.Name != nil && !n.Name.Param.Alias {
+ for _, n1 := range cycle {
+ if n1.Name != nil && !n1.Name.Param.Alias {
+ // Cycle is ok. But if n is an alias type and doesn't
+ // have a type yet, we have a recursive type declaration
+ // with aliases that we can't handle properly yet.
+ // Report an error rather than crashing later.
+ if n.Name != nil && n.Name.Param.Alias && n.Type == nil {
+ lineno = n.Pos
+ Fatalf("cannot handle alias type declaration (issue #25838): %v", n)
+ }
lineno = lno
return n
}
@@ -294,7 +356,11 @@ func indexlit(n *Node) *Node {
// The result of typecheck1 MUST be assigned back to n, e.g.
// n.Left = typecheck1(n.Left, top)
-func typecheck1(n *Node, top int) *Node {
+func typecheck1(n *Node, top int) (res *Node) {
+ if enableTrace && trace {
+ defer tracePrint("typecheck1", n)(&res)
+ }
+
switch n.Op {
case OLITERAL, ONAME, ONONAME, OTYPE:
if n.Sym == nil {
@@ -1094,11 +1160,15 @@ func typecheck1(n *Node, top int) *Node {
ok |= Erv
t := n.Type
+ if t == nil {
+ Fatalf("no type specified for OSLICEHEADER")
+ }
+
if !t.IsSlice() {
Fatalf("invalid type %v for OSLICEHEADER", n.Type)
}
- if !n.Left.Type.IsUnsafePtr() {
+ if n.Left == nil || n.Left.Type == nil || !n.Left.Type.IsUnsafePtr() {
Fatalf("need unsafe.Pointer for OSLICEHEADER")
}
@@ -2381,7 +2451,11 @@ func lookdot1(errnode *Node, s *types.Sym, t *types.Type, fs *types.Fields, dost
// typecheckMethodExpr checks selector expressions (ODOT) where the
// base expression is a type expression (OTYPE).
-func typecheckMethodExpr(n *Node) *Node {
+func typecheckMethodExpr(n *Node) (res *Node) {
+ if enableTrace && trace {
+ defer tracePrint("typecheckMethodExpr", n)(&res)
+ }
+
t := n.Left.Type
// Compute the method set for t.
@@ -2924,7 +2998,11 @@ func pushtype(n *Node, t *types.Type) {
// The result of typecheckcomplit MUST be assigned back to n, e.g.
// n.Left = typecheckcomplit(n.Left)
-func typecheckcomplit(n *Node) *Node {
+func typecheckcomplit(n *Node) (res *Node) {
+ if enableTrace && trace {
+ defer tracePrint("typecheckcomplit", n)(&res)
+ }
+
lno := lineno
defer func() {
lineno = lno
@@ -3337,6 +3415,10 @@ func samesafeexpr(l *Node, r *Node) bool {
// if this assignment is the definition of a var on the left side,
// fill in the var's type.
func typecheckas(n *Node) {
+ if enableTrace && trace {
+ defer tracePrint("typecheckas", n)(nil)
+ }
+
// delicate little dance.
// the definition of n may refer to this assignment
// as its definition, in which case it will call typecheckas.
@@ -3393,6 +3475,10 @@ func checkassignto(src *types.Type, dst *Node) {
}
func typecheckas2(n *Node) {
+ if enableTrace && trace {
+ defer tracePrint("typecheckas2", n)(nil)
+ }
+
ls := n.List.Slice()
for i1, n1 := range ls {
// delicate little dance.
@@ -3521,6 +3607,10 @@ out:
// type check function definition
func typecheckfunc(n *Node) {
+ if enableTrace && trace {
+ defer tracePrint("typecheckfunc", n)(nil)
+ }
+
for _, ln := range n.Func.Dcl {
if ln.Op == ONAME && (ln.Class() == PPARAM || ln.Class() == PPARAMOUT) {
ln.Name.Decldepth = 1
@@ -3593,8 +3683,7 @@ func copytype(n *Node, t *types.Type) {
embedlineno := n.Type.ForwardType().Embedlineno
l := n.Type.ForwardType().Copyto
- ptrBase := n.Type.PtrBase
- sliceOf := n.Type.SliceOf
+ cache := n.Type.Cache
// TODO(mdempsky): Fix Type rekinding.
*n.Type = *t
@@ -3615,8 +3704,7 @@ func copytype(n *Node, t *types.Type) {
t.Nod = asTypesNode(n)
t.SetDeferwidth(false)
- t.PtrBase = ptrBase
- t.SliceOf = sliceOf
+ t.Cache = cache
// Propagate go:notinheap pragma from the Name to the Type.
if n.Name != nil && n.Name.Param != nil && n.Name.Param.Pragma&NotInHeap != 0 {
@@ -3637,6 +3725,10 @@ func copytype(n *Node, t *types.Type) {
}
func typecheckdeftype(n *Node) {
+ if enableTrace && trace {
+ defer tracePrint("typecheckdeftype", n)(nil)
+ }
+
n.Type.Sym = n.Sym
n.SetTypecheck(1)
n.Name.Param.Ntype = typecheck(n.Name.Param.Ntype, Etype)
@@ -3654,6 +3746,10 @@ func typecheckdeftype(n *Node) {
}
func typecheckdef(n *Node) {
+ if enableTrace && trace {
+ defer tracePrint("typecheckdef", n)(nil)
+ }
+
lno := setlineno(n)
if n.Op == ONONAME {
@@ -3992,6 +4088,12 @@ func deadcode(fn *Node) {
}
func deadcodeslice(nn Nodes) {
+ var lastLabel = -1
+ for i, n := range nn.Slice() {
+ if n != nil && n.Op == OLABEL {
+ lastLabel = i
+ }
+ }
for i, n := range nn.Slice() {
// Cut is set to true when all nodes after i'th position
// should be removed.
@@ -4014,10 +4116,14 @@ func deadcodeslice(nn Nodes) {
// If "then" or "else" branch ends with panic or return statement,
// it is safe to remove all statements after this node.
// isterminating is not used to avoid goto-related complications.
+ // We must be careful not to deadcode-remove labels, as they
+ // might be the target of a goto. See issue 28616.
if body := body.Slice(); len(body) != 0 {
switch body[(len(body) - 1)].Op {
case ORETURN, ORETJMP, OPANIC:
- cut = true
+ if i > lastLabel {
+ cut = true
+ }
}
}
}
diff --git a/src/cmd/compile/internal/gc/universe.go b/src/cmd/compile/internal/gc/universe.go
index 96980ad500..760a8e40b0 100644
--- a/src/cmd/compile/internal/gc/universe.go
+++ b/src/cmd/compile/internal/gc/universe.go
@@ -200,8 +200,6 @@ func typeinit() {
isComplex[TCOMPLEX64] = true
isComplex[TCOMPLEX128] = true
- isforw[TFORW] = true
-
// initialize okfor
for et := types.EType(0); et < NTYPE; et++ {
if isInt[et] || et == TIDEAL {
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index 0e07efa0d9..37d995b1bd 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -384,41 +384,31 @@ func convFuncName(from, to *types.Type) (fnname string, needsaddr bool) {
tkind := to.Tie()
switch from.Tie() {
case 'I':
- switch tkind {
- case 'I':
+ if tkind == 'I' {
return "convI2I", false
}
case 'T':
+ switch {
+ case from.Size() == 2 && from.Align == 2:
+ return "convT16", false
+ case from.Size() == 4 && from.Align == 4 && !types.Haspointers(from):
+ return "convT32", false
+ case from.Size() == 8 && from.Align == types.Types[TUINT64].Align && !types.Haspointers(from):
+ return "convT64", false
+ case from.IsString():
+ return "convTstring", false
+ case from.IsSlice():
+ return "convTslice", false
+ }
+
switch tkind {
case 'E':
- switch {
- case from.Size() == 2 && from.Align == 2:
- return "convT2E16", false
- case from.Size() == 4 && from.Align == 4 && !types.Haspointers(from):
- return "convT2E32", false
- case from.Size() == 8 && from.Align == types.Types[TUINT64].Align && !types.Haspointers(from):
- return "convT2E64", false
- case from.IsString():
- return "convT2Estring", false
- case from.IsSlice():
- return "convT2Eslice", false
- case !types.Haspointers(from):
+ if !types.Haspointers(from) {
return "convT2Enoptr", true
}
return "convT2E", true
case 'I':
- switch {
- case from.Size() == 2 && from.Align == 2:
- return "convT2I16", false
- case from.Size() == 4 && from.Align == 4 && !types.Haspointers(from):
- return "convT2I32", false
- case from.Size() == 8 && from.Align == types.Types[TUINT64].Align && !types.Haspointers(from):
- return "convT2I64", false
- case from.IsString():
- return "convT2Istring", false
- case from.IsSlice():
- return "convT2Islice", false
- case !types.Haspointers(from):
+ if !types.Haspointers(from) {
return "convT2Inoptr", true
}
return "convT2I", true
@@ -496,7 +486,7 @@ opswitch:
OIND, OSPTR, OITAB, OIDATA, OADDR:
n.Left = walkexpr(n.Left, init)
- case OEFACE, OAND, OSUB, OMUL, OADD, OOR, OXOR:
+ case OEFACE, OAND, OSUB, OMUL, OADD, OOR, OXOR, OLSH, ORSH:
n.Left = walkexpr(n.Left, init)
n.Right = walkexpr(n.Right, init)
@@ -548,15 +538,6 @@ opswitch:
n.SetTypecheck(1)
}
- case OLSH, ORSH:
- n.Left = walkexpr(n.Left, init)
- n.Right = walkexpr(n.Right, init)
- t := n.Left.Type
- n.SetBounded(bounded(n.Right, 8*t.Width))
- if Debug['m'] != 0 && n.Bounded() && !Isconst(n.Right, CTINT) {
- Warn("shift bounds check elided")
- }
-
case OCOMPLEX:
// Use results from call expression as arguments for complex.
if n.Left == nil && n.Right == nil {
@@ -834,16 +815,21 @@ opswitch:
case OCONVIFACE:
n.Left = walkexpr(n.Left, init)
- // Optimize convT2E or convT2I as a two-word copy when T is pointer-shaped.
- if isdirectiface(n.Left.Type) {
- var t *Node
- if n.Type.IsEmptyInterface() {
- t = typename(n.Left.Type)
- } else {
- t = itabname(n.Left.Type, n.Type)
+ fromType := n.Left.Type
+ toType := n.Type
+
+ // typeword generates the type word of the interface value.
+ typeword := func() *Node {
+ if toType.IsEmptyInterface() {
+ return typename(fromType)
}
- l := nod(OEFACE, t, n.Left)
- l.Type = n.Type
+ return itabname(fromType, toType)
+ }
+
+ // Optimize convT2E or convT2I as a two-word copy when T is pointer-shaped.
+ if isdirectiface(fromType) {
+ l := nod(OEFACE, typeword(), n.Left)
+ l.Type = toType
l.SetTypecheck(n.Typecheck())
n = l
break
@@ -863,11 +849,11 @@ opswitch:
// or creating one on the stack.
var value *Node
switch {
- case n.Left.Type.Size() == 0:
+ case fromType.Size() == 0:
// n.Left is zero-sized. Use zerobase.
cheapexpr(n.Left, init) // Evaluate n.Left for side-effects. See issue 19246.
value = zerobase
- case n.Left.Type.IsBoolean() || (n.Left.Type.Size() == 1 && n.Left.Type.IsInteger()):
+ case fromType.IsBoolean() || (fromType.Size() == 1 && fromType.IsInteger()):
// n.Left is a bool/byte. Use staticbytes[n.Left].
n.Left = cheapexpr(n.Left, init)
value = nod(OINDEX, staticbytes, byteindex(n.Left))
@@ -875,23 +861,17 @@ opswitch:
case n.Left.Class() == PEXTERN && n.Left.Name != nil && n.Left.Name.Readonly():
// n.Left is a readonly global; use it directly.
value = n.Left
- case !n.Left.Type.IsInterface() && n.Esc == EscNone && n.Left.Type.Width <= 1024:
+ case !fromType.IsInterface() && n.Esc == EscNone && fromType.Width <= 1024:
// n.Left does not escape. Use a stack temporary initialized to n.Left.
- value = temp(n.Left.Type)
+ value = temp(fromType)
init.Append(typecheck(nod(OAS, value, n.Left), Etop))
}
if value != nil {
// Value is identical to n.Left.
// Construct the interface directly: {type/itab, &value}.
- var t *Node
- if n.Type.IsEmptyInterface() {
- t = typename(n.Left.Type)
- } else {
- t = itabname(n.Left.Type, n.Type)
- }
- l := nod(OEFACE, t, typecheck(nod(OADDR, value, nil), Erv))
- l.Type = n.Type
+ l := nod(OEFACE, typeword(), typecheck(nod(OADDR, value, nil), Erv))
+ l.Type = toType
l.SetTypecheck(n.Typecheck())
n = l
break
@@ -903,9 +883,9 @@ opswitch:
// tmp = tmp.type
// }
// e = iface{tmp, i.data}
- if n.Type.IsEmptyInterface() && n.Left.Type.IsInterface() && !n.Left.Type.IsEmptyInterface() {
+ if toType.IsEmptyInterface() && fromType.IsInterface() && !fromType.IsEmptyInterface() {
// Evaluate the input interface.
- c := temp(n.Left.Type)
+ c := temp(fromType)
init.Append(nod(OAS, c, n.Left))
// Get the itab out of the interface.
@@ -919,26 +899,43 @@ opswitch:
// Build the result.
e := nod(OEFACE, tmp, ifaceData(c, types.NewPtr(types.Types[TUINT8])))
- e.Type = n.Type // assign type manually, typecheck doesn't understand OEFACE.
+ e.Type = toType // assign type manually, typecheck doesn't understand OEFACE.
e.SetTypecheck(1)
n = e
break
}
- var ll []*Node
- if n.Type.IsEmptyInterface() {
- if !n.Left.Type.IsInterface() {
- ll = append(ll, typename(n.Left.Type))
- }
- } else {
- if n.Left.Type.IsInterface() {
- ll = append(ll, typename(n.Type))
- } else {
- ll = append(ll, itabname(n.Left.Type, n.Type))
- }
+ fnname, needsaddr := convFuncName(fromType, toType)
+
+ if !needsaddr && !fromType.IsInterface() {
+ // Use a specialized conversion routine that only returns a data pointer.
+ // ptr = convT2X(val)
+ // e = iface{typ/tab, ptr}
+ fn := syslook(fnname)
+ dowidth(fromType)
+ fn = substArgTypes(fn, fromType)
+ dowidth(fn.Type)
+ call := nod(OCALL, fn, nil)
+ call.List.Set1(n.Left)
+ call = typecheck(call, Erv)
+ call = walkexpr(call, init)
+ call = safeexpr(call, init)
+ e := nod(OEFACE, typeword(), call)
+ e.Type = toType
+ e.SetTypecheck(1)
+ n = e
+ break
+ }
+
+ var tab *Node
+ if fromType.IsInterface() {
+ // convI2I
+ tab = typename(toType)
+ } else {
+ // convT2x
+ tab = typeword()
}
- fnname, needsaddr := convFuncName(n.Left.Type, n.Type)
v := n.Left
if needsaddr {
// Types of large or unknown size are passed by reference.
@@ -952,14 +949,13 @@ opswitch:
}
v = nod(OADDR, v, nil)
}
- ll = append(ll, v)
- dowidth(n.Left.Type)
+ dowidth(fromType)
fn := syslook(fnname)
- fn = substArgTypes(fn, n.Left.Type, n.Type)
+ fn = substArgTypes(fn, fromType, toType)
dowidth(fn.Type)
n = nod(OCALL, fn, nil)
- n.List.Set(ll)
+ n.List.Set2(tab, v)
n = typecheck(n, Erv)
n = walkexpr(n, init)
@@ -1343,14 +1339,17 @@ opswitch:
argtype = types.Types[TINT]
}
+ m := nod(OSLICEHEADER, nil, nil)
+ m.Type = t
+
fn := syslook(fnname)
- n.Left = mkcall1(fn, types.Types[TUNSAFEPTR], init, typename(t.Elem()), conv(len, argtype), conv(cap, argtype))
- n.Left.SetNonNil(true)
- n.List.Set2(conv(len, types.Types[TINT]), conv(cap, types.Types[TINT]))
- n.Op = OSLICEHEADER
- n.Type = t
- n = typecheck(n, Erv)
- n = walkexpr(n, init)
+ m.Left = mkcall1(fn, types.Types[TUNSAFEPTR], init, typename(t.Elem()), conv(len, argtype), conv(cap, argtype))
+ m.Left.SetNonNil(true)
+ m.List.Set2(conv(len, types.Types[TINT]), conv(cap, types.Types[TINT]))
+
+ m = typecheck(m, Erv)
+ m = walkexpr(m, init)
+ n = m
}
case ORUNESTR:
diff --git a/src/cmd/compile/internal/ppc64/ssa.go b/src/cmd/compile/internal/ppc64/ssa.go
index a3f8b67177..a6dd8cab5f 100644
--- a/src/cmd/compile/internal/ppc64/ssa.go
+++ b/src/cmd/compile/internal/ppc64/ssa.go
@@ -569,7 +569,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
ssa.OpPPC64ROTL, ssa.OpPPC64ROTLW,
ssa.OpPPC64MULHD, ssa.OpPPC64MULHW, ssa.OpPPC64MULHDU, ssa.OpPPC64MULHWU,
ssa.OpPPC64FMUL, ssa.OpPPC64FMULS, ssa.OpPPC64FDIV, ssa.OpPPC64FDIVS, ssa.OpPPC64FCPSGN,
- ssa.OpPPC64AND, ssa.OpPPC64OR, ssa.OpPPC64ANDN, ssa.OpPPC64ORN, ssa.OpPPC64NOR, ssa.OpPPC64XOR, ssa.OpPPC64EQV:
+ ssa.OpPPC64AND, ssa.OpPPC64ANDCC, ssa.OpPPC64OR, ssa.OpPPC64ORCC, ssa.OpPPC64ANDN, ssa.OpPPC64ORN, ssa.OpPPC64NOR, ssa.OpPPC64XOR, ssa.OpPPC64XORCC, ssa.OpPPC64EQV:
r := v.Reg()
r1 := v.Args[0].Reg()
r2 := v.Args[1].Reg()
diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go
index e79629695a..558c4b7db8 100644
--- a/src/cmd/compile/internal/ssa/config.go
+++ b/src/cmd/compile/internal/ssa/config.go
@@ -112,7 +112,7 @@ type Logger interface {
// Logf logs a message from the compiler.
Logf(string, ...interface{})
- // Log returns true if logging is not a no-op
+ // Log reports whether logging is not a no-op
// some logging calls account for more than a few heap allocations.
Log() bool
diff --git a/src/cmd/compile/internal/ssa/debug.go b/src/cmd/compile/internal/ssa/debug.go
index 8df8a94b76..3d0be0fe1c 100644
--- a/src/cmd/compile/internal/ssa/debug.go
+++ b/src/cmd/compile/internal/ssa/debug.go
@@ -790,7 +790,7 @@ func (e *pendingEntry) clear() {
}
}
-// canMerge returns true if the location description for new is the same as
+// canMerge reports whether the location description for new is the same as
// pending.
func canMerge(pending, new VarLoc) bool {
if pending.absent() && new.absent() {
diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go
index 2ed4086fd1..d73d39ce28 100644
--- a/src/cmd/compile/internal/ssa/func.go
+++ b/src/cmd/compile/internal/ssa/func.go
@@ -621,7 +621,7 @@ func (f *Func) invalidateCFG() {
f.cachedLoopnest = nil
}
-// DebugHashMatch returns true if environment variable evname
+// DebugHashMatch reports whether environment variable evname
// 1) is empty (this is a special more-quickly implemented case of 3)
// 2) is "y" or "Y"
// 3) is a suffix of the sha1 hash of name
diff --git a/src/cmd/compile/internal/ssa/gen/PPC64.rules b/src/cmd/compile/internal/ssa/gen/PPC64.rules
index 0eaa88596b..24cee6f0a3 100644
--- a/src/cmd/compile/internal/ssa/gen/PPC64.rules
+++ b/src/cmd/compile/internal/ssa/gen/PPC64.rules
@@ -518,6 +518,13 @@
(LessEqual (InvertFlags x)) -> (GreaterEqual x)
(GreaterEqual (InvertFlags x)) -> (LessEqual x)
+// Elide compares of bit tests // TODO need to make both CC and result of ANDCC available.
+((EQ|NE|LT|LE|GT|GE) (CMPconst [0] (ANDconst [c] x)) yes no) -> ((EQ|NE|LT|LE|GT|GE) (ANDCCconst [c] x) yes no)
+((EQ|NE|LT|LE|GT|GE) (CMPWconst [0] (ANDconst [c] x)) yes no) -> ((EQ|NE|LT|LE|GT|GE) (ANDCCconst [c] x) yes no)
+((EQ|NE|LT|LE|GT|GE) (CMPconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> ((EQ|NE|LT|LE|GT|GE) (ANDCC x y) yes no)
+((EQ|NE|LT|LE|GT|GE) (CMPconst [0] z:(OR x y)) yes no) && z.Uses == 1 -> ((EQ|NE|LT|LE|GT|GE) (ORCC x y) yes no)
+((EQ|NE|LT|LE|GT|GE) (CMPconst [0] z:(XOR x y)) yes no) && z.Uses == 1 -> ((EQ|NE|LT|LE|GT|GE) (XORCC x y) yes no)
+
// Lowering loads
(Load ptr mem) && (is64BitInt(t) || isPtr(t)) -> (MOVDload ptr mem)
(Load ptr mem) && is32BitInt(t) && isSigned(t) -> (MOVWload ptr mem)
diff --git a/src/cmd/compile/internal/ssa/gen/PPC64Ops.go b/src/cmd/compile/internal/ssa/gen/PPC64Ops.go
index ef0db69fb7..d6638b1ec7 100644
--- a/src/cmd/compile/internal/ssa/gen/PPC64Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/PPC64Ops.go
@@ -241,24 +241,27 @@ func init() {
{name: "MFVSRD", argLength: 1, reg: fpgp, asm: "MFVSRD", typ: "Int64"}, // move 64 bits of F register into G register
{name: "MTVSRD", argLength: 1, reg: gpfp, asm: "MTVSRD", typ: "Float64"}, // move 64 bits of G register into F register
- {name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true}, // arg0&arg1
- {name: "ANDN", argLength: 2, reg: gp21, asm: "ANDN"}, // arg0&^arg1
- {name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true}, // arg0|arg1
- {name: "ORN", argLength: 2, reg: gp21, asm: "ORN"}, // arg0|^arg1
- {name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true}, // ^(arg0|arg1)
- {name: "XOR", argLength: 2, reg: gp21, asm: "XOR", typ: "Int64", commutative: true}, // arg0^arg1
- {name: "EQV", argLength: 2, reg: gp21, asm: "EQV", typ: "Int64", commutative: true}, // arg0^^arg1
- {name: "NEG", argLength: 1, reg: gp11, asm: "NEG"}, // -arg0 (integer)
- {name: "FNEG", argLength: 1, reg: fp11, asm: "FNEG"}, // -arg0 (floating point)
- {name: "FSQRT", argLength: 1, reg: fp11, asm: "FSQRT"}, // sqrt(arg0) (floating point)
- {name: "FSQRTS", argLength: 1, reg: fp11, asm: "FSQRTS"}, // sqrt(arg0) (floating point, single precision)
- {name: "FFLOOR", argLength: 1, reg: fp11, asm: "FRIM"}, // floor(arg0), float64
- {name: "FCEIL", argLength: 1, reg: fp11, asm: "FRIP"}, // ceil(arg0), float64
- {name: "FTRUNC", argLength: 1, reg: fp11, asm: "FRIZ"}, // trunc(arg0), float64
- {name: "FROUND", argLength: 1, reg: fp11, asm: "FRIN"}, // round(arg0), float64
- {name: "FABS", argLength: 1, reg: fp11, asm: "FABS"}, // abs(arg0), float64
- {name: "FNABS", argLength: 1, reg: fp11, asm: "FNABS"}, // -abs(arg0), float64
- {name: "FCPSGN", argLength: 2, reg: fp21, asm: "FCPSGN"}, // copysign arg0 -> arg1, float64
+ {name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true}, // arg0&arg1
+ {name: "ANDN", argLength: 2, reg: gp21, asm: "ANDN"}, // arg0&^arg1
+ {name: "ANDCC", argLength: 2, reg: gp21, asm: "ANDCC", commutative: true, typ: "Flags"}, // arg0&arg1 sets CC
+ {name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true}, // arg0|arg1
+ {name: "ORN", argLength: 2, reg: gp21, asm: "ORN"}, // arg0|^arg1
+ {name: "ORCC", argLength: 2, reg: gp21, asm: "ORCC", commutative: true, typ: "Flags"}, // arg0|arg1 sets CC
+ {name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true}, // ^(arg0|arg1)
+ {name: "XOR", argLength: 2, reg: gp21, asm: "XOR", typ: "Int64", commutative: true}, // arg0^arg1
+ {name: "XORCC", argLength: 2, reg: gp21, asm: "XORCC", commutative: true, typ: "Flags"}, // arg0^arg1 sets CC
+ {name: "EQV", argLength: 2, reg: gp21, asm: "EQV", typ: "Int64", commutative: true}, // arg0^^arg1
+ {name: "NEG", argLength: 1, reg: gp11, asm: "NEG"}, // -arg0 (integer)
+ {name: "FNEG", argLength: 1, reg: fp11, asm: "FNEG"}, // -arg0 (floating point)
+ {name: "FSQRT", argLength: 1, reg: fp11, asm: "FSQRT"}, // sqrt(arg0) (floating point)
+ {name: "FSQRTS", argLength: 1, reg: fp11, asm: "FSQRTS"}, // sqrt(arg0) (floating point, single precision)
+ {name: "FFLOOR", argLength: 1, reg: fp11, asm: "FRIM"}, // floor(arg0), float64
+ {name: "FCEIL", argLength: 1, reg: fp11, asm: "FRIP"}, // ceil(arg0), float64
+ {name: "FTRUNC", argLength: 1, reg: fp11, asm: "FRIZ"}, // trunc(arg0), float64
+ {name: "FROUND", argLength: 1, reg: fp11, asm: "FRIN"}, // round(arg0), float64
+ {name: "FABS", argLength: 1, reg: fp11, asm: "FABS"}, // abs(arg0), float64
+ {name: "FNABS", argLength: 1, reg: fp11, asm: "FNABS"}, // -abs(arg0), float64
+ {name: "FCPSGN", argLength: 2, reg: fp21, asm: "FCPSGN"}, // copysign arg0 -> arg1, float64
{name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int64"}, // arg0|aux
{name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64"}, // arg0^aux
diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules
index 14a67846dc..5a1bee0fa2 100644
--- a/src/cmd/compile/internal/ssa/gen/generic.rules
+++ b/src/cmd/compile/internal/ssa/gen/generic.rules
@@ -1804,11 +1804,25 @@
// Later passes (deadstore, elim unread auto) will remove the A -> B move, if possible.
// This happens most commonly when B is an autotmp inserted earlier
// during compilation to ensure correctness.
-(Move {t1} [s1] dst tmp1 midmem:(Move {t2} [s2] tmp2 src _))
- && s1 == s2
+// Take care that overlapping moves are preserved.
+// Restrict this optimization to the stack, to avoid duplicating loads from the heap;
+// see CL 145208 for discussion.
+(Move {t1} [s] dst tmp1 midmem:(Move {t2} [s] tmp2 src _))
&& t1.(*types.Type).Compare(t2.(*types.Type)) == types.CMPeq
&& isSamePtr(tmp1, tmp2)
- -> (Move {t1} [s1] dst src midmem)
+ && isStackPtr(src)
+ && disjoint(src, s, tmp2, s)
+ && (disjoint(src, s, dst, s) || isInlinableMemmove(dst, src, s, config))
+ -> (Move {t1} [s] dst src midmem)
+
+// Same, but for large types that require VarDefs.
+(Move {t1} [s] dst tmp1 midmem:(VarDef (Move {t2} [s] tmp2 src _)))
+ && t1.(*types.Type).Compare(t2.(*types.Type)) == types.CMPeq
+ && isSamePtr(tmp1, tmp2)
+ && isStackPtr(src)
+ && disjoint(src, s, tmp2, s)
+ && (disjoint(src, s, dst, s) || isInlinableMemmove(dst, src, s, config))
+ -> (Move {t1} [s] dst src midmem)
// Elide self-moves. This only happens rarely (e.g test/fixedbugs/bug277.go).
// However, this rule is needed to prevent the previous rule from looping forever in such cases.
diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go
index 522ccbf893..ba8d93cf2c 100644
--- a/src/cmd/compile/internal/ssa/gen/genericOps.go
+++ b/src/cmd/compile/internal/ssa/gen/genericOps.go
@@ -529,7 +529,7 @@ var genericOps = []opData{
{name: "AtomicAdd64", argLength: 3, typ: "(UInt64,Mem)", hasSideEffects: true}, // Do *arg0 += arg1. arg2=memory. Returns sum and new memory.
{name: "AtomicCompareAndSwap32", argLength: 4, typ: "(Bool,Mem)", hasSideEffects: true}, // if *arg0==arg1, then set *arg0=arg2. Returns true if store happens and new memory.
{name: "AtomicCompareAndSwap64", argLength: 4, typ: "(Bool,Mem)", hasSideEffects: true}, // if *arg0==arg1, then set *arg0=arg2. Returns true if store happens and new memory.
- {name: "AtomicCompareAndSwapRel32", argLength: 4, typ: "(Bool,Mem)", hasSideEffects: true}, // if *arg0==arg1, then set *arg0=arg2. Lock release, returns true if store happens and new memory.
+ {name: "AtomicCompareAndSwapRel32", argLength: 4, typ: "(Bool,Mem)", hasSideEffects: true}, // if *arg0==arg1, then set *arg0=arg2. Lock release, reports whether store happens and new memory.
{name: "AtomicAnd8", argLength: 3, typ: "Mem", hasSideEffects: true}, // *arg0 &= arg1. arg2=memory. Returns memory.
{name: "AtomicOr8", argLength: 3, typ: "Mem", hasSideEffects: true}, // *arg0 |= arg1. arg2=memory. Returns memory.
diff --git a/src/cmd/compile/internal/ssa/gen/rulegen.go b/src/cmd/compile/internal/ssa/gen/rulegen.go
index faaad974c4..34517b4cb9 100644
--- a/src/cmd/compile/internal/ssa/gen/rulegen.go
+++ b/src/cmd/compile/internal/ssa/gen/rulegen.go
@@ -6,7 +6,7 @@
// This program generates Go code that applies rewrite rules to a Value.
// The generated code implements a function of type func (v *Value) bool
-// which returns true iff if did something.
+// which reports whether if did something.
// Ideas stolen from Swift: http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-2000-2.html
package main
@@ -386,7 +386,7 @@ func genRules(arch arch) {
}
}
-// genMatch returns true if the match can fail.
+// genMatch reports whether the match can fail.
func genMatch(w io.Writer, arch arch, match string, loc string) bool {
return genMatch0(w, arch, match, "v", map[string]struct{}{}, true, loc)
}
@@ -623,7 +623,7 @@ outer:
return r
}
-// isBlock returns true if this op is a block opcode.
+// isBlock reports whether this op is a block opcode.
func isBlock(name string, arch arch) bool {
for _, b := range genericBlocks {
if b.name == name {
@@ -768,7 +768,7 @@ func typeName(typ string) string {
}
}
-// unbalanced returns true if there aren't the same number of ( and ) in the string.
+// unbalanced reports whether there aren't the same number of ( and ) in the string.
func unbalanced(s string) bool {
var left, right int
for _, c := range s {
diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go
index 03837b5f63..f6568be660 100644
--- a/src/cmd/compile/internal/ssa/opGen.go
+++ b/src/cmd/compile/internal/ssa/opGen.go
@@ -1663,10 +1663,13 @@ const (
OpPPC64MTVSRD
OpPPC64AND
OpPPC64ANDN
+ OpPPC64ANDCC
OpPPC64OR
OpPPC64ORN
+ OpPPC64ORCC
OpPPC64NOR
OpPPC64XOR
+ OpPPC64XORCC
OpPPC64EQV
OpPPC64NEG
OpPPC64FNEG
@@ -22202,6 +22205,21 @@ var opcodeTable = [...]opInfo{
},
},
},
+ {
+ name: "ANDCC",
+ argLen: 2,
+ commutative: true,
+ asm: ppc64.AANDCC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+ {1, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+ },
+ outputs: []outputInfo{
+ {0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+ },
+ },
+ },
{
name: "OR",
argLen: 2,
@@ -22231,6 +22249,21 @@ var opcodeTable = [...]opInfo{
},
},
},
+ {
+ name: "ORCC",
+ argLen: 2,
+ commutative: true,
+ asm: ppc64.AORCC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+ {1, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+ },
+ outputs: []outputInfo{
+ {0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+ },
+ },
+ },
{
name: "NOR",
argLen: 2,
@@ -22261,6 +22294,21 @@ var opcodeTable = [...]opInfo{
},
},
},
+ {
+ name: "XORCC",
+ argLen: 2,
+ commutative: true,
+ asm: ppc64.AXORCC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+ {1, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+ },
+ outputs: []outputInfo{
+ {0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+ },
+ },
+ },
{
name: "EQV",
argLen: 2,
diff --git a/src/cmd/compile/internal/ssa/poset.go b/src/cmd/compile/internal/ssa/poset.go
index 0e0e2789b1..4ebfb89e52 100644
--- a/src/cmd/compile/internal/ssa/poset.go
+++ b/src/cmd/compile/internal/ssa/poset.go
@@ -781,7 +781,7 @@ func (po *poset) DotDump(fn string, title string) error {
return nil
}
-// Ordered returns true if n1 [o2] p2) d1 (Store {t3} (OffPtr [o3] p3) d2 (Store {t4} (OffPtr [o4] p4) d3 (Store {t5} (OffPtr [o5] p5) d4 (Zero {t6} [n] p6 _)))))))
// cond: isSamePtr(p1, p2) && isSamePtr(p2, p3) && isSamePtr(p3, p4) && isSamePtr(p4, p5) && isSamePtr(p5, p6) && alignof(t2) <= alignof(t1) && alignof(t3) <= alignof(t1) && alignof(t4) <= alignof(t1) && alignof(t5) <= alignof(t1) && alignof(t6) <= alignof(t1) && registerizable(b, t2) && registerizable(b, t3) && registerizable(b, t4) && registerizable(b, t5) && n >= o2 + sizeof(t2) && n >= o3 + sizeof(t3) && n >= o4 + sizeof(t4) && n >= o5 + sizeof(t5)
// result: (Store {t2} (OffPtr [o2] dst) d1 (Store {t3} (OffPtr [o3] dst) d2 (Store {t4} (OffPtr [o4] dst) d3 (Store {t5} (OffPtr [o5] dst) d4 (Zero {t1} [n] dst mem)))))
@@ -17355,11 +17357,11 @@ func rewriteValuegeneric_OpMove_20(v *Value) bool {
v.AddArg(v1)
return true
}
- // match: (Move {t1} [s1] dst tmp1 midmem:(Move {t2} [s2] tmp2 src _))
- // cond: s1 == s2 && t1.(*types.Type).Compare(t2.(*types.Type)) == types.CMPeq && isSamePtr(tmp1, tmp2)
- // result: (Move {t1} [s1] dst src midmem)
+ // match: (Move {t1} [s] dst tmp1 midmem:(Move {t2} [s] tmp2 src _))
+ // cond: t1.(*types.Type).Compare(t2.(*types.Type)) == types.CMPeq && isSamePtr(tmp1, tmp2) && isStackPtr(src) && disjoint(src, s, tmp2, s) && (disjoint(src, s, dst, s) || isInlinableMemmove(dst, src, s, config))
+ // result: (Move {t1} [s] dst src midmem)
for {
- s1 := v.AuxInt
+ s := v.AuxInt
t1 := v.Aux
_ = v.Args[2]
dst := v.Args[0]
@@ -17368,16 +17370,53 @@ func rewriteValuegeneric_OpMove_20(v *Value) bool {
if midmem.Op != OpMove {
break
}
- s2 := midmem.AuxInt
+ if midmem.AuxInt != s {
+ break
+ }
t2 := midmem.Aux
_ = midmem.Args[2]
tmp2 := midmem.Args[0]
src := midmem.Args[1]
- if !(s1 == s2 && t1.(*types.Type).Compare(t2.(*types.Type)) == types.CMPeq && isSamePtr(tmp1, tmp2)) {
+ if !(t1.(*types.Type).Compare(t2.(*types.Type)) == types.CMPeq && isSamePtr(tmp1, tmp2) && isStackPtr(src) && disjoint(src, s, tmp2, s) && (disjoint(src, s, dst, s) || isInlinableMemmove(dst, src, s, config))) {
break
}
v.reset(OpMove)
- v.AuxInt = s1
+ v.AuxInt = s
+ v.Aux = t1
+ v.AddArg(dst)
+ v.AddArg(src)
+ v.AddArg(midmem)
+ return true
+ }
+ // match: (Move {t1} [s] dst tmp1 midmem:(VarDef (Move {t2} [s] tmp2 src _)))
+ // cond: t1.(*types.Type).Compare(t2.(*types.Type)) == types.CMPeq && isSamePtr(tmp1, tmp2) && isStackPtr(src) && disjoint(src, s, tmp2, s) && (disjoint(src, s, dst, s) || isInlinableMemmove(dst, src, s, config))
+ // result: (Move {t1} [s] dst src midmem)
+ for {
+ s := v.AuxInt
+ t1 := v.Aux
+ _ = v.Args[2]
+ dst := v.Args[0]
+ tmp1 := v.Args[1]
+ midmem := v.Args[2]
+ if midmem.Op != OpVarDef {
+ break
+ }
+ midmem_0 := midmem.Args[0]
+ if midmem_0.Op != OpMove {
+ break
+ }
+ if midmem_0.AuxInt != s {
+ break
+ }
+ t2 := midmem_0.Aux
+ _ = midmem_0.Args[2]
+ tmp2 := midmem_0.Args[0]
+ src := midmem_0.Args[1]
+ if !(t1.(*types.Type).Compare(t2.(*types.Type)) == types.CMPeq && isSamePtr(tmp1, tmp2) && isStackPtr(src) && disjoint(src, s, tmp2, s) && (disjoint(src, s, dst, s) || isInlinableMemmove(dst, src, s, config))) {
+ break
+ }
+ v.reset(OpMove)
+ v.AuxInt = s
v.Aux = t1
v.AddArg(dst)
v.AddArg(src)
diff --git a/src/cmd/compile/internal/ssa/testdata/hist.dlv-opt.nexts b/src/cmd/compile/internal/ssa/testdata/hist.dlv-opt.nexts
index 7eb1d3a35b..89d0b1b637 100644
--- a/src/cmd/compile/internal/ssa/testdata/hist.dlv-opt.nexts
+++ b/src/cmd/compile/internal/ssa/testdata/hist.dlv-opt.nexts
@@ -58,11 +58,13 @@
87: if a == 0 { //gdb-opt=(a,n,t)
86: for i, a := range hist {
87: if a == 0 { //gdb-opt=(a,n,t)
+92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
91: n += a
90: t += i * a
92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
86: for i, a := range hist {
87: if a == 0 { //gdb-opt=(a,n,t)
+92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
91: n += a
90: t += i * a
92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
@@ -70,11 +72,13 @@
87: if a == 0 { //gdb-opt=(a,n,t)
86: for i, a := range hist {
87: if a == 0 { //gdb-opt=(a,n,t)
+92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
91: n += a
90: t += i * a
92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
86: for i, a := range hist {
87: if a == 0 { //gdb-opt=(a,n,t)
+92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
91: n += a
90: t += i * a
92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
diff --git a/src/cmd/compile/internal/ssa/testdata/hist.gdb-opt.nexts b/src/cmd/compile/internal/ssa/testdata/hist.gdb-opt.nexts
index 8664ea77c4..b2f3216707 100644
--- a/src/cmd/compile/internal/ssa/testdata/hist.gdb-opt.nexts
+++ b/src/cmd/compile/internal/ssa/testdata/hist.gdb-opt.nexts
@@ -123,6 +123,7 @@ t = 0
92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
91: n += a
90: t += i * a
+92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
86: for i, a := range hist {
87: if a == 0 { //gdb-opt=(a,n,t)
a = 3
@@ -131,6 +132,7 @@ t = 3
92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
91: n += a
90: t += i * a
+92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
86: for i, a := range hist {
87: if a == 0 { //gdb-opt=(a,n,t)
a = 0
@@ -144,6 +146,7 @@ t = 9
92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
91: n += a
90: t += i * a
+92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
86: for i, a := range hist {
87: if a == 0 { //gdb-opt=(a,n,t)
a = 1
@@ -152,6 +155,7 @@ t = 17
92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
91: n += a
90: t += i * a
+92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
86: for i, a := range hist {
87: if a == 0 { //gdb-opt=(a,n,t)
a = 0
diff --git a/src/cmd/compile/internal/ssa/trim.go b/src/cmd/compile/internal/ssa/trim.go
index d97c6baaa1..1293548aad 100644
--- a/src/cmd/compile/internal/ssa/trim.go
+++ b/src/cmd/compile/internal/ssa/trim.go
@@ -94,7 +94,7 @@ func trim(f *Func) {
}
}
-// emptyBlock returns true if the block does not contain actual
+// emptyBlock reports whether the block does not contain actual
// instructions
func emptyBlock(b *Block) bool {
for _, v := range b.Values {
@@ -105,7 +105,7 @@ func emptyBlock(b *Block) bool {
return true
}
-// trimmableBlock returns true if the block can be trimmed from the CFG,
+// trimmableBlock reports whether the block can be trimmed from the CFG,
// subject to the following criteria:
// - it should not be the first block
// - it should be BlockPlain
diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go
index 39f4d2aa7b..45355e5798 100644
--- a/src/cmd/compile/internal/types/type.go
+++ b/src/cmd/compile/internal/types/type.go
@@ -149,8 +149,11 @@ type Type struct {
Nod *Node // canonical OTYPE node
Orig *Type // original type (type literal or predefined type)
- SliceOf *Type
- PtrBase *Type
+ // Cache of composite types, with this type being the element type.
+ Cache struct {
+ ptr *Type // *T, or nil
+ slice *Type // []T, or nil
+ }
Sym *Sym // symbol containing name, for named types
Vargen int32 // unique name for OTYPE/ONAME
@@ -488,7 +491,7 @@ func NewArray(elem *Type, bound int64) *Type {
// NewSlice returns the slice Type with element type elem.
func NewSlice(elem *Type) *Type {
- if t := elem.SliceOf; t != nil {
+ if t := elem.Cache.slice; t != nil {
if t.Elem() != elem {
Fatalf("elem mismatch")
}
@@ -497,7 +500,7 @@ func NewSlice(elem *Type) *Type {
t := New(TSLICE)
t.Extra = Slice{Elem: elem}
- elem.SliceOf = t
+ elem.Cache.slice = t
return t
}
@@ -551,7 +554,7 @@ func NewPtr(elem *Type) *Type {
Fatalf("NewPtr: pointer to elem Type is nil")
}
- if t := elem.PtrBase; t != nil {
+ if t := elem.Cache.ptr; t != nil {
if t.Elem() != elem {
Fatalf("NewPtr: elem mismatch")
}
@@ -563,7 +566,7 @@ func NewPtr(elem *Type) *Type {
t.Width = int64(Widthptr)
t.Align = uint8(Widthptr)
if NewPtrCacheEnabled {
- elem.PtrBase = t
+ elem.Cache.ptr = t
}
return t
}
@@ -662,23 +665,18 @@ func SubstAny(t *Type, types *[]*Type) *Type {
}
case TSTRUCT:
+ // Make a copy of all fields, including ones whose type does not change.
+ // This prevents aliasing across functions, which can lead to later
+ // fields getting their Offset incorrectly overwritten.
fields := t.FieldSlice()
- var nfs []*Field
+ nfs := make([]*Field, len(fields))
for i, f := range fields {
nft := SubstAny(f.Type, types)
- if nft == f.Type {
- continue
- }
- if nfs == nil {
- nfs = append([]*Field(nil), fields...)
- }
nfs[i] = f.Copy()
nfs[i].Type = nft
}
- if nfs != nil {
- t = t.copy()
- t.SetFields(nfs)
- }
+ t = t.copy()
+ t.SetFields(nfs)
}
return t
@@ -1258,6 +1256,11 @@ func (t *Type) IsPtr() bool {
return t.Etype == TPTR
}
+// IsPtrElem reports whether t is the element of a pointer (to t).
+func (t *Type) IsPtrElem() bool {
+ return t.Cache.ptr != nil
+}
+
// IsUnsafePtr reports whether t is an unsafe pointer.
func (t *Type) IsUnsafePtr() bool {
return t.Etype == TUNSAFEPTR
diff --git a/src/cmd/fix/fix.go b/src/cmd/fix/fix.go
index 03c828a581..2c64e9b414 100644
--- a/src/cmd/fix/fix.go
+++ b/src/cmd/fix/fix.go
@@ -478,7 +478,7 @@ func newPkgDot(pos token.Pos, pkg, name string) ast.Expr {
}
// renameTop renames all references to the top-level name old.
-// It returns true if it makes any changes.
+// It reports whether it makes any changes.
func renameTop(f *ast.File, old, new string) bool {
var fixed bool
diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go
index b0c10c8531..f8c4d2ffa9 100644
--- a/src/cmd/go/alldocs.go
+++ b/src/cmd/go/alldocs.go
@@ -972,6 +972,8 @@
// and -dropreplace editing flags may be repeated, and the changes
// are applied in the order given.
//
+// The -go=version flag sets the expected Go language version.
+//
// The -print flag prints the final go.mod in its text format instead of
// writing it back to go.mod.
//
@@ -984,7 +986,8 @@
// }
//
// type GoMod struct {
-// Module Module
+// Module Module
+// Go string
// Require []Require
// Exclude []Module
// Replace []Replace
@@ -1604,17 +1607,20 @@
// verb followed by arguments. For example:
//
// module my/thing
+// go 1.12
// require other/thing v1.0.2
-// require new/thing v2.3.4
+// require new/thing/v2 v2.3.4
// exclude old/thing v1.2.3
// replace bad/thing v1.4.5 => good/thing v1.4.5
//
-// The verbs are module, to define the module path; require, to require
-// a particular module at a given version or later; exclude, to exclude
-// a particular module version from use; and replace, to replace a module
-// version with a different module version. Exclude and replace apply only
-// in the main module's go.mod and are ignored in dependencies.
-// See https://research.swtch.com/vgo-mvs for details.
+// The verbs are
+// module, to define the module path;
+// go, to set the expected language version;
+// require, to require a particular module at a given version or later;
+// exclude, to exclude a particular module version from use; and
+// replace, to replace a module version with a different module version.
+// Exclude and replace apply only in the main module's go.mod and are ignored
+// in dependencies. See https://research.swtch.com/vgo-mvs for details.
//
// The leading verb can be factored out of adjacent lines to create a block,
// like in Go imports:
diff --git a/src/cmd/go/internal/cache/hash.go b/src/cmd/go/internal/cache/hash.go
index 0e45e7db54..e4bb2a34bb 100644
--- a/src/cmd/go/internal/cache/hash.go
+++ b/src/cmd/go/internal/cache/hash.go
@@ -123,7 +123,7 @@ var hashFileCache struct {
m map[string][HashSize]byte
}
-// HashFile returns the hash of the named file.
+// FileHash returns the hash of the named file.
// It caches repeated lookups for a given file,
// and the cache entry for a file can be initialized
// using SetFileHash.
diff --git a/src/cmd/go/internal/cmdflag/flag.go b/src/cmd/go/internal/cmdflag/flag.go
index b2a67e6f74..7f2c53def8 100644
--- a/src/cmd/go/internal/cmdflag/flag.go
+++ b/src/cmd/go/internal/cmdflag/flag.go
@@ -79,15 +79,15 @@ func AddKnownFlags(cmd string, defns []*Defn) {
// Parse sees if argument i is present in the definitions and if so,
// returns its definition, value, and whether it consumed an extra word.
-// If the flag begins (cmd+".") it is ignored for the purpose of this function.
-func Parse(cmd string, defns []*Defn, args []string, i int) (f *Defn, value string, extra bool) {
+// If the flag begins (cmd.Name()+".") it is ignored for the purpose of this function.
+func Parse(cmd string, usage func(), defns []*Defn, args []string, i int) (f *Defn, value string, extra bool) {
arg := args[i]
if strings.HasPrefix(arg, "--") { // reduce two minuses to one
arg = arg[1:]
}
switch arg {
case "-?", "-h", "-help":
- base.Usage()
+ usage()
}
if arg == "" || arg[0] != '-' {
return
diff --git a/src/cmd/go/internal/modcmd/edit.go b/src/cmd/go/internal/modcmd/edit.go
index 5fea3e48e0..c589c6d4ed 100644
--- a/src/cmd/go/internal/modcmd/edit.go
+++ b/src/cmd/go/internal/modcmd/edit.go
@@ -62,6 +62,8 @@ The -require, -droprequire, -exclude, -dropexclude, -replace,
and -dropreplace editing flags may be repeated, and the changes
are applied in the order given.
+The -go=version flag sets the expected Go language version.
+
The -print flag prints the final go.mod in its text format instead of
writing it back to go.mod.
@@ -74,7 +76,8 @@ writing it back to go.mod. The JSON output corresponds to these Go types:
}
type GoMod struct {
- Module Module
+ Module Module
+ Go string
Require []Require
Exclude []Module
Replace []Replace
@@ -102,8 +105,8 @@ by invoking 'go mod edit' with -require, -exclude, and so on.
}
var (
- editFmt = cmdEdit.Flag.Bool("fmt", false, "")
- // editGo = cmdEdit.Flag.String("go", "", "")
+ editFmt = cmdEdit.Flag.Bool("fmt", false, "")
+ editGo = cmdEdit.Flag.String("go", "", "")
editJSON = cmdEdit.Flag.Bool("json", false, "")
editPrint = cmdEdit.Flag.Bool("print", false, "")
editModule = cmdEdit.Flag.String("module", "", "")
@@ -131,6 +134,7 @@ func init() {
func runEdit(cmd *base.Command, args []string) {
anyFlags :=
*editModule != "" ||
+ *editGo != "" ||
*editJSON ||
*editPrint ||
*editFmt ||
@@ -161,7 +165,11 @@ func runEdit(cmd *base.Command, args []string) {
}
}
- // TODO(rsc): Implement -go= once we start advertising it.
+ if *editGo != "" {
+ if !modfile.GoVersionRE.MatchString(*editGo) {
+ base.Fatalf(`go mod: invalid -go option; expecting something like "-go 1.12"`)
+ }
+ }
data, err := ioutil.ReadFile(gomod)
if err != nil {
@@ -177,6 +185,12 @@ func runEdit(cmd *base.Command, args []string) {
modFile.AddModuleStmt(modload.CmdModModule)
}
+ if *editGo != "" {
+ if err := modFile.AddGoStmt(*editGo); err != nil {
+ base.Fatalf("go: internal error: %v", err)
+ }
+ }
+
if len(edits) > 0 {
for _, edit := range edits {
edit(modFile)
@@ -344,6 +358,7 @@ func flagDropReplace(arg string) {
// fileJSON is the -json output data structure.
type fileJSON struct {
Module module.Version
+ Go string `json:",omitempty"`
Require []requireJSON
Exclude []module.Version
Replace []replaceJSON
@@ -364,6 +379,9 @@ type replaceJSON struct {
func editPrintJSON(modFile *modfile.File) {
var f fileJSON
f.Module = modFile.Module.Mod
+ if modFile.Go != nil {
+ f.Go = modFile.Go.Version
+ }
for _, r := range modFile.Require {
f.Require = append(f.Require, requireJSON{Path: r.Mod.Path, Version: r.Mod.Version, Indirect: r.Indirect})
}
diff --git a/src/cmd/go/internal/modfile/rule.go b/src/cmd/go/internal/modfile/rule.go
index e11f0a6e31..7f9a18c6c2 100644
--- a/src/cmd/go/internal/modfile/rule.go
+++ b/src/cmd/go/internal/modfile/rule.go
@@ -154,7 +154,7 @@ func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (*File
return f, nil
}
-var goVersionRE = regexp.MustCompile(`([1-9][0-9]*)\.(0|[1-9][0-9]*)`)
+var GoVersionRE = regexp.MustCompile(`([1-9][0-9]*)\.(0|[1-9][0-9]*)`)
func (f *File) add(errs *bytes.Buffer, line *Line, verb string, args []string, fix VersionFixer, strict bool) {
// If strict is false, this module is a dependency.
@@ -181,7 +181,7 @@ func (f *File) add(errs *bytes.Buffer, line *Line, verb string, args []string, f
fmt.Fprintf(errs, "%s:%d: repeated go statement\n", f.Syntax.Name, line.Start.Line)
return
}
- if len(args) != 1 || !goVersionRE.MatchString(args[0]) {
+ if len(args) != 1 || !GoVersionRE.MatchString(args[0]) {
fmt.Fprintf(errs, "%s:%d: usage: go 1.23\n", f.Syntax.Name, line.Start.Line)
return
}
@@ -477,6 +477,22 @@ func (f *File) Cleanup() {
f.Syntax.Cleanup()
}
+func (f *File) AddGoStmt(version string) error {
+ if !GoVersionRE.MatchString(version) {
+ return fmt.Errorf("invalid language version string %q", version)
+ }
+ if f.Go == nil {
+ f.Go = &Go{
+ Version: version,
+ Syntax: f.Syntax.addLine(nil, "go", version),
+ }
+ } else {
+ f.Go.Version = version
+ f.Syntax.updateLine(f.Go.Syntax, "go", version)
+ }
+ return nil
+}
+
func (f *File) AddRequire(path, vers string) error {
need := true
for _, r := range f.Require {
diff --git a/src/cmd/go/internal/modload/help.go b/src/cmd/go/internal/modload/help.go
index f2f3419724..d9c8ae40d8 100644
--- a/src/cmd/go/internal/modload/help.go
+++ b/src/cmd/go/internal/modload/help.go
@@ -393,17 +393,20 @@ no /* */ comments. Each line holds a single directive, made up of a
verb followed by arguments. For example:
module my/thing
+ go 1.12
require other/thing v1.0.2
- require new/thing v2.3.4
+ require new/thing/v2 v2.3.4
exclude old/thing v1.2.3
replace bad/thing v1.4.5 => good/thing v1.4.5
-The verbs are module, to define the module path; require, to require
-a particular module at a given version or later; exclude, to exclude
-a particular module version from use; and replace, to replace a module
-version with a different module version. Exclude and replace apply only
-in the main module's go.mod and are ignored in dependencies.
-See https://research.swtch.com/vgo-mvs for details.
+The verbs are
+ module, to define the module path;
+ go, to set the expected language version;
+ require, to require a particular module at a given version or later;
+ exclude, to exclude a particular module version from use; and
+ replace, to replace a module version with a different module version.
+Exclude and replace apply only in the main module's go.mod and are ignored
+in dependencies. See https://research.swtch.com/vgo-mvs for details.
The leading verb can be factored out of adjacent lines to create a block,
like in Go imports:
diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go
index 2bab3eede1..da778b4fad 100644
--- a/src/cmd/go/internal/modload/init.go
+++ b/src/cmd/go/internal/modload/init.go
@@ -19,6 +19,7 @@ import (
"cmd/go/internal/search"
"encoding/json"
"fmt"
+ "go/build"
"io/ioutil"
"os"
"path"
@@ -335,6 +336,8 @@ func legacyModInit() {
modFile.AddModuleStmt(path)
}
+ addGoStmt()
+
for _, name := range altConfigs {
cfg := filepath.Join(ModRoot, name)
data, err := ioutil.ReadFile(cfg)
@@ -357,6 +360,25 @@ func legacyModInit() {
}
}
+// InitGoStmt adds a go statement, unless there already is one.
+func InitGoStmt() {
+ if modFile.Go == nil {
+ addGoStmt()
+ }
+}
+
+// addGoStmt adds a go statement referring to the current version.
+func addGoStmt() {
+ tags := build.Default.ReleaseTags
+ version := tags[len(tags)-1]
+ if !strings.HasPrefix(version, "go") || !modfile.GoVersionRE.MatchString(version[2:]) {
+ base.Fatalf("go: unrecognized default version %q", version)
+ }
+ if err := modFile.AddGoStmt(version[2:]); err != nil {
+ base.Fatalf("go: internal error: %v", err)
+ }
+}
+
var altConfigs = []string{
"Gopkg.lock",
diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go
index 750b515e41..b38eb4c41d 100644
--- a/src/cmd/go/internal/test/test.go
+++ b/src/cmd/go/internal/test/test.go
@@ -124,16 +124,6 @@ A cached test result is treated as executing in no time at all,
so a successful package test result will be cached and reused
regardless of -timeout setting.
-` + strings.TrimSpace(testFlag1) + ` See 'go help testflag' for details.
-
-For more about build flags, see 'go help build'.
-For more about specifying packages, see 'go help packages'.
-
-See also: go build, go vet.
-`,
-}
-
-const testFlag1 = `
In addition to the build flags, the flags handled by 'go test' itself are:
-args
@@ -164,15 +154,13 @@ In addition to the build flags, the flags handled by 'go test' itself are:
The test still runs (unless -c or -i is specified).
The test binary also accepts flags that control execution of the test; these
-flags are also accessible by 'go test'.
-`
+flags are also accessible by 'go test'. See 'go help testflag' for details.
-// Usage prints the usage message for 'go test -h' and exits.
-func Usage() {
- os.Stderr.WriteString("usage: " + testUsage + "\n\n" +
- strings.TrimSpace(testFlag1) + "\n\n\t" +
- strings.TrimSpace(testFlag2) + "\n")
- os.Exit(2)
+For more about build flags, see 'go help build'.
+For more about specifying packages, see 'go help packages'.
+
+See also: go build, go vet.
+`,
}
var HelpTestflag = &base.Command{
@@ -190,11 +178,6 @@ options of pprof control how the information is presented.
The following flags are recognized by the 'go test' command and
control the execution of any test:
- ` + strings.TrimSpace(testFlag2) + `
-`,
-}
-
-const testFlag2 = `
-bench regexp
Run only those benchmarks matching a regular expression.
By default, no benchmarks are run.
@@ -414,7 +397,8 @@ In the first example, the -x and the second -v are passed through to the
test binary unchanged and with no effect on the go command itself.
In the second example, the argument math is passed through to the test
binary, instead of being interpreted as the package list.
-`
+`,
+}
var HelpTestfunc = &base.Command{
UsageLine: "testfunc",
@@ -532,7 +516,7 @@ var testVetFlags = []string{
func runTest(cmd *base.Command, args []string) {
modload.LoadTests = true
- pkgArgs, testArgs = testFlags(args)
+ pkgArgs, testArgs = testFlags(cmd.Usage, args)
work.FindExecCmd() // initialize cached result
diff --git a/src/cmd/go/internal/test/testflag.go b/src/cmd/go/internal/test/testflag.go
index 73f8c69d9e..ebcf49a4e9 100644
--- a/src/cmd/go/internal/test/testflag.go
+++ b/src/cmd/go/internal/test/testflag.go
@@ -87,7 +87,7 @@ func init() {
// to allow both
// go test fmt -custom-flag-for-fmt-test
// go test -x math
-func testFlags(args []string) (packageNames, passToTest []string) {
+func testFlags(usage func(), args []string) (packageNames, passToTest []string) {
args = str.StringList(cmdflag.FindGOFLAGS(testFlagDefn), args)
inPkg := false
var explicitArgs []string
@@ -108,7 +108,7 @@ func testFlags(args []string) (packageNames, passToTest []string) {
inPkg = false
}
- f, value, extraWord := cmdflag.Parse(cmd, testFlagDefn, args, i)
+ f, value, extraWord := cmdflag.Parse(cmd, usage, testFlagDefn, args, i)
if f == nil {
// This is a flag we do not know; we must assume
// that any args we see after this might be flag
diff --git a/src/cmd/go/internal/vet/vet.go b/src/cmd/go/internal/vet/vet.go
index b64bf3f8e8..616f774bf6 100644
--- a/src/cmd/go/internal/vet/vet.go
+++ b/src/cmd/go/internal/vet/vet.go
@@ -38,7 +38,7 @@ See also: go fmt, go fix.
func runVet(cmd *base.Command, args []string) {
modload.LoadTests = true
- vetFlags, pkgArgs := vetFlags(args)
+ vetFlags, pkgArgs := vetFlags(cmd.Usage, args)
work.BuildInit()
work.VetFlags = vetFlags
diff --git a/src/cmd/go/internal/vet/vetflag.go b/src/cmd/go/internal/vet/vetflag.go
index cfa4352cb9..9b5184a4d4 100644
--- a/src/cmd/go/internal/vet/vetflag.go
+++ b/src/cmd/go/internal/vet/vetflag.go
@@ -23,24 +23,43 @@ import (
// go vet flag processing
//
-// We query the flags of the tool specified by GOVETTOOL (default:
-// cmd/vet) and accept any of those flags plus any flag valid for 'go
-// build'. The tool must support -flags, which prints a description of
-// its flags in JSON to stdout.
+// We query the flags of the tool specified by -vettool and accept any
+// of those flags plus any flag valid for 'go build'. The tool must
+// support -flags, which prints a description of its flags in JSON to
+// stdout.
-// GOVETTOOL specifies the vet command to run.
-// This must be an environment variable because
-// we need it before flag processing, as we execute
-// $GOVETTOOL to discover the set of flags it supports.
+// vetTool specifies the vet command to run.
+// Any tool that supports the (still unpublished) vet
+// command-line protocol may be supplied; see
+// golang.org/x/tools/go/analysis/unitchecker for one
+// implementation. It is also used by tests.
//
-// Using an environment variable also makes it easy for users to opt in
-// to (and later, opt out of) the new cmd/vet analysis driver during the
-// transition. It is also used by tests.
-var vetTool = os.Getenv("GOVETTOOL")
+// The default behavior (vetTool=="") runs 'go tool vet'.
+//
+var vetTool string // -vettool
+
+func init() {
+ // Extract -vettool by ad hoc flag processing:
+ // its value is needed even before we can declare
+ // the flags available during main flag processing.
+ for i, arg := range os.Args {
+ if arg == "-vettool" || arg == "--vettool" {
+ if i+1 >= len(os.Args) {
+ log.Fatalf("%s requires a filename", arg)
+ }
+ vetTool = os.Args[i+1]
+ break
+ } else if strings.HasPrefix(arg, "-vettool=") ||
+ strings.HasPrefix(arg, "--vettool=") {
+ vetTool = arg[strings.IndexByte(arg, '=')+1:]
+ break
+ }
+ }
+}
// vetFlags processes the command line, splitting it at the first non-flag
// into the list of flags and list of packages.
-func vetFlags(args []string) (passToVet, packageNames []string) {
+func vetFlags(usage func(), args []string) (passToVet, packageNames []string) {
// Query the vet command for its flags.
tool := vetTool
if tool != "" {
@@ -94,6 +113,9 @@ func vetFlags(args []string) (passToVet, packageNames []string) {
// Add build flags to vetFlagDefn.
var cmd base.Command
work.AddBuildFlags(&cmd)
+ // This flag declaration is a placeholder:
+ // -vettool is actually parsed by the init function above.
+ cmd.Flag.StringVar(new(string), "vettool", "", "path to vet tool binary")
cmd.Flag.VisitAll(func(f *flag.Flag) {
vetFlagDefn = append(vetFlagDefn, &cmdflag.Defn{
Name: f.Name,
@@ -108,7 +130,7 @@ func vetFlags(args []string) (passToVet, packageNames []string) {
return args[:i], args[i:]
}
- f, value, extraWord := cmdflag.Parse("vet", vetFlagDefn, args, i)
+ f, value, extraWord := cmdflag.Parse("vet", usage, vetFlagDefn, args, i)
if f == nil {
fmt.Fprintf(os.Stderr, "vet: flag %q not defined\n", args[i])
fmt.Fprintf(os.Stderr, "Run \"go help vet\" for more information\n")
diff --git a/src/cmd/go/internal/work/buildid.go b/src/cmd/go/internal/work/buildid.go
index a6cfb50558..c5aa1db50b 100644
--- a/src/cmd/go/internal/work/buildid.go
+++ b/src/cmd/go/internal/work/buildid.go
@@ -178,7 +178,8 @@ func (b *Builder) toolID(name string) string {
path := base.Tool(name)
desc := "go tool " + name
- // Special case: undocumented $GOVETTOOL overrides usual vet, for testing vet.
+ // Special case: undocumented -vettool overrides usual vet,
+ // for testing vet or supplying an alternative analysis tool.
if name == "vet" && VetTool != "" {
path = VetTool
desc = VetTool
diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go
index d9c59aab80..92e814ee6f 100644
--- a/src/cmd/go/internal/work/exec.go
+++ b/src/cmd/go/internal/work/exec.go
@@ -434,10 +434,6 @@ func (b *Builder) build(a *Action) (err error) {
return fmt.Errorf("missing or invalid binary-only package; expected file %q", a.Package.Target)
}
- if p.Module != nil && !allowedVersion(p.Module.GoVersion) {
- return fmt.Errorf("module requires Go %s", p.Module.GoVersion)
- }
-
if err := b.Mkdir(a.Objdir); err != nil {
return err
}
@@ -638,12 +634,19 @@ func (b *Builder) build(a *Action) (err error) {
objpkg := objdir + "_pkg_.a"
ofile, out, err := BuildToolchain.gc(b, a, objpkg, icfg.Bytes(), len(sfiles) > 0, gofiles)
if len(out) > 0 {
- b.showOutput(a, a.Package.Dir, a.Package.Desc(), b.processOutput(out))
+ output := b.processOutput(out)
+ if p.Module != nil && !allowedVersion(p.Module.GoVersion) {
+ output += "note: module requires Go " + p.Module.GoVersion
+ }
+ b.showOutput(a, a.Package.Dir, a.Package.Desc(), output)
if err != nil {
return errPrintedOutput
}
}
if err != nil {
+ if p.Module != nil && !allowedVersion(p.Module.GoVersion) {
+ b.showOutput(a, a.Package.Dir, a.Package.Desc(), "note: module requires Go "+p.Module.GoVersion)
+ }
return err
}
if ofile != objpkg {
diff --git a/src/cmd/go/internal/work/gc.go b/src/cmd/go/internal/work/gc.go
index 6e5333ccbc..5a0bd1c2cf 100644
--- a/src/cmd/go/internal/work/gc.go
+++ b/src/cmd/go/internal/work/gc.go
@@ -53,6 +53,9 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg []byte, a
pkgpath = "main"
}
gcargs := []string{"-p", pkgpath}
+ if p.Module != nil && p.Module.GoVersion != "" && allowedVersion(p.Module.GoVersion) {
+ gcargs = append(gcargs, "-lang=go"+p.Module.GoVersion)
+ }
if p.Standard {
gcargs = append(gcargs, "-std")
}
diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go
index d6934ce5e9..6a188262cc 100644
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -235,17 +235,6 @@ func init() {
}
func mainUsage() {
- // special case "go test -h"
- if len(os.Args) > 1 && os.Args[1] == "test" {
- test.Usage()
- }
- // Since vet shares code with test in cmdflag, it doesn't show its
- // command usage properly. For now, special case it too.
- // TODO(mvdan): fix the cmdflag package instead; see
- // golang.org/issue/26999
- if len(os.Args) > 1 && os.Args[1] == "vet" {
- vet.CmdVet.Usage()
- }
help.PrintUsage(os.Stderr, base.Go)
os.Exit(2)
}
diff --git a/src/cmd/go/script_test.go b/src/cmd/go/script_test.go
index f03d9840ca..31ddf02fb0 100644
--- a/src/cmd/go/script_test.go
+++ b/src/cmd/go/script_test.go
@@ -11,6 +11,7 @@ import (
"bytes"
"context"
"fmt"
+ "go/build"
"internal/testenv"
"io/ioutil"
"os"
@@ -104,6 +105,7 @@ func (ts *testScript) setup() {
"GOROOT=" + testGOROOT,
tempEnvName() + "=" + filepath.Join(ts.workdir, "tmp"),
"devnull=" + os.DevNull,
+ "goversion=" + goVersion(ts),
":=" + string(os.PathListSeparator),
}
@@ -130,6 +132,16 @@ func (ts *testScript) setup() {
}
}
+// goVersion returns the current Go version.
+func goVersion(ts *testScript) string {
+ tags := build.Default.ReleaseTags
+ version := tags[len(tags)-1]
+ if !regexp.MustCompile(`^go([1-9][0-9]*)\.(0|[1-9][0-9]*)$`).MatchString(version) {
+ ts.fatalf("invalid go version %q", version)
+ }
+ return version[2:]
+}
+
var execCache par.Cache
// run runs the test script.
@@ -331,6 +343,7 @@ var scriptCmds = map[string]func(*testScript, bool, []string){
"addcrlf": (*testScript).cmdAddcrlf,
"cd": (*testScript).cmdCd,
"cmp": (*testScript).cmdCmp,
+ "cmpenv": (*testScript).cmdCmpenv,
"cp": (*testScript).cmdCp,
"env": (*testScript).cmdEnv,
"exec": (*testScript).cmdExec,
@@ -396,7 +409,21 @@ func (ts *testScript) cmdCmp(neg bool, args []string) {
if len(args) != 2 {
ts.fatalf("usage: cmp file1 file2")
}
+ ts.doCmdCmp(args, false)
+}
+// cmpenv compares two files with environment variable substitution.
+func (ts *testScript) cmdCmpenv(neg bool, args []string) {
+ if neg {
+ ts.fatalf("unsupported: ! cmpenv")
+ }
+ if len(args) != 2 {
+ ts.fatalf("usage: cmpenv file1 file2")
+ }
+ ts.doCmdCmp(args, true)
+}
+
+func (ts *testScript) doCmdCmp(args []string, env bool) {
name1, name2 := args[0], args[1]
var text1, text2 string
if name1 == "stdout" {
@@ -413,6 +440,11 @@ func (ts *testScript) cmdCmp(neg bool, args []string) {
ts.check(err)
text2 = string(data)
+ if env {
+ text1 = ts.expand(text1)
+ text2 = ts.expand(text2)
+ }
+
if text1 == text2 {
return
}
diff --git a/src/cmd/go/testdata/script/README b/src/cmd/go/testdata/script/README
index f28f1b87ed..22124b9fb8 100644
--- a/src/cmd/go/testdata/script/README
+++ b/src/cmd/go/testdata/script/README
@@ -36,6 +36,7 @@ Scripts also have access to these other environment variables:
PATH=
TMPDIR=$WORK/tmp
devnull=
+ goversion=
The environment variable $exe (lowercase) is an empty string on most systems, ".exe" on Windows.
@@ -92,6 +93,10 @@ The commands are:
from the most recent exec or go command.
(If the files have differing content, the failure prints a diff.)
+- cmpenv file1 file2
+ Like cmp, but environment variables are substituted in the file contents
+ before the comparison. For example, $GOOS is replaced by the target GOOS.
+
- cp src... dst
Copy the listed files to the target file or existing directory.
diff --git a/src/cmd/go/testdata/script/help.txt b/src/cmd/go/testdata/script/help.txt
index 656e680100..3d0650880e 100644
--- a/src/cmd/go/testdata/script/help.txt
+++ b/src/cmd/go/testdata/script/help.txt
@@ -35,7 +35,13 @@ stderr 'Run ''go help mod'' for usage.'
stderr 'usage: go vet'
stderr 'Run ''go help vet'' for details'
+# Earlier versions of Go printed a large document here, instead of these two
+# lines.
+! go test -h
+stderr 'usage: go test'
+stderr 'Run ''go help test'' for details'
+
# go help get shows usage for get
go help get
stdout 'usage: go get'
-stdout 'get when using GOPATH'
\ No newline at end of file
+stdout 'get when using GOPATH'
diff --git a/src/cmd/go/testdata/script/mod_edit.txt b/src/cmd/go/testdata/script/mod_edit.txt
index 60a6f74536..61801d5021 100644
--- a/src/cmd/go/testdata/script/mod_edit.txt
+++ b/src/cmd/go/testdata/script/mod_edit.txt
@@ -10,37 +10,37 @@ stderr 'cannot determine module path'
go mod init x.x/y/z
stderr 'creating new go.mod: module x.x/y/z'
-cmp go.mod $WORK/go.mod.init
+cmpenv go.mod $WORK/go.mod.init
! go mod init
-cmp go.mod $WORK/go.mod.init
+cmpenv go.mod $WORK/go.mod.init
# go mod edits
go mod edit -droprequire=x.1 -require=x.1@v1.0.0 -require=x.2@v1.1.0 -droprequire=x.2 -exclude='x.1 @ v1.2.0' -exclude=x.1@v1.2.1 -replace=x.1@v1.3.0=y.1@v1.4.0 -replace='x.1@v1.4.0 = ../z'
-cmp go.mod $WORK/go.mod.edit1
+cmpenv go.mod $WORK/go.mod.edit1
go mod edit -droprequire=x.1 -dropexclude=x.1@v1.2.1 -dropreplace=x.1@v1.3.0 -require=x.3@v1.99.0
-cmp go.mod $WORK/go.mod.edit2
+cmpenv go.mod $WORK/go.mod.edit2
# go mod edit -json
go mod edit -json
-cmp stdout $WORK/go.mod.json
+cmpenv stdout $WORK/go.mod.json
# go mod edit -replace
go mod edit -replace=x.1@v1.3.0=y.1/v2@v2.3.5 -replace=x.1@v1.4.0=y.1/v2@v2.3.5
-cmp go.mod $WORK/go.mod.edit3
+cmpenv go.mod $WORK/go.mod.edit3
go mod edit -replace=x.1=y.1/v2@v2.3.6
-cmp go.mod $WORK/go.mod.edit4
+cmpenv go.mod $WORK/go.mod.edit4
go mod edit -dropreplace=x.1
-cmp go.mod $WORK/go.mod.edit5
+cmpenv go.mod $WORK/go.mod.edit5
# go mod edit -fmt
cp $WORK/go.mod.badfmt go.mod
go mod edit -fmt -print # -print should avoid writing file
-cmp stdout $WORK/go.mod.edit4
+cmpenv stdout $WORK/go.mod.edit6
cmp go.mod $WORK/go.mod.badfmt
go mod edit -fmt # without -print, should write file (and nothing to stdout)
! stdout .
-cmp go.mod $WORK/go.mod.edit4
+cmpenv go.mod $WORK/go.mod.edit6
-- x.go --
package x
@@ -50,9 +50,13 @@ package w
-- $WORK/go.mod.init --
module x.x/y/z
+
+go $goversion
-- $WORK/go.mod.edit1 --
module x.x/y/z
+go $goversion
+
require x.1 v1.0.0
exclude (
@@ -67,6 +71,8 @@ replace (
-- $WORK/go.mod.edit2 --
module x.x/y/z
+go $goversion
+
exclude x.1 v1.2.0
replace x.1 v1.4.0 => ../z
@@ -77,6 +83,7 @@ require x.3 v1.99.0
"Module": {
"Path": "x.x/y/z"
},
+ "Go": "$goversion",
"Require": [
{
"Path": "x.3",
@@ -104,6 +111,8 @@ require x.3 v1.99.0
-- $WORK/go.mod.edit3 --
module x.x/y/z
+go $goversion
+
exclude x.1 v1.2.0
replace (
@@ -115,6 +124,8 @@ require x.3 v1.99.0
-- $WORK/go.mod.edit4 --
module x.x/y/z
+go $goversion
+
exclude x.1 v1.2.0
replace x.1 => y.1/v2 v2.3.6
@@ -123,12 +134,26 @@ require x.3 v1.99.0
-- $WORK/go.mod.edit5 --
module x.x/y/z
+go $goversion
+
exclude x.1 v1.2.0
+require x.3 v1.99.0
+-- $WORK/go.mod.edit6 --
+module x.x/y/z
+
+go 1.10
+
+exclude x.1 v1.2.0
+
+replace x.1 => y.1/v2 v2.3.6
+
require x.3 v1.99.0
-- $WORK/go.mod.badfmt --
module x.x/y/z
+go 1.10
+
exclude x.1 v1.2.0
replace x.1 => y.1/v2 v2.3.6
diff --git a/src/cmd/go/testdata/script/mod_edit_go.txt b/src/cmd/go/testdata/script/mod_edit_go.txt
new file mode 100644
index 0000000000..3ec8137e2d
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_edit_go.txt
@@ -0,0 +1,16 @@
+# Test support for go mod -edit to set language version.
+
+env GO111MODULE=on
+! go build
+stderr 'type aliases only supported as of'
+go mod edit -go=1.9
+grep 'go 1.9' go.mod
+go build
+
+-- go.mod --
+module m
+go 1.8
+
+-- alias.go --
+package alias
+type T = int
diff --git a/src/cmd/go/testdata/script/mod_go_version.txt b/src/cmd/go/testdata/script/mod_go_version.txt
index f2de74cee8..37f173531b 100644
--- a/src/cmd/go/testdata/script/mod_go_version.txt
+++ b/src/cmd/go/testdata/script/mod_go_version.txt
@@ -3,9 +3,10 @@
env GO111MODULE=on
go list
-! go build
-stderr 'module requires Go 1.999'
+go build
go build sub.1
+go build subver.1
+! stderr 'module requires'
! go build badsub.1
stderr 'module requires Go 1.11111'
@@ -19,11 +20,13 @@ module m
go 1.999
require (
sub.1 v1.0.0
+ subver.1 v1.0.0
badsub.1 v1.0.0
versioned.1 v1.0.0
)
replace (
sub.1 => ./sub
+ subver.1 => ./subver
badsub.1 => ./badsub
versioned.1 v1.0.0 => ./versioned1
versioned.1 v1.1.0 => ./versioned2
@@ -39,12 +42,20 @@ go 1.11
-- sub/x.go --
package x
+-- subver/go.mod --
+module m
+go 1.11111
+
+-- subver/x.go --
+package x
+
-- badsub/go.mod --
module m
go 1.11111
-- badsub/x.go --
package x
+invalid syntax
-- versioned1/go.mod --
module versioned
@@ -59,3 +70,4 @@ go 1.99999
-- versioned2/x.go --
package x
+invalid syntax
diff --git a/src/cmd/go/testdata/script/mod_readonly.txt b/src/cmd/go/testdata/script/mod_readonly.txt
index 1b5932e441..188a66d0e1 100644
--- a/src/cmd/go/testdata/script/mod_readonly.txt
+++ b/src/cmd/go/testdata/script/mod_readonly.txt
@@ -37,6 +37,8 @@ cmp go.mod go.mod.inconsistent
-- go.mod --
module m
+go 1.20
+
-- x.go --
package x
import _ "rsc.io/quote"
diff --git a/src/cmd/go/testdata/script/mod_tidy.txt b/src/cmd/go/testdata/script/mod_tidy.txt
index 449aa073a7..de3b52e2c0 100644
--- a/src/cmd/go/testdata/script/mod_tidy.txt
+++ b/src/cmd/go/testdata/script/mod_tidy.txt
@@ -5,6 +5,9 @@ go mod tidy -v
stderr '^unused y.1'
! stderr '^unused [^y]'
+# tidy should not touch existing go line
+grep 'go 1.10' go.mod
+
go list -m all
! stdout '^y'
stdout '^w.1 v1.2.0'
@@ -12,11 +15,17 @@ stdout '^z.1 v1.2.0'
# empty tidy should not crash
cd triv
+! grep 'go ' go.mod
go mod tidy
+# tidy should add missing go line
+grep 'go ' go.mod
+
-- go.mod --
module m
+go 1.10
+
require (
x.1 v1.0.0
y.1 v1.0.0
diff --git a/src/cmd/internal/dwarf/dwarf.go b/src/cmd/internal/dwarf/dwarf.go
index 21512a80bd..8ad84105a4 100644
--- a/src/cmd/internal/dwarf/dwarf.go
+++ b/src/cmd/internal/dwarf/dwarf.go
@@ -967,7 +967,7 @@ Outer:
}
}
-// HasChildren returns true if 'die' uses an abbrev that supports children.
+// HasChildren reports whether 'die' uses an abbrev that supports children.
func HasChildren(die *DWDie) bool {
return abbrevs[die.Abbrev].children != 0
}
diff --git a/src/cmd/internal/obj/arm64/a.out.go b/src/cmd/internal/obj/arm64/a.out.go
index c4c75e41d4..18cdd10f9b 100644
--- a/src/cmd/internal/obj/arm64/a.out.go
+++ b/src/cmd/internal/obj/arm64/a.out.go
@@ -414,6 +414,8 @@ const (
C_BITCON // bitfield and logical immediate masks
C_ADDCON2 // 24-bit constant
C_LCON // 32-bit constant
+ C_MOVCON2 // a constant that can be loaded with one MOVZ/MOVN and one MOVK
+ C_MOVCON3 // a constant that can be loaded with one MOVZ/MOVN and two MOVKs
C_VCON // 64-bit constant
C_FCON // floating-point constant
C_VCONADDR // 64-bit memory address
diff --git a/src/cmd/internal/obj/arm64/anames7.go b/src/cmd/internal/obj/arm64/anames7.go
index f8fdc68c1e..e1703fc4ab 100644
--- a/src/cmd/internal/obj/arm64/anames7.go
+++ b/src/cmd/internal/obj/arm64/anames7.go
@@ -30,6 +30,8 @@ var cnames7 = []string{
"BITCON",
"ADDCON2",
"LCON",
+ "MOVCON2",
+ "MOVCON3",
"VCON",
"FCON",
"VCONADDR",
diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go
index 6a6e81807a..9746426d90 100644
--- a/src/cmd/internal/obj/arm64/asm7.go
+++ b/src/cmd/internal/obj/arm64/asm7.go
@@ -198,9 +198,15 @@ var optab = []Optab{
{ACMP, C_BITCON, C_RSP, C_NONE, C_NONE, 62, 8, 0, 0, 0},
{AADD, C_ADDCON2, C_RSP, C_NONE, C_RSP, 48, 8, 0, 0, 0},
{AADD, C_ADDCON2, C_NONE, C_NONE, C_RSP, 48, 8, 0, 0, 0},
- {AADD, C_VCON, C_RSP, C_NONE, C_RSP, 13, 8, 0, LFROM, 0},
- {AADD, C_VCON, C_NONE, C_NONE, C_RSP, 13, 8, 0, LFROM, 0},
- {ACMP, C_VCON, C_REG, C_NONE, C_NONE, 13, 8, 0, LFROM, 0},
+ {AADD, C_MOVCON2, C_RSP, C_NONE, C_RSP, 13, 12, 0, 0, 0},
+ {AADD, C_MOVCON2, C_NONE, C_NONE, C_RSP, 13, 12, 0, 0, 0},
+ {AADD, C_MOVCON3, C_RSP, C_NONE, C_RSP, 13, 16, 0, 0, 0},
+ {AADD, C_MOVCON3, C_NONE, C_NONE, C_RSP, 13, 16, 0, 0, 0},
+ {AADD, C_VCON, C_RSP, C_NONE, C_RSP, 13, 20, 0, 0, 0},
+ {AADD, C_VCON, C_NONE, C_NONE, C_RSP, 13, 20, 0, 0, 0},
+ {ACMP, C_MOVCON2, C_REG, C_NONE, C_NONE, 13, 12, 0, 0, 0},
+ {ACMP, C_MOVCON3, C_REG, C_NONE, C_NONE, 13, 16, 0, 0, 0},
+ {ACMP, C_VCON, C_REG, C_NONE, C_NONE, 13, 20, 0, 0, 0},
{AADD, C_SHIFT, C_REG, C_NONE, C_REG, 3, 4, 0, 0, 0},
{AADD, C_SHIFT, C_NONE, C_NONE, C_REG, 3, 4, 0, 0, 0},
{AMVN, C_SHIFT, C_NONE, C_NONE, C_REG, 3, 4, 0, 0, 0},
@@ -255,11 +261,21 @@ var optab = []Optab{
{AANDS, C_MOVCON, C_REG, C_NONE, C_REG, 62, 8, 0, 0, 0},
{AANDS, C_MOVCON, C_NONE, C_NONE, C_REG, 62, 8, 0, 0, 0},
{ATST, C_MOVCON, C_REG, C_NONE, C_NONE, 62, 8, 0, 0, 0},
- {AAND, C_VCON, C_REG, C_NONE, C_REG, 28, 8, 0, LFROM, 0},
- {AAND, C_VCON, C_NONE, C_NONE, C_REG, 28, 8, 0, LFROM, 0},
- {AANDS, C_VCON, C_REG, C_NONE, C_REG, 28, 8, 0, LFROM, 0},
- {AANDS, C_VCON, C_NONE, C_NONE, C_REG, 28, 8, 0, LFROM, 0},
- {ATST, C_VCON, C_REG, C_NONE, C_NONE, 28, 8, 0, LFROM, 0},
+ {AAND, C_MOVCON2, C_REG, C_NONE, C_REG, 28, 12, 0, 0, 0},
+ {AAND, C_MOVCON2, C_NONE, C_NONE, C_REG, 28, 12, 0, 0, 0},
+ {AAND, C_MOVCON3, C_REG, C_NONE, C_REG, 28, 16, 0, 0, 0},
+ {AAND, C_MOVCON3, C_NONE, C_NONE, C_REG, 28, 16, 0, 0, 0},
+ {AAND, C_VCON, C_REG, C_NONE, C_REG, 28, 20, 0, 0, 0},
+ {AAND, C_VCON, C_NONE, C_NONE, C_REG, 28, 20, 0, 0, 0},
+ {AANDS, C_MOVCON2, C_REG, C_NONE, C_REG, 28, 12, 0, 0, 0},
+ {AANDS, C_MOVCON2, C_NONE, C_NONE, C_REG, 28, 12, 0, 0, 0},
+ {AANDS, C_MOVCON3, C_REG, C_NONE, C_REG, 28, 16, 0, 0, 0},
+ {AANDS, C_MOVCON3, C_NONE, C_NONE, C_REG, 28, 16, 0, 0, 0},
+ {AANDS, C_VCON, C_REG, C_NONE, C_REG, 28, 20, 0, 0, 0},
+ {AANDS, C_VCON, C_NONE, C_NONE, C_REG, 28, 20, 0, 0, 0},
+ {ATST, C_MOVCON2, C_REG, C_NONE, C_NONE, 28, 12, 0, 0, 0},
+ {ATST, C_MOVCON3, C_REG, C_NONE, C_NONE, 28, 16, 0, 0, 0},
+ {ATST, C_VCON, C_REG, C_NONE, C_NONE, 28, 20, 0, 0, 0},
{AAND, C_SHIFT, C_REG, C_NONE, C_REG, 3, 4, 0, 0, 0},
{AAND, C_SHIFT, C_NONE, C_NONE, C_REG, 3, 4, 0, 0, 0},
{AANDS, C_SHIFT, C_REG, C_NONE, C_REG, 3, 4, 0, 0, 0},
@@ -278,8 +294,10 @@ var optab = []Optab{
{AMOVD, C_MOVCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0},
{AMOVW, C_BITCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0},
{AMOVD, C_BITCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0},
- {AMOVW, C_LCON, C_NONE, C_NONE, C_REG, 12, 4, 0, LFROM, 0},
- {AMOVD, C_VCON, C_NONE, C_NONE, C_REG, 12, 4, 0, LFROM, 0},
+ {AMOVW, C_MOVCON2, C_NONE, C_NONE, C_REG, 12, 8, 0, 0, 0},
+ {AMOVD, C_MOVCON2, C_NONE, C_NONE, C_REG, 12, 8, 0, 0, 0},
+ {AMOVD, C_MOVCON3, C_NONE, C_NONE, C_REG, 12, 12, 0, 0, 0},
+ {AMOVD, C_VCON, C_NONE, C_NONE, C_REG, 12, 16, 0, 0, 0},
{AMOVK, C_VCON, C_NONE, C_NONE, C_REG, 33, 4, 0, 0, 0},
{AMOVD, C_AACON, C_NONE, C_NONE, C_REG, 4, 4, REGFROM, 0, 0},
@@ -401,8 +419,8 @@ var optab = []Optab{
{AMOVH, C_REG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
{AMOVW, C_REG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
{AMOVW, C_REG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
- {AMOVD, C_REG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
{AMOVD, C_REG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
+ {AMOVD, C_REG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
{AFMOVS, C_FREG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
{AFMOVS, C_FREG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
@@ -411,15 +429,15 @@ var optab = []Optab{
/* scaled 12-bit unsigned displacement load */
{AMOVB, C_UAUTO4K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
- {AMOVB, C_UOREG4K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+ {AMOVB, C_UOREG4K, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
{AMOVBU, C_UAUTO4K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
- {AMOVBU, C_UOREG4K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+ {AMOVBU, C_UOREG4K, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
{AMOVH, C_UAUTO8K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
- {AMOVH, C_UOREG8K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+ {AMOVH, C_UOREG8K, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
{AMOVW, C_UAUTO16K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
- {AMOVW, C_UOREG16K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+ {AMOVW, C_UOREG16K, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
{AMOVD, C_UAUTO32K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
- {AMOVD, C_UOREG32K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+ {AMOVD, C_UOREG32K, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
{AFMOVS, C_UAUTO16K, C_NONE, C_NONE, C_FREG, 21, 4, REGSP, 0, 0},
{AFMOVS, C_UOREG16K, C_NONE, C_NONE, C_FREG, 21, 4, 0, 0, 0},
@@ -428,15 +446,15 @@ var optab = []Optab{
/* unscaled 9-bit signed displacement load */
{AMOVB, C_NSAUTO, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
- {AMOVB, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+ {AMOVB, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
{AMOVBU, C_NSAUTO, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
- {AMOVBU, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+ {AMOVBU, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
{AMOVH, C_NSAUTO, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
- {AMOVH, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+ {AMOVH, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
{AMOVW, C_NSAUTO, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
- {AMOVW, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+ {AMOVW, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
{AMOVD, C_NSAUTO, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
- {AMOVD, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+ {AMOVD, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
{AFMOVS, C_NSAUTO, C_NONE, C_NONE, C_FREG, 21, 4, REGSP, 0, 0},
{AFMOVS, C_NSOREG, C_NONE, C_NONE, C_FREG, 21, 4, 0, 0, 0},
@@ -1105,6 +1123,15 @@ func isSTXPop(op obj.As) bool {
return false
}
+func isANDop(op obj.As) bool {
+ switch op {
+ case AAND, AORR, AEOR, AANDS, ATST,
+ ABIC, AEON, AORN, ABICS:
+ return true
+ }
+ return false
+}
+
func isANDWop(op obj.As) bool {
switch op {
case AANDW, AORRW, AEORW, AANDSW, ATSTW,
@@ -1114,6 +1141,14 @@ func isANDWop(op obj.As) bool {
return false
}
+func isADDop(op obj.As) bool {
+ switch op {
+ case AADD, AADDS, ASUB, ASUBS, ACMN, ACMP:
+ return true
+ }
+ return false
+}
+
func isADDWop(op obj.As) bool {
switch op {
case AADDW, AADDSW, ASUBW, ASUBSW, ACMNW, ACMPW:
@@ -1445,6 +1480,12 @@ func (c *ctxt7) con32class(a *obj.Addr) int {
if isbitcon(uint64(v)) {
return C_ABCON
}
+ if movcon(int64(v)) >= 0 {
+ return C_AMCON
+ }
+ if movcon(int64(^v)) >= 0 {
+ return C_AMCON
+ }
return C_ADDCON
}
@@ -1474,6 +1515,29 @@ func (c *ctxt7) con32class(a *obj.Addr) int {
return C_LCON
}
+// con64class reclassifies the constant of C_VCON and C_LCON class.
+func (c *ctxt7) con64class(a *obj.Addr) int {
+ zeroCount := 0
+ negCount := 0
+ for i := uint(0); i < 4; i++ {
+ immh := uint32(a.Offset >> (i * 16) & 0xffff)
+ if immh == 0 {
+ zeroCount++
+ } else if immh == 0xffff {
+ negCount++
+ }
+ }
+ if zeroCount >= 3 || negCount >= 3 {
+ return C_MOVCON
+ } else if zeroCount == 2 || negCount == 2 {
+ return C_MOVCON2
+ } else if zeroCount == 1 || negCount == 1 {
+ return C_MOVCON3
+ } else {
+ return C_VCON
+ }
+}
+
func (c *ctxt7) aclass(a *obj.Addr) int {
switch a.Type {
case obj.TYPE_NONE:
@@ -1689,21 +1753,18 @@ func (c *ctxt7) oplook(p *obj.Prog) *Optab {
a1 = ra0 + 1
p.From.Class = int8(a1)
}
- if isANDWop(p.As) {
- switch p.As {
- case AANDW, AORRW, AEORW, AANDSW, ATSTW:
- // For 32-bit logical instruction with constant,
- // rewrite the high 32-bit to be a copy of the low
- // 32-bit, so that the BITCON test can be shared
- // for both 32-bit and 64-bit.
- if a0 == C_BITCON {
- break
- }
- fallthrough
- default:
- a1 = c.con32class(&p.From) + 1
- p.From.Class = int8(a1)
- }
+ if isANDWop(p.As) && a0 != C_BITCON {
+ // For 32-bit logical instruction with constant,
+ // the BITCON test is special in that it looks at
+ // the 64-bit which has the high 32-bit as a copy
+ // of the low 32-bit. We have handled that and
+ // don't pass it to con32class.
+ a1 = c.con32class(&p.From) + 1
+ p.From.Class = int8(a1)
+ }
+ if ((p.As == AMOVD) || isANDop(p.As) || isADDop(p.As)) && (a0 == C_LCON || a0 == C_VCON) {
+ a1 = c.con64class(&p.From) + 1
+ p.From.Class = int8(a1)
}
}
}
@@ -1800,6 +1861,9 @@ func cmp(a int, b int) bool {
return true
}
+ case C_MOVCON2:
+ return cmp(C_LCON, b)
+
case C_VCON:
return cmp(C_LCON, b)
@@ -2718,6 +2782,7 @@ func (c *ctxt7) checkShiftAmount(p *obj.Prog, a *obj.Addr) {
}
func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
+ var os [5]uint32
o1 := uint32(0)
o2 := uint32(0)
o3 := uint32(0)
@@ -2907,13 +2972,29 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
}
case 12: /* movT $vcon, reg */
- o1 = c.omovlit(p.As, p, &p.From, int(p.To.Reg))
+ num := c.omovlconst(p.As, p, &p.From, int(p.To.Reg), os[:])
+ if num == 0 {
+ c.ctxt.Diag("invalid constant: %v", p)
+ }
+ o1 = os[0]
+ o2 = os[1]
+ o3 = os[2]
+ o4 = os[3]
case 13: /* addop $vcon, [R], R (64 bit literal); cmp $lcon,R -> addop $lcon,R, ZR */
- o1 = c.omovlit(AMOVD, p, &p.From, REGTMP)
-
- if o1 == 0 {
- break
+ o := uint32(0)
+ num := uint8(0)
+ cls := oclass(&p.From)
+ if isADDWop(p.As) {
+ if (cls != C_LCON) && (cls != C_ADDCON2) {
+ c.ctxt.Diag("illegal combination: %v", p)
+ }
+ num = c.omovlconst(AMOVW, p, &p.From, REGTMP, os[:])
+ } else {
+ num = c.omovlconst(AMOVD, p, &p.From, REGTMP, os[:])
+ }
+ if num == 0 {
+ c.ctxt.Diag("invalid constant: %v", p)
}
rt := int(p.To.Reg)
if p.To.Type == obj.TYPE_NONE {
@@ -2924,16 +3005,23 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
r = rt
}
if p.To.Type != obj.TYPE_NONE && (p.To.Reg == REGSP || r == REGSP) {
- o2 = c.opxrrr(p, p.As, false)
- o2 |= REGTMP & 31 << 16
- o2 |= LSL0_64
+ o = c.opxrrr(p, p.As, false)
+ o |= REGTMP & 31 << 16
+ o |= LSL0_64
} else {
- o2 = c.oprrr(p, p.As)
- o2 |= REGTMP & 31 << 16 /* shift is 0 */
+ o = c.oprrr(p, p.As)
+ o |= REGTMP & 31 << 16 /* shift is 0 */
}
- o2 |= uint32(r&31) << 5
- o2 |= uint32(rt & 31)
+ o |= uint32(r&31) << 5
+ o |= uint32(rt & 31)
+
+ os[num] = o
+ o1 = os[0]
+ o2 = os[1]
+ o3 = os[2]
+ o4 = os[3]
+ o5 = os[4]
case 14: /* word */
if c.aclass(&p.To) == C_ADDR {
@@ -3179,10 +3267,20 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
o1 |= (uint32(r&31) << 5) | uint32(rt&31)
case 28: /* logop $vcon, [R], R (64 bit literal) */
- o1 = c.omovlit(AMOVD, p, &p.From, REGTMP)
+ o := uint32(0)
+ num := uint8(0)
+ cls := oclass(&p.From)
+ if isANDWop(p.As) {
+ if (cls != C_LCON) && (cls != C_ADDCON) {
+ c.ctxt.Diag("illegal combination: %v", p)
+ }
+ num = c.omovlconst(AMOVW, p, &p.From, REGTMP, os[:])
+ } else {
+ num = c.omovlconst(AMOVD, p, &p.From, REGTMP, os[:])
+ }
- if o1 == 0 {
- break
+ if num == 0 {
+ c.ctxt.Diag("invalid constant: %v", p)
}
rt := int(p.To.Reg)
if p.To.Type == obj.TYPE_NONE {
@@ -3192,10 +3290,17 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
if r == 0 {
r = rt
}
- o2 = c.oprrr(p, p.As)
- o2 |= REGTMP & 31 << 16 /* shift is 0 */
- o2 |= uint32(r&31) << 5
- o2 |= uint32(rt & 31)
+ o = c.oprrr(p, p.As)
+ o |= REGTMP & 31 << 16 /* shift is 0 */
+ o |= uint32(r&31) << 5
+ o |= uint32(rt & 31)
+
+ os[num] = o
+ o1 = os[0]
+ o2 = os[1]
+ o3 = os[2]
+ o4 = os[3]
+ o5 = os[4]
case 29: /* op Rn, Rd */
fc := c.aclass(&p.From)
@@ -6326,10 +6431,155 @@ func (c *ctxt7) omovconst(as obj.As, p *obj.Prog, a *obj.Addr, rt int) (o1 uint3
}
o1 |= MOVCONST(d, s, rt)
}
-
return o1
}
+// load a 32-bit/64-bit large constant (LCON or VCON) in a.Offset into rt
+// put the instruction sequence in os and return the number of instructions.
+func (c *ctxt7) omovlconst(as obj.As, p *obj.Prog, a *obj.Addr, rt int, os []uint32) (num uint8) {
+ switch as {
+ case AMOVW:
+ d := uint32(a.Offset)
+ // use MOVZW and MOVKW to load a constant to rt
+ os[0] = c.opirr(p, AMOVZW)
+ os[0] |= MOVCONST(int64(d), 0, rt)
+ os[1] = c.opirr(p, AMOVKW)
+ os[1] |= MOVCONST(int64(d), 1, rt)
+ return 2
+
+ case AMOVD:
+ d := a.Offset
+ dn := ^d
+ var immh [4]uint64
+ var i int
+ zeroCount := int(0)
+ negCount := int(0)
+ for i = 0; i < 4; i++ {
+ immh[i] = uint64((d >> uint(i*16)) & 0xffff)
+ if immh[i] == 0 {
+ zeroCount++
+ } else if immh[i] == 0xffff {
+ negCount++
+ }
+ }
+
+ if zeroCount == 4 || negCount == 4 {
+ c.ctxt.Diag("the immediate should be MOVCON: %v", p)
+ }
+ switch {
+ case zeroCount == 3:
+ // one MOVZ
+ for i = 0; i < 4; i++ {
+ if immh[i] != 0 {
+ os[0] = c.opirr(p, AMOVZ)
+ os[0] |= MOVCONST(d, i, rt)
+ break
+ }
+ }
+ return 1
+
+ case negCount == 3:
+ // one MOVN
+ for i = 0; i < 4; i++ {
+ if immh[i] != 0xffff {
+ os[0] = c.opirr(p, AMOVN)
+ os[0] |= MOVCONST(dn, i, rt)
+ break
+ }
+ }
+ return 1
+
+ case zeroCount == 2:
+ // one MOVZ and one MOVK
+ for i = 0; i < 4; i++ {
+ if immh[i] != 0 {
+ os[0] = c.opirr(p, AMOVZ)
+ os[0] |= MOVCONST(d, i, rt)
+ i++
+ break
+ }
+ }
+ for ; i < 4; i++ {
+ if immh[i] != 0 {
+ os[1] = c.opirr(p, AMOVK)
+ os[1] |= MOVCONST(d, i, rt)
+ }
+ }
+ return 2
+
+ case negCount == 2:
+ // one MOVN and one MOVK
+ for i = 0; i < 4; i++ {
+ if immh[i] != 0xffff {
+ os[0] = c.opirr(p, AMOVN)
+ os[0] |= MOVCONST(dn, i, rt)
+ i++
+ break
+ }
+ }
+ for ; i < 4; i++ {
+ if immh[i] != 0xffff {
+ os[1] = c.opirr(p, AMOVK)
+ os[1] |= MOVCONST(d, i, rt)
+ }
+ }
+ return 2
+
+ case zeroCount == 1:
+ // one MOVZ and two MOVKs
+ for i = 0; i < 4; i++ {
+ if immh[i] != 0 {
+ os[0] = c.opirr(p, AMOVZ)
+ os[0] |= MOVCONST(d, i, rt)
+ i++
+ break
+ }
+ }
+
+ for j := 1; i < 4; i++ {
+ if immh[i] != 0 {
+ os[j] = c.opirr(p, AMOVK)
+ os[j] |= MOVCONST(d, i, rt)
+ j++
+ }
+ }
+ return 3
+
+ case negCount == 1:
+ // one MOVN and two MOVKs
+ for i = 0; i < 4; i++ {
+ if immh[i] != 0xffff {
+ os[0] = c.opirr(p, AMOVN)
+ os[0] |= MOVCONST(dn, i, rt)
+ i++
+ break
+ }
+ }
+
+ for j := 1; i < 4; i++ {
+ if immh[i] != 0xffff {
+ os[j] = c.opirr(p, AMOVK)
+ os[j] |= MOVCONST(d, i, rt)
+ j++
+ }
+ }
+ return 3
+
+ default:
+ // one MOVZ and 3 MOVKs
+ os[0] = c.opirr(p, AMOVZ)
+ os[0] |= MOVCONST(d, 0, rt)
+ for i = 1; i < 4; i++ {
+ os[i] = c.opirr(p, AMOVK)
+ os[i] |= MOVCONST(d, i, rt)
+ }
+ return 4
+ }
+ default:
+ return 0
+ }
+}
+
func (c *ctxt7) opbfm(p *obj.Prog, a obj.As, r int, s int, rf int, rt int) uint32 {
var b uint32
o := c.opirr(p, a)
diff --git a/src/cmd/internal/obj/arm64/doc.go b/src/cmd/internal/obj/arm64/doc.go
index 845fb22817..7fb129989b 100644
--- a/src/cmd/internal/obj/arm64/doc.go
+++ b/src/cmd/internal/obj/arm64/doc.go
@@ -89,7 +89,7 @@ such as str, stur, strb, sturb, strh, sturh stlr, stlrb. stlrh, st1.
Examples:
MOVD R29, 384(R19) <=> str x29, [x19,#384]
MOVB.P R30, 30(R4) <=> strb w30, [x4],#30
- STLRH R21, (R18) <=> stlrh w21, [x18]
+ STLRH R21, (R19) <=> stlrh w21, [x19]
(2) MADD, MADDW, MSUB, MSUBW, SMADDL, SMSUBL, UMADDL, UMSUBL , , ,
@@ -127,7 +127,7 @@ such as str, stur, strb, sturb, strh, sturh stlr, stlrb. stlrh, st1.
Examples:
CCMN VS, R13, R22, $10 <=> ccmn x13, x22, #0xa, vs
- CCMPW HS, R18, R14, $11 <=> ccmp w18, w14, #0xb, cs
+ CCMPW HS, R19, R14, $11 <=> ccmp w19, w14, #0xb, cs
(9) CSEL, CSELW, CSNEG, CSNEGW, CSINC, CSINCW , , , ;
FCSELD, FCSELS , , ,
@@ -144,12 +144,12 @@ FCSELD, FCSELS , , ,
Examples:
STLXR ZR, (R15), R16 <=> stlxr w16, xzr, [x15]
- STXRB R9, (R21), R18 <=> stxrb w18, w9, [x21]
+ STXRB R9, (R21), R19 <=> stxrb w19, w9, [x21]
(12) STLXP, STLXPW, STXP, STXPW (, ), (),
Examples:
- STLXP (R17, R18), (R4), R5 <=> stlxp w5, x17, x18, [x4]
+ STLXP (R17, R19), (R4), R5 <=> stlxp w5, x17, x19, [x4]
STXPW (R30, R25), (R22), R13 <=> stxp w13, w30, w25, [x22]
2. Expressions for special arguments.
@@ -173,7 +173,7 @@ Extended registers are written as {.{<<}}.
can be UXTB, UXTH, UXTW, UXTX, SXTB, SXTH, SXTW or SXTX.
Examples:
- ADDS R18.UXTB<<4, R9, R26 <=> adds x26, x9, w18, uxtb #4
+ ADDS R19.UXTB<<4, R9, R26 <=> adds x26, x9, w19, uxtb #4
ADDSW R14.SXTX, R14, R6 <=> adds w6, w14, w14, sxtx
Memory references: [{,#0}] is written as (Rn|RSP), a base register and an immediate
diff --git a/src/cmd/internal/obj/arm64/obj7.go b/src/cmd/internal/obj/arm64/obj7.go
index 4476dad071..d0e354eabd 100644
--- a/src/cmd/internal/obj/arm64/obj7.go
+++ b/src/cmd/internal/obj/arm64/obj7.go
@@ -311,12 +311,9 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
// shared for both 32-bit and 64-bit. 32-bit ops
// will zero the high 32-bit of the destination
// register anyway.
- switch p.As {
- case AANDW, AORRW, AEORW, AANDSW, ATSTW:
- if p.From.Type == obj.TYPE_CONST {
- v := p.From.Offset & 0xffffffff
- p.From.Offset = v | v<<32
- }
+ if isANDWop(p.As) && p.From.Type == obj.TYPE_CONST {
+ v := p.From.Offset & 0xffffffff
+ p.From.Offset = v | v<<32
}
if c.ctxt.Flag_dynlink {
diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go
index f983d5277e..d924cbc214 100644
--- a/src/cmd/internal/obj/link.go
+++ b/src/cmd/internal/obj/link.go
@@ -403,9 +403,9 @@ type FuncInfo struct {
dwarfAbsFnSym *LSym
dwarfIsStmtSym *LSym
- GCArgs LSym
- GCLocals LSym
- GCRegs LSym
+ GCArgs *LSym
+ GCLocals *LSym
+ GCRegs *LSym
StackObjects *LSym
}
diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go
index b6cfec3b3e..3c72f543cc 100644
--- a/src/cmd/internal/obj/objfile.go
+++ b/src/cmd/internal/obj/objfile.go
@@ -25,12 +25,6 @@ type objWriter struct {
// Temporary buffer for zigzag int writing.
varintbuf [10]uint8
- // Provide the index of a symbol reference by symbol name.
- // One map for versioned symbols and one for unversioned symbols.
- // Used for deduplicating the symbol reference list.
- refIdx map[string]int
- vrefIdx map[string]int
-
// Number of objects written of each type.
nRefs int
nData int
@@ -79,10 +73,8 @@ func (w *objWriter) writeLengths() {
func newObjWriter(ctxt *Link, b *bufio.Writer) *objWriter {
return &objWriter{
- ctxt: ctxt,
- wr: b,
- vrefIdx: make(map[string]int),
- refIdx: make(map[string]int),
+ ctxt: ctxt,
+ wr: b,
}
}
@@ -157,17 +149,6 @@ func (w *objWriter) writeRef(s *LSym, isPath bool) {
if s == nil || s.RefIdx != 0 {
return
}
- var m map[string]int
- if !s.Static() {
- m = w.refIdx
- } else {
- m = w.vrefIdx
- }
-
- if idx := m[s.Name]; idx != 0 {
- s.RefIdx = idx
- return
- }
w.wr.WriteByte(symPrefix)
if isPath {
w.writeString(filepath.ToSlash(s.Name))
@@ -178,7 +159,6 @@ func (w *objWriter) writeRef(s *LSym, isPath bool) {
w.writeBool(s.Static())
w.nRefs++
s.RefIdx = w.nRefs
- m[s.Name] = w.nRefs
}
func (w *objWriter) writeRefs(s *LSym) {
diff --git a/src/cmd/internal/obj/plist.go b/src/cmd/internal/obj/plist.go
index a8675055d9..6710b375f1 100644
--- a/src/cmd/internal/obj/plist.go
+++ b/src/cmd/internal/obj/plist.go
@@ -147,18 +147,6 @@ func (ctxt *Link) InitTextSym(s *LSym, flag int) {
isstmt.Type = objabi.SDWARFMISC
isstmt.Set(AttrDuplicateOK, s.DuplicateOK())
ctxt.Data = append(ctxt.Data, isstmt)
-
- // Set up the function's gcargs and gclocals.
- // They will be filled in later if needed.
- gcargs := &s.Func.GCArgs
- gcargs.Set(AttrDuplicateOK, true)
- gcargs.Type = objabi.SRODATA
- gclocals := &s.Func.GCLocals
- gclocals.Set(AttrDuplicateOK, true)
- gclocals.Type = objabi.SRODATA
- gcregs := &s.Func.GCRegs
- gcregs.Set(AttrDuplicateOK, true)
- gcregs.Type = objabi.SRODATA
}
func (ctxt *Link) Globl(s *LSym, size int64, flag int) {
diff --git a/src/cmd/internal/obj/wasm/a.out.go b/src/cmd/internal/obj/wasm/a.out.go
index 6f882215ff..0e8196be60 100644
--- a/src/cmd/internal/obj/wasm/a.out.go
+++ b/src/cmd/internal/obj/wasm/a.out.go
@@ -246,7 +246,7 @@ const (
REG_RET1
REG_RET2
REG_RET3
- REG_RUN
+ REG_PAUSE
// locals
REG_R0
diff --git a/src/cmd/internal/obj/wasm/wasmobj.go b/src/cmd/internal/obj/wasm/wasmobj.go
index b1eae2882b..f271101f4b 100644
--- a/src/cmd/internal/obj/wasm/wasmobj.go
+++ b/src/cmd/internal/obj/wasm/wasmobj.go
@@ -16,16 +16,16 @@ import (
)
var Register = map[string]int16{
- "PC_F": REG_PC_F,
- "PC_B": REG_PC_B,
- "SP": REG_SP,
- "CTXT": REG_CTXT,
- "g": REG_g,
- "RET0": REG_RET0,
- "RET1": REG_RET1,
- "RET2": REG_RET2,
- "RET3": REG_RET3,
- "RUN": REG_RUN,
+ "PC_F": REG_PC_F,
+ "PC_B": REG_PC_B,
+ "SP": REG_SP,
+ "CTXT": REG_CTXT,
+ "g": REG_g,
+ "RET0": REG_RET0,
+ "RET1": REG_RET1,
+ "RET2": REG_RET2,
+ "RET3": REG_RET3,
+ "PAUSE": REG_PAUSE,
"R0": REG_R0,
"R1": REG_R1,
@@ -777,7 +777,7 @@ func assemble(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
}
reg := p.From.Reg
switch {
- case reg >= REG_PC_F && reg <= REG_RUN:
+ case reg >= REG_PC_F && reg <= REG_PAUSE:
w.WriteByte(0x23) // get_global
writeUleb128(w, uint64(reg-REG_PC_F))
case reg >= REG_R0 && reg <= REG_R15:
@@ -797,7 +797,7 @@ func assemble(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
}
reg := p.To.Reg
switch {
- case reg >= REG_PC_F && reg <= REG_RUN:
+ case reg >= REG_PC_F && reg <= REG_PAUSE:
w.WriteByte(0x24) // set_global
writeUleb128(w, uint64(reg-REG_PC_F))
case reg >= REG_R0 && reg <= REG_F15:
diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go
index 1d056097c3..a4507352f7 100644
--- a/src/cmd/internal/obj/x86/asm6.go
+++ b/src/cmd/internal/obj/x86/asm6.go
@@ -4704,7 +4704,9 @@ func (ab *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
r = obj.Addrel(cursym)
r.Off = int32(p.Pc + int64(ab.Len()))
r.Sym = p.To.Sym
- r.Type = objabi.R_PCREL
+ // Note: R_CALL instead of R_PCREL. R_CALL is more permissive in that
+ // it can point to a trampoline instead of the destination itself.
+ r.Type = objabi.R_CALL
r.Siz = 4
ab.PutInt32(0)
break
diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go
index 770590fd35..5ba038d147 100644
--- a/src/cmd/link/internal/arm64/asm.go
+++ b/src/cmd/link/internal/arm64/asm.go
@@ -256,7 +256,7 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bo
// (https://sourceware.org/bugzilla/show_bug.cgi?id=18270). So
// we convert the adrp; ld64 + R_ARM64_GOTPCREL into adrp;
// add + R_ADDRARM64.
- if !(r.Sym.Version != 0 || r.Sym.Attr.VisibilityHidden() || r.Sym.Attr.Local()) && r.Sym.Type == sym.STEXT && ctxt.DynlinkingGo() {
+ if !(r.Sym.IsFileLocal() || r.Sym.Attr.VisibilityHidden() || r.Sym.Attr.Local()) && r.Sym.Type == sym.STEXT && ctxt.DynlinkingGo() {
if o2&0xffc00000 != 0xf9400000 {
ld.Errorf(s, "R_ARM64_GOTPCREL against unexpected instruction %x", o2)
}
diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go
index 7a20650d9c..d10f4ab3c3 100644
--- a/src/cmd/link/internal/ld/dwarf.go
+++ b/src/cmd/link/internal/ld/dwarf.go
@@ -342,6 +342,26 @@ func lookupOrDiag(ctxt *Link, n string) *sym.Symbol {
return s
}
+// dwarfFuncSym looks up a DWARF metadata symbol for function symbol s.
+// If the symbol does not exist, it creates it if create is true,
+// or returns nil otherwise.
+func dwarfFuncSym(ctxt *Link, s *sym.Symbol, meta string, create bool) *sym.Symbol {
+ // All function ABIs use symbol version 0 for the DWARF data.
+ //
+ // TODO(austin): It may be useful to have DWARF info for ABI
+ // wrappers, in which case we may want these versions to
+ // align. Better yet, replace these name lookups with a
+ // general way to attach metadata to a symbol.
+ ver := 0
+ if s.IsFileLocal() {
+ ver = int(s.Version)
+ }
+ if create {
+ return ctxt.Syms.Lookup(meta+s.Name, ver)
+ }
+ return ctxt.Syms.ROLookup(meta+s.Name, ver)
+}
+
func dotypedef(ctxt *Link, parent *dwarf.DWDie, name string, def *dwarf.DWDie) *dwarf.DWDie {
// Only emit typedefs for real names.
if strings.HasPrefix(name, "map[") {
@@ -843,7 +863,7 @@ func dwarfDefineGlobal(ctxt *Link, s *sym.Symbol, str string, v int64, gotype *s
}
dv := newdie(ctxt, ctxt.compUnitByPackage[lib].dwinfo, dwarf.DW_ABRV_VARIABLE, str, int(s.Version))
newabslocexprattr(dv, v, s)
- if s.Version == 0 {
+ if !s.IsFileLocal() {
newattr(dv, dwarf.DW_AT_external, dwarf.DW_CLS_FLAG, 1, 0)
}
dt := defgotype(ctxt, gotype)
@@ -1146,7 +1166,7 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) {
// indexes (created by numberfile) to CU-local indexes.
fileNums := make(map[int]int)
for _, s := range unit.lib.Textp { // textp has been dead-code-eliminated already.
- dsym := ctxt.Syms.Lookup(dwarf.InfoPrefix+s.Name, int(s.Version))
+ dsym := dwarfFuncSym(ctxt, s, dwarf.InfoPrefix, true)
for _, f := range s.FuncInfo.File {
if _, ok := fileNums[int(f.Value)]; ok {
continue
@@ -1756,12 +1776,12 @@ func dwarfGenerateDebugInfo(ctxt *Link) {
// referenced abstract functions.
// Collect all debug_range symbols in unit.rangeSyms
for _, s := range lib.Textp { // textp has been dead-code-eliminated already.
- dsym := ctxt.Syms.ROLookup(dwarf.InfoPrefix+s.Name, int(s.Version))
+ dsym := dwarfFuncSym(ctxt, s, dwarf.InfoPrefix, false)
dsym.Attr |= sym.AttrNotInSymbolTable | sym.AttrReachable
dsym.Type = sym.SDWARFINFO
unit.funcDIEs = append(unit.funcDIEs, dsym)
- rangeSym := ctxt.Syms.ROLookup(dwarf.RangePrefix+s.Name, int(s.Version))
+ rangeSym := dwarfFuncSym(ctxt, s, dwarf.RangePrefix, false)
if rangeSym != nil && rangeSym.Size > 0 {
rangeSym.Attr |= sym.AttrReachable | sym.AttrNotInSymbolTable
rangeSym.Type = sym.SDWARFRANGE
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index a70935e821..2af9c76a8b 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -2130,7 +2130,7 @@ func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int6
if s.Attr.NotInSymbolTable() {
continue
}
- if (s.Name == "" || s.Name[0] == '.') && s.Version == 0 && s.Name != ".rathole" && s.Name != ".TOC." {
+ if (s.Name == "" || s.Name[0] == '.') && !s.IsFileLocal() && s.Name != ".rathole" && s.Name != ".TOC." {
continue
}
switch s.Type {
diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go
index cf197f50b0..68251786ed 100644
--- a/src/cmd/link/internal/ld/pe.go
+++ b/src/cmd/link/internal/ld/pe.go
@@ -704,7 +704,7 @@ func (f *peFile) writeSymbols(ctxt *Link) {
}
}
class := IMAGE_SYM_CLASS_EXTERNAL
- if s.Version != 0 || s.Attr.VisibilityHidden() || s.Attr.Local() {
+ if s.IsFileLocal() || s.Attr.VisibilityHidden() || s.Attr.Local() {
class = IMAGE_SYM_CLASS_STATIC
}
f.writeSymbol(ctxt.Out, s, value, sect, typ, uint8(class))
diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go
index d2737deca5..276a3a1cbb 100644
--- a/src/cmd/link/internal/ld/symtab.go
+++ b/src/cmd/link/internal/ld/symtab.go
@@ -128,7 +128,7 @@ func putelfsym(ctxt *Link, x *sym.Symbol, s string, t SymbolType, addr int64, go
// maybe one day STB_WEAK.
bind := STB_GLOBAL
- if x.Version != 0 || x.Attr.VisibilityHidden() || x.Attr.Local() {
+ if x.IsFileLocal() || x.Attr.VisibilityHidden() || x.Attr.Local() {
bind = STB_LOCAL
}
@@ -224,7 +224,7 @@ func putplan9sym(ctxt *Link, x *sym.Symbol, s string, typ SymbolType, addr int64
t := int(typ)
switch typ {
case TextSym, DataSym, BSSSym:
- if x.Version != 0 {
+ if x.IsFileLocal() {
t += 'a' - 'A'
}
fallthrough
diff --git a/src/cmd/link/internal/sym/symbol.go b/src/cmd/link/internal/sym/symbol.go
index a6c2aaea77..4faa991463 100644
--- a/src/cmd/link/internal/sym/symbol.go
+++ b/src/cmd/link/internal/sym/symbol.go
@@ -51,6 +51,10 @@ type AuxSymbol struct {
elftype elf.SymType
}
+const (
+ SymVerStatic = 10 // Minimum version used by static (file-local) syms
+)
+
func (s *Symbol) String() string {
if s.Version == 0 {
return s.Name
@@ -58,6 +62,10 @@ func (s *Symbol) String() string {
return fmt.Sprintf("%s<%d>", s.Name, s.Version)
}
+func (s *Symbol) IsFileLocal() bool {
+ return s.Version >= SymVerStatic
+}
+
func (s *Symbol) ElfsymForReloc() int32 {
// If putelfsym created a local version of this symbol, use that in all
// relocations.
diff --git a/src/cmd/link/internal/sym/symbols.go b/src/cmd/link/internal/sym/symbols.go
index d79d1d8b1d..d7266c840b 100644
--- a/src/cmd/link/internal/sym/symbols.go
+++ b/src/cmd/link/internal/sym/symbols.go
@@ -40,12 +40,11 @@ type Symbols struct {
}
func NewSymbols() *Symbols {
+ hash := make([]map[string]*Symbol, SymVerStatic)
+ // Preallocate about 2mb for hash of non static symbols
+ hash[0] = make(map[string]*Symbol, 100000)
return &Symbols{
- hash: []map[string]*Symbol{
- // preallocate about 2mb for hash of
- // non static symbols
- make(map[string]*Symbol, 100000),
- },
+ hash: hash,
Allsym: make([]*Symbol, 0, 100000),
}
}
diff --git a/src/cmd/link/internal/wasm/asm.go b/src/cmd/link/internal/wasm/asm.go
index bffbc7c8a6..737de59928 100644
--- a/src/cmd/link/internal/wasm/asm.go
+++ b/src/cmd/link/internal/wasm/asm.go
@@ -54,7 +54,11 @@ type wasmFuncType struct {
}
var wasmFuncTypes = map[string]*wasmFuncType{
- "_rt0_wasm_js": &wasmFuncType{Params: []byte{I32, I32}}, // argc, argv
+ "_rt0_wasm_js": &wasmFuncType{Params: []byte{}}, //
+ "wasm_export_run": &wasmFuncType{Params: []byte{I32, I32}}, // argc, argv
+ "wasm_export_resume": &wasmFuncType{Params: []byte{}}, //
+ "wasm_export_getsp": &wasmFuncType{Results: []byte{I32}}, // sp
+ "wasm_pc_f_loop": &wasmFuncType{Params: []byte{}}, //
"runtime.wasmMove": &wasmFuncType{Params: []byte{I32, I32, I32}}, // dst, src, len
"runtime.wasmZero": &wasmFuncType{Params: []byte{I32, I32}}, // ptr, len
"runtime.wasmDiv": &wasmFuncType{Params: []byte{I64, I64}, Results: []byte{I64}}, // x, y -> x/y
@@ -162,9 +166,6 @@ func asmb(ctxt *ld.Link) {
fns[i] = &wasmFunc{Name: name, Type: typ, Code: wfn.Bytes()}
}
- // look up program entry point
- rt0 := uint32(len(hostImports)) + uint32(ctxt.Syms.ROLookup("_rt0_wasm_js", 0).Value>>16) - funcValueOffset
-
ctxt.Out.Write([]byte{0x00, 0x61, 0x73, 0x6d}) // magic
ctxt.Out.Write([]byte{0x01, 0x00, 0x00, 0x00}) // version
@@ -180,7 +181,7 @@ func asmb(ctxt *ld.Link) {
writeTableSec(ctxt, fns)
writeMemorySec(ctxt)
writeGlobalSec(ctxt)
- writeExportSec(ctxt, rt0)
+ writeExportSec(ctxt, len(hostImports))
writeElementSec(ctxt, uint64(len(hostImports)), uint64(len(fns)))
writeCodeSec(ctxt, fns)
writeDataSec(ctxt)
@@ -326,7 +327,7 @@ func writeGlobalSec(ctxt *ld.Link) {
I64, // 6: RET1
I64, // 7: RET2
I64, // 8: RET3
- I32, // 9: RUN
+ I32, // 9: PAUSE
}
writeUleb128(ctxt.Out, uint64(len(globalRegs))) // number of globals
@@ -348,15 +349,18 @@ func writeGlobalSec(ctxt *ld.Link) {
// writeExportSec writes the section that declares exports.
// Exports can be accessed by the WebAssembly host, usually JavaScript.
-// Currently _rt0_wasm_js (program entry point) and the linear memory get exported.
-func writeExportSec(ctxt *ld.Link, rt0 uint32) {
+// The wasm_export_* functions and the linear memory get exported.
+func writeExportSec(ctxt *ld.Link, lenHostImports int) {
sizeOffset := writeSecHeader(ctxt, sectionExport)
- writeUleb128(ctxt.Out, 2) // number of exports
+ writeUleb128(ctxt.Out, 4) // number of exports
- writeName(ctxt.Out, "run") // inst.exports.run in wasm_exec.js
- ctxt.Out.WriteByte(0x00) // func export
- writeUleb128(ctxt.Out, uint64(rt0)) // funcidx
+ for _, name := range []string{"run", "resume", "getsp"} {
+ idx := uint32(lenHostImports) + uint32(ctxt.Syms.ROLookup("wasm_export_"+name, 0).Value>>16) - funcValueOffset
+ writeName(ctxt.Out, name) // inst.exports.run/resume/getsp in wasm_exec.js
+ ctxt.Out.WriteByte(0x00) // func export
+ writeUleb128(ctxt.Out, uint64(idx)) // funcidx
+ }
writeName(ctxt.Out, "mem") // inst.exports.mem in wasm_exec.js
ctxt.Out.WriteByte(0x02) // mem export
diff --git a/src/cmd/trace/annotations.go b/src/cmd/trace/annotations.go
index 9905456b46..a4933b51bf 100644
--- a/src/cmd/trace/annotations.go
+++ b/src/cmd/trace/annotations.go
@@ -508,7 +508,7 @@ func (task *taskDesc) overlappingGCDuration(evs []*trace.Event) (overlapping tim
return overlapping
}
-// overlappingInstant returns true if the instantaneous event, ev, occurred during
+// overlappingInstant reports whether the instantaneous event, ev, occurred during
// any of the task's region if ev is a goroutine-local event, or overlaps with the
// task's lifetime if ev is a global event.
func (task *taskDesc) overlappingInstant(ev *trace.Event) bool {
diff --git a/src/cmd/trace/main.go b/src/cmd/trace/main.go
index a33d2f4679..2f71a3d4bd 100644
--- a/src/cmd/trace/main.go
+++ b/src/cmd/trace/main.go
@@ -189,7 +189,7 @@ var templMain = template.Must(template.New("").Parse(`
{{if $}}
{{range $e := $}}
- View trace ({{$e.Name}})
+ View trace ({{$e.Name}})
{{end}}
{{else}}
@@ -202,6 +202,7 @@ var templMain = template.Must(template.New("").Parse(`
Scheduler latency profile (⬇)
User-defined tasks
User-defined regions
+Minimum mutator utilization