[dev.boringcrypto] all: merge master into dev.boringcrypto

Change-Id: I81b64fe503bf07b4d7bd823286b83e663b5c0f76
This commit is contained in:
Filippo Valsorda 2018-11-14 15:30:58 -05:00
commit 0007017f96
487 changed files with 30207 additions and 4496 deletions

View file

@ -740,6 +740,7 @@ The ARM64 port is in an experimental state.
<p> <p>
<code>R18</code> is the "platform register", reserved on the Apple platform. <code>R18</code> is the "platform register", reserved on the Apple platform.
To prevent accidental misuse, the register is named <code>R18_PLATFORM</code>.
<code>R27</code> and <code>R28</code> are reserved by the compiler and linker. <code>R27</code> and <code>R28</code> are reserved by the compiler and linker.
<code>R29</code> is the frame pointer. <code>R29</code> is the frame pointer.
<code>R30</code> is the link register. <code>R30</code> is the link register.

View file

@ -92,6 +92,7 @@ func Test25143(t *testing.T) { test25143(t) }
func Test23356(t *testing.T) { test23356(t) } func Test23356(t *testing.T) { test23356(t) }
func Test26066(t *testing.T) { test26066(t) } func Test26066(t *testing.T) { test26066(t) }
func Test26213(t *testing.T) { test26213(t) } func Test26213(t *testing.T) { test26213(t) }
func Test27660(t *testing.T) { test27660(t) }
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) } func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
func BenchmarkGoString(b *testing.B) { benchGoString(b) } func BenchmarkGoString(b *testing.B) { benchGoString(b) }

View file

@ -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 <unistd.h>
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)
}
}

View file

@ -50,6 +50,9 @@ go src=..
google google
pprof pprof
internal internal
binutils
testdata
+
driver driver
testdata testdata
+ +

View file

@ -79,6 +79,10 @@
console.warn("exit code:", code); console.warn("exit code:", code);
} }
}; };
this._exitPromise = new Promise((resolve) => {
this._resolveExitPromise = resolve;
});
this._pendingCallback = null;
this._callbackTimeouts = new Map(); this._callbackTimeouts = new Map();
this._nextCallbackTimeoutID = 1; this._nextCallbackTimeoutID = 1;
@ -194,6 +198,11 @@
const timeOrigin = Date.now() - performance.now(); const timeOrigin = Date.now() - performance.now();
this.importObject = { this.importObject = {
go: { 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) // func wasmExit(code int32)
"runtime.wasmExit": (sp) => { "runtime.wasmExit": (sp) => {
const code = mem().getInt32(sp + 8, true); const code = mem().getInt32(sp + 8, true);
@ -229,7 +238,7 @@
const id = this._nextCallbackTimeoutID; const id = this._nextCallbackTimeoutID;
this._nextCallbackTimeoutID++; this._nextCallbackTimeoutID++;
this._callbackTimeouts.set(id, setTimeout( this._callbackTimeouts.set(id, setTimeout(
() => { this._resolveCallbackPromise(); }, () => { this._resume(); },
getInt64(sp + 8) + 1, // setTimeout has been seen to fire up to 1 millisecond early getInt64(sp + 8) + 1, // setTimeout has been seen to fire up to 1 millisecond early
)); ));
mem().setInt32(sp + 16, id, true); mem().setInt32(sp + 16, id, true);
@ -254,7 +263,9 @@
// func valueGet(v ref, p string) ref // func valueGet(v ref, p string) ref
"syscall/js.valueGet": (sp) => { "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) // func valueSet(v ref, p string, x ref)
@ -278,7 +289,9 @@
const v = loadValue(sp + 8); const v = loadValue(sp + 8);
const m = Reflect.get(v, loadString(sp + 16)); const m = Reflect.get(v, loadString(sp + 16));
const args = loadSliceOfValues(sp + 32); 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); mem().setUint8(sp + 64, 1);
} catch (err) { } catch (err) {
storeValue(sp + 56, err); storeValue(sp + 56, err);
@ -291,7 +304,9 @@
try { try {
const v = loadValue(sp + 8); const v = loadValue(sp + 8);
const args = loadSliceOfValues(sp + 16); 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); mem().setUint8(sp + 48, 1);
} catch (err) { } catch (err) {
storeValue(sp + 40, err); storeValue(sp + 40, err);
@ -304,7 +319,9 @@
try { try {
const v = loadValue(sp + 8); const v = loadValue(sp + 8);
const args = loadSliceOfValues(sp + 16); 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); mem().setUint8(sp + 48, 1);
} catch (err) { } catch (err) {
storeValue(sp + 40, err); storeValue(sp + 40, err);
@ -355,7 +372,6 @@
this, this,
]; ];
this._refs = new Map(); this._refs = new Map();
this._callbackShutdown = false;
this.exited = false; this.exited = false;
const mem = new DataView(this._inst.exports.mem.buffer) const mem = new DataView(this._inst.exports.mem.buffer)
@ -390,42 +406,30 @@
offset += 8; offset += 8;
}); });
while (true) { this._inst.exports.run(argc, argv);
const callbackPromise = new Promise((resolve) => { if (this.exited) {
this._resolveCallbackPromise = () => { this._resolveExitPromise();
if (this.exited) { }
throw new Error("bad callback: Go program has already exited"); await this._exitPromise;
} }
setTimeout(resolve, 0); // make sure it is asynchronous
}; _resume() {
}); if (this.exited) {
this._inst.exports.run(argc, argv); throw new Error("bad callback: Go program has already exited");
if (this.exited) { }
break; this._inst.exports.resume();
} if (this.exited) {
await callbackPromise; this._resolveExitPromise();
} }
} }
static _makeCallbackHelper(id, pendingCallbacks, go) { _makeCallbackHelper(id) {
const go = this;
return function () { return function () {
pendingCallbacks.push({ id: id, args: arguments }); const cb = { id: id, this: this, args: arguments };
go._resolveCallbackPromise(); go._pendingCallback = cb;
}; go._resume();
} return cb.result;
static _makeEventCallbackHelper(preventDefault, stopPropagation, stopImmediatePropagation, fn) {
return function (event) {
if (preventDefault) {
event.preventDefault();
}
if (stopPropagation) {
event.stopPropagation();
}
if (stopImmediatePropagation) {
event.stopImmediatePropagation();
}
fn(event);
}; };
} }
} }
@ -444,8 +448,8 @@
process.on("exit", (code) => { // Node.js exits if no callback is pending process.on("exit", (code) => { // Node.js exits if no callback is pending
if (code === 0 && !go.exited) { if (code === 0 && !go.exited) {
// deadlock, make Go print error and stack traces // deadlock, make Go print error and stack traces
go._callbackShutdown = true; go._pendingCallback = { id: 0 };
go._inst.exports.run(); go._resume();
} }
}); });
return go.run(result.instance); return go.run(result.instance);

View file

@ -550,7 +550,7 @@ func TestWriter(t *testing.T) {
t.Errorf("%s: %d bytes written", context, len(written)) t.Errorf("%s: %d bytes written", context, len(written))
} }
for l := 0; l < len(written); l++ { for l := 0; l < len(written); l++ {
if written[i] != data[i] { if written[l] != data[l] {
t.Errorf("wrong bytes written") t.Errorf("wrong bytes written")
t.Errorf("want=%q", data[0:len(written)]) t.Errorf("want=%q", data[0:len(written)])
t.Errorf("have=%q", written) t.Errorf("have=%q", written)

View file

@ -12,6 +12,13 @@ import (
"unicode/utf8" "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 { func equalPortable(a, b []byte) bool {
if len(a) != len(b) { if len(a) != len(b) {
return false return false
@ -24,6 +31,13 @@ func equalPortable(a, b []byte) bool {
return true 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), // 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. // up to a maximum of n byte slices. Invalid UTF-8 sequences are chopped into individual bytes.
func explode(s []byte, n int) [][]byte { func explode(s []byte, n int) [][]byte {
@ -83,6 +97,11 @@ func ContainsRune(b []byte, r rune) bool {
return IndexRune(b, r) >= 0 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 { func indexBytePortable(s []byte, c byte) int {
for i, b := range s { for i, b := range s {
if b == c { if b == c {

View file

@ -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

View file

@ -61,6 +61,7 @@ func main() {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
defer f.Close()
tab, err := f.PCLineTable() tab, err := f.PCLineTable()
if err != nil { if err != nil {

View file

@ -258,6 +258,9 @@ func archArm64() *Arch {
for i := arm64.REG_R0; i <= arm64.REG_R31; i++ { for i := arm64.REG_R0; i <= arm64.REG_R31; i++ {
register[obj.Rconv(i)] = int16(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++ { for i := arm64.REG_F0; i <= arm64.REG_F31; i++ {
register[obj.Rconv(i)] = int16(i) register[obj.Rconv(i)] = int16(i)
} }

View file

@ -607,6 +607,7 @@ var arm64OperandTests = []operandTest{
{"R0", "R0"}, {"R0", "R0"},
{"R10", "R10"}, {"R10", "R10"},
{"R11", "R11"}, {"R11", "R11"},
{"R18_PLATFORM", "R18"},
{"$4503601774854144.0", "$(4503601774854144.0)"}, {"$4503601774854144.0", "$(4503601774854144.0)"},
{"$runtime·badsystemstack(SB)", "$runtime.badsystemstack(SB)"}, {"$runtime·badsystemstack(SB)", "$runtime.badsystemstack(SB)"},
{"ZR", "ZR"}, {"ZR", "ZR"},

View file

@ -47,8 +47,8 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
ADD R2.SXTX<<1, RSP, RSP // ffe7228b ADD R2.SXTX<<1, RSP, RSP // ffe7228b
ADD ZR.SXTX<<1, R2, R3 // 43e43f8b ADD ZR.SXTX<<1, R2, R3 // 43e43f8b
ADDW R2.SXTW, R10, R12 // 4cc1220b ADDW R2.SXTW, R10, R12 // 4cc1220b
ADD R18.UXTX, R14, R17 // d161328b ADD R19.UXTX, R14, R17 // d161338b
ADDSW R18.UXTW, R14, R17 // d141322b ADDSW R19.UXTW, R14, R17 // d141332b
ADDS R12.SXTX, R3, R1 // 61e02cab ADDS R12.SXTX, R3, R1 // 61e02cab
SUB R19.UXTH<<4, R2, R21 // 553033cb SUB R19.UXTH<<4, R2, R21 // 553033cb
SUBW R1.UXTX<<1, R3, R2 // 6264214b SUBW R1.UXTX<<1, R3, R2 // 6264214b
@ -144,7 +144,7 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
MOVD (R2)(R6.SXTW), R4 // 44c866f8 MOVD (R2)(R6.SXTW), R4 // 44c866f8
MOVD (R3)(R6), R5 // MOVD (R3)(R6*1), R5 // 656866f8 MOVD (R3)(R6), R5 // MOVD (R3)(R6*1), R5 // 656866f8
MOVD (R2)(R6), R4 // MOVD (R2)(R6*1), R4 // 446866f8 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 (R2)(R6<<3), R4 // 447866f8
MOVD (R3)(R7.SXTX<<3), R8 // 68f867f8 MOVD (R3)(R7.SXTX<<3), R8 // 68f867f8
MOVWU (R5)(R4.UXTW), R10 // aa4864b8 MOVWU (R5)(R4.UXTW), R10 // aa4864b8
@ -154,7 +154,7 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
MOVHU (R1)(R2<<1), R5 // 25786278 MOVHU (R1)(R2<<1), R5 // 25786278
MOVB (R9)(R3.UXTW), R6 // 2649a338 MOVB (R9)(R3.UXTW), R6 // 2649a338
MOVB (R10)(R6), R15 // MOVB (R10)(R6*1), R15 // 4f69a638 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 MOVH (R8)(R4<<1), R10 // 0a79a478
MOVW (R9)(R8.SXTW<<2), R19 // 33d9a8b8 MOVW (R9)(R8.SXTW<<2), R19 // 33d9a8b8
MOVW (R1)(R4.SXTX), R11 // 2be8a4b8 MOVW (R1)(R4.SXTX), R11 // 2be8a4b8
@ -195,6 +195,11 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
CMPW $27745, R2 // 3b8c8d525f001b6b CMPW $27745, R2 // 3b8c8d525f001b6b
CMNW $0x3fffffc0, R2 // CMNW $1073741760, R2 // fb5f1a325f001b2b CMNW $0x3fffffc0, R2 // CMNW $1073741760, R2 // fb5f1a325f001b2b
CMPW $0xffff0, R1 // CMPW $1048560, R1 // fb3f1c323f001b6b 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 ADD $0x3fffffffc000, R5 // ADD $70368744161280, R5 // fb7f72b2a5001b8b
// LTYPE1 imsr ',' spreg ',' // LTYPE1 imsr ',' spreg ','
// { // {
@ -222,6 +227,13 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
EOR $(1<<63), R1 // EOR $-9223372036854775808, R1 // 210041d2 EOR $(1<<63), R1 // EOR $-9223372036854775808, R1 // 210041d2
EOR $(1<<63-1), R1 // EOR $9223372036854775807, R1 // 21f840d2 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 AND $0x22220000, R3, R4 // AND $572653568, R3, R4 // 5b44a4d264001b8a
ORR $0x22220000, R3, R4 // ORR $572653568, R3, R4 // 5b44a4d264001baa ORR $0x22220000, R3, R4 // ORR $572653568, R3, R4 // 5b44a4d264001baa
EOR $0x22220000, R3, R4 // EOR $572653568, R3, R4 // 5b44a4d264001bca 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 EOR $0xe03fffffffffffff, R20, R22 // EOR $-2287828610704211969, R20, R22 // 96e243d2
TSTW $0x600000006, R1 // TSTW $25769803782, R1 // 3f041f72 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 ANDS $0xffff, R2 // ANDS $65535, R2 // 423c40f2
AND $0x7fffffff, R3 // AND $2147483647, R3 // 63784092 AND $0x7fffffff, R3 // AND $2147483647, R3 // 63784092
ANDS $0x0ffffffff80000000, R2 // ANDS $-2147483648, R2 // 428061f2 ANDS $0x0ffffffff80000000, R2 // ANDS $-2147483648, R2 // 428061f2
AND $0xfffff, R2 // AND $1048575, R2 // 424c4092 AND $0xfffff, R2 // AND $1048575, R2 // 424c4092
ANDW $0xf00fffff, R1 // ANDW $4027580415, R1 // 215c0412 ANDW $0xf00fffff, R1 // ANDW $4027580415, R1 // 215c0412
ANDSW $0xff00ffff, R1 // ANDSW $4278255615, R1 // 215c0872 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 TSTW $0xff00ff, R1 // TSTW $16711935, R1 // 3f9c0072
AND $8, R0, RSP // 1f007d92 AND $8, R0, RSP // 1f007d92
@ -249,13 +270,20 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
EON $8, R0, RSP // 1ff87cd2 EON $8, R0, RSP // 1ff87cd2
MOVD $0x3fffffffc000, R0 // MOVD $70368744161280, R0 // e07f72b2 MOVD $0x3fffffffc000, R0 // MOVD $70368744161280, R0 // e07f72b2
MOVW $1000000, R4 // 04488852e401a072
MOVW $0xaaaa0000, R1 // MOVW $2863267840, R1 // 4155b552 MOVW $0xaaaa0000, R1 // MOVW $2863267840, R1 // 4155b552
MOVW $0xaaaaffff, R1 // MOVW $2863333375, R1 // a1aaaa12 MOVW $0xaaaaffff, R1 // MOVW $2863333375, R1 // a1aaaa12
MOVW $0xaaaa, R1 // MOVW $43690, R1 // 41559552 MOVW $0xaaaa, R1 // MOVW $43690, R1 // 41559552
MOVW $0xffffaaaa, R1 // MOVW $4294945450, R1 // a1aa8a12 MOVW $0xffffaaaa, R1 // MOVW $4294945450, R1 // a1aa8a12
MOVW $0xffff0000, R1 // MOVW $4294901760, R1 // e1ffbf52 MOVW $0xffff0000, R1 // MOVW $4294901760, R1 // e1ffbf52
MOVD $0xffff00000000000, R1 // MOVD $1152903912420802560, R1 // e13f54b2 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 $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 $0, R1 // 010080d2
MOVD $-1, R1 // 01008092 MOVD $-1, R1 // 01008092
MOVD $0x210000, R0 // MOVD $2162688, R0 // 2004a0d2 MOVD $0x210000, R0 // MOVD $2162688, R0 // 2004a0d2

View file

@ -56,7 +56,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
BFXILW $3, R27, $23, R14 // 6e670333 BFXILW $3, R27, $23, R14 // 6e670333
BFXIL $26, R8, $16, R20 // 14a55ab3 BFXIL $26, R8, $16, R20 // 14a55ab3
BICW R7@>15, R5, R16 // b03ce70a BICW R7@>15, R5, R16 // b03ce70a
BIC R12@>13, R12, R18 // 9235ec8a BIC R12@>13, R12, R19 // 9335ec8a
BICSW R25->20, R3, R20 // 7450b96a BICSW R25->20, R3, R20 // 7450b96a
BICS R19->12, R1, R23 // 3730b3ea BICS R19->12, R1, R23 // 3730b3ea
BICS R19, R1, R23 // 370033ea BICS R19, R1, R23 // 370033ea
@ -76,7 +76,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
CCMN LE, R30, R12, $6 // c6d34cba CCMN LE, R30, R12, $6 // c6d34cba
CCMPW VS, R29, $15, $7 // a76b4f7a CCMPW VS, R29, $15, $7 // a76b4f7a
CCMP LE, R7, $19, $3 // e3d853fa CCMP LE, R7, $19, $3 // e3d853fa
CCMPW HS, R18, R6, $0 // 4022467a CCMPW HS, R19, R6, $0 // 6022467a
CCMP LT, R30, R6, $7 // c7b346fa CCMP LT, R30, R6, $7 // c7b346fa
CCMN MI, ZR, R1, $4 // e44341ba CCMN MI, ZR, R1, $4 // e44341ba
CSINCW HS, ZR, R27, R14 // ee279b1a CSINCW HS, ZR, R27, R14 // ee279b1a
@ -118,7 +118,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
CRC32H R3, R21, R27 // bb46c31a CRC32H R3, R21, R27 // bb46c31a
CRC32W R22, R30, R9 // c94bd61a CRC32W R22, R30, R9 // c94bd61a
CRC32X R20, R4, R15 // 8f4cd49a CRC32X R20, R4, R15 // 8f4cd49a
CRC32CB R18, R27, R22 // 7653d21a CRC32CB R19, R27, R22 // 7653d31a
CRC32CH R21, R0, R20 // 1454d51a CRC32CH R21, R0, R20 // 1454d51a
CRC32CW R9, R3, R21 // 7558c91a CRC32CW R9, R3, R21 // 7558c91a
CRC32CX R11, R0, R24 // 185ccb9a CRC32CX R11, R0, R24 // 185ccb9a
@ -133,7 +133,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
CSINVW AL, R23, R21, R5 // e5e2955a CSINVW AL, R23, R21, R5 // e5e2955a
CSINV LO, R2, R11, R14 // 4e308bda CSINV LO, R2, R11, R14 // 4e308bda
CSNEGW HS, R16, R29, R10 // 0a269d5a CSNEGW HS, R16, R29, R10 // 0a269d5a
CSNEG NE, R21, R18, R11 // ab1692da CSNEG NE, R21, R19, R11 // ab1693da
//TODO DC //TODO DC
DCPS1 $11378 // 418ea5d4 DCPS1 $11378 // 418ea5d4
DCPS2 $10699 // 6239a5d4 DCPS2 $10699 // 6239a5d4
@ -185,23 +185,23 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
MOVBU.P 42(R2), R12 // 4ca44238 MOVBU.P 42(R2), R12 // 4ca44238
MOVBU.W -27(R2), R14 // 4e5c5e38 MOVBU.W -27(R2), R14 // 4e5c5e38
MOVBU 2916(R24), R3 // 03936d39 MOVBU 2916(R24), R3 // 03936d39
MOVBU (R18)(R14<<0), R23 // 577a6e38 MOVBU (R19)(R14<<0), R23 // 777a6e38
MOVBU (R2)(R8.SXTX), R19 // 53e86838 MOVBU (R2)(R8.SXTX), R19 // 53e86838
MOVBU (R27)(R23), R14 // MOVBU (R27)(R23*1), R14 // 6e6b7738 MOVBU (R27)(R23), R14 // MOVBU (R27)(R23*1), R14 // 6e6b7738
MOVHU.P 107(R14), R13 // cdb54678 MOVHU.P 107(R14), R13 // cdb54678
MOVHU.W 192(R3), R2 // 620c4c78 MOVHU.W 192(R3), R2 // 620c4c78
MOVHU 6844(R4), R18 // 92787579 MOVHU 6844(R4), R19 // 93787579
MOVHU (R5)(R25.SXTW), R15 // afc87978 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 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 MOVB.W -178(R16), R24 // 18ee9438
//TODO MOVBW 430(R8), R22 // 16b9c639 //TODO MOVBW 430(R8), R22 // 16b9c639
MOVB 997(R9), R23 // 37958f39 MOVB 997(R9), R23 // 37958f39
//TODO MOVBW (R2<<1)(R21), R15 // af7ae238 //TODO MOVBW (R2<<1)(R21), R15 // af7ae238
//TODO MOVBW (R26)(R0), R21 // 1568fa38 //TODO MOVBW (R26)(R0), R21 // 1568fa38
MOVB (R5)(R15), R16 // MOVB (R5)(R15*1), R16 // b068af38 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 MOVB (R29)(R30), R14 // MOVB (R29)(R30*1), R14 // ae6bbe38
//TODO MOVHW.P 218(R22), R25 // d9a6cd78 //TODO MOVHW.P 218(R22), R25 // d9a6cd78
MOVH.P 179(R23), R5 // e5368b78 MOVH.P 179(R23), R5 // e5368b78
@ -212,7 +212,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
//TODO MOVHW (R22)(R24.SXTX), R4 // c4eaf878 //TODO MOVHW (R22)(R24.SXTX), R4 // c4eaf878
MOVH (R26)(R30.UXTW<<1), ZR // 5f5bbe78 MOVH (R26)(R30.UXTW<<1), ZR // 5f5bbe78
MOVW.P -58(R16), R2 // 02669cb8 MOVW.P -58(R16), R2 // 02669cb8
MOVW.W -216(R18), R8 // 488e92b8 MOVW.W -216(R19), R8 // 688e92b8
MOVW 4764(R23), R10 // ea9e92b9 MOVW 4764(R23), R10 // ea9e92b9
MOVW (R8)(R3.UXTW), R17 // 1149a3b8 MOVW (R8)(R3.UXTW), R17 // 1149a3b8
//TODO LDTR -0x1e(R3), R4 // 64285eb8 //TODO LDTR -0x1e(R3), R4 // 64285eb8
@ -297,7 +297,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
RET // c0035fd6 RET // c0035fd6
REVW R8, R10 // 0a09c05a REVW R8, R10 // 0a09c05a
REV R1, R2 // 220cc0da REV R1, R2 // 220cc0da
REV16W R21, R18 // b206c05a REV16W R21, R19 // b306c05a
REV16 R25, R4 // 2407c0da REV16 R25, R4 // 2407c0da
REV32 R27, R21 // 750bc0da REV32 R27, R21 // 750bc0da
EXTRW $27, R4, R25, R19 // 336f8413 EXTRW $27, R4, R25, R19 // 336f8413
@ -308,7 +308,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
ROR R0, R23, R2 // e22ec09a ROR R0, R23, R2 // e22ec09a
SBCW R4, R8, R24 // 1801045a SBCW R4, R8, R24 // 1801045a
SBC R25, R10, R26 // 5a0119da SBC R25, R10, R26 // 5a0119da
SBCSW R27, R18, R18 // 52021b7a SBCSW R27, R19, R19 // 73021b7a
SBCS R5, R9, R5 // 250105fa SBCS R5, R9, R5 // 250105fa
SBFIZW $9, R10, $18, R22 // 56451713 SBFIZW $9, R10, $18, R22 // 56451713
SBFIZ $6, R11, $15, R20 // 74397a93 SBFIZ $6, R11, $15, R20 // 74397a93
@ -337,7 +337,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
//TODO STNPW 44(R1), R3, R10 // 2a8c0528 //TODO STNPW 44(R1), R3, R10 // 2a8c0528
//TODO STNP 0x108(R3), ZR, R7 // 67fc10a8 //TODO STNP 0x108(R3), ZR, R7 // 67fc10a8
LDP.P -384(R3), (R22, R26) // 7668e8a8 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.P (R22, R27), 352(R0) // 166c96a8
STP.W (R17, R11), 96(R8) // 112d86a9 STP.W (R17, R11), 96(R8) // 112d86a9
MOVW.P R20, -28(R1) // 34441eb8 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 MOVB R2, (R29)(R26) // MOVB R2, (R29)(R26*1) // a26b3a38
MOVH R11, -80(R23) // eb021b78 MOVH R11, -80(R23) // eb021b78
MOVH R11, (R27)(R14.SXTW<<1) // 6bdb2e78 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 MOVB R1, (R6)(R4) // MOVB R1, (R6)(R4*1) // c1682438
MOVH R3, (R11)(R13<<1) // 63792d78 MOVH R3, (R11)(R13<<1) // 63792d78
//TODO STTR 55(R4), R29 // 9d7803b8 //TODO STTR 55(R4), R29 // 9d7803b8
//TODO STTR 124(R5), R25 // b9c807f8 //TODO STTR 124(R5), R25 // b9c807f8
//TODO STTRB -28(R23), R16 // f04a1e38 //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), (R3), R10 // 61082ac8
STXP (R1, R2), (RSP), R10 // e10b2ac8 STXP (R1, R2), (RSP), R10 // e10b2ac8
STXPW (R1, R2), (R3), R10 // 61082a88 STXPW (R1, R2), (R3), R10 // 61082a88
STXPW (R1, R2), (RSP), R10 // e10b2a88 STXPW (R1, R2), (RSP), R10 // e10b2a88
STXRW R2, (R19), R18 // 627e1288 STXRW R2, (R19), R20 // 627e1488
STXR R15, (R21), R13 // af7e0dc8 STXR R15, (R21), R13 // af7e0dc8
STXRB R7, (R9), R24 // 277d1808 STXRB R7, (R9), R24 // 277d1808
STXRH R12, (R3), R8 // 6c7c0848 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 R5.SXTW<<2, R1, R26 // 3ac825cb
SUB $(1923<<12), R4, R27 // SUB $7876608, R4, R27 // 9b0c5ed1 SUB $(1923<<12), R4, R27 // SUB $7876608, R4, R27 // 9b0c5ed1
SUBW $(1923<<12), R4, R27 // SUBW $7876608, R4, R27 // 9b0c5e51 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 UBFXW $3, R7, $20, R15 // ef580353
UBFX $33, R17, $25, R5 // 25e661d3 UBFX $33, R17, $25, R5 // 25e661d3
UDIVW R8, R21, R15 // af0ac81a UDIVW R8, R21, R15 // af0ac81a
UDIV R2, R18, R21 // 550ac29a UDIV R2, R19, R21 // 750ac29a
UMADDL R0, R20, R17, R17 // 3152a09b UMADDL R0, R20, R17, R17 // 3152a09b
UMSUBL R22, R4, R3, R7 // 6790b69b UMSUBL R22, R4, R3, R7 // 6790b69b
UMNEGL R3, R18, R1 // 41fea39b UMNEGL R3, R19, R1 // 61fea39b
UMULH R24, R20, R24 // 987ed89b UMULH R24, R20, R24 // 987ed89b
UMULL R18, R22, R19 // d37eb29b UMULL R19, R22, R19 // d37eb39b
UXTBW R2, R6 // 461c0053 UXTBW R2, R6 // 461c0053
UXTHW R7, R20 // f43c0053 UXTHW R7, R20 // f43c0053
VCNT V0.B8, V0.B8 // 0058200e VCNT V0.B8, V0.B8 // 0058200e
@ -471,7 +471,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
//TODO FCVTAS F27, R7 // 6703241e //TODO FCVTAS F27, R7 // 6703241e
//TODO FCVTAS F19, R26 // 7a02249e //TODO FCVTAS F19, R26 // 7a02249e
//TODO FCVTAS F4, R0 // 8000641e //TODO FCVTAS F4, R0 // 8000641e
//TODO FCVTAS F3, R18 // 7200649e //TODO FCVTAS F3, R19 // 7300649e
//TODO FCVTAU F18, F28 // 5cca217e //TODO FCVTAU F18, F28 // 5cca217e
//TODO VFCVTAU V30.S4, V27.S4 // dbcb216e //TODO VFCVTAU V30.S4, V27.S4 // dbcb216e
//TODO FCVTAU F0, R2 // 0200251e //TODO FCVTAU F0, R2 // 0200251e
@ -482,16 +482,16 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
//TODO VFCVTL2 V15.H8, V25.S4 // f979214e //TODO VFCVTL2 V15.H8, V25.S4 // f979214e
//TODO FCVTMS F21, F28 // bcba215e //TODO FCVTMS F21, F28 // bcba215e
//TODO VFCVTMS V5.D2, V2.D2 // a2b8614e //TODO VFCVTMS V5.D2, V2.D2 // a2b8614e
//TODO FCVTMS F31, R18 // f203301e //TODO FCVTMS F31, R19 // f303301e
//TODO FCVTMS F23, R16 // f002309e //TODO FCVTMS F23, R16 // f002309e
//TODO FCVTMS F16, R22 // 1602701e //TODO FCVTMS F16, R22 // 1602701e
//TODO FCVTMS F14, R19 // d301709e //TODO FCVTMS F14, R19 // d301709e
//TODO FCVTMU F14, F8 // c8b9217e //TODO FCVTMU F14, F8 // c8b9217e
//TODO VFCVTMU V7.D2, V1.D2 // e1b8616e //TODO VFCVTMU V7.D2, V1.D2 // e1b8616e
//TODO FCVTMU F2, R0 // 4000311e //TODO FCVTMU F2, R0 // 4000311e
//TODO FCVTMU F23, R18 // f202319e //TODO FCVTMU F23, R19 // f302319e
//TODO FCVTMU F16, R17 // 1102711e //TODO FCVTMU F16, R17 // 1102711e
//TODO FCVTMU F12, R18 // 9201719e //TODO FCVTMU F12, R19 // 9301719e
//TODO VFCVTN V23.D2, V26.S2 // fa6a610e //TODO VFCVTN V23.D2, V26.S2 // fa6a610e
//TODO VFCVTN2 V2.D2, V31.S4 // 5f68614e //TODO VFCVTN2 V2.D2, V31.S4 // 5f68614e
//TODO FCVTNS F3, F27 // 7ba8215e //TODO FCVTNS F3, F27 // 7ba8215e
@ -540,7 +540,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
//TODO FCVTZU $14, F24, R20 // 14cb191e //TODO FCVTZU $14, F24, R20 // 14cb191e
//TODO FCVTZU $6, F25, R17 // 31eb199e //TODO FCVTZU $6, F25, R17 // 31eb199e
//TODO FCVTZU $5, F17, R10 // 2aee591e //TODO FCVTZU $5, F17, R10 // 2aee591e
//TODO FCVTZU $6, F7, R18 // f2e8599e //TODO FCVTZU $6, F7, R19 // f3e8599e
FCVTZUSW F2, R9 // 4900391e FCVTZUSW F2, R9 // 4900391e
FCVTZUS F12, R29 // 9d01399e FCVTZUS F12, R29 // 9d01399e
FCVTZUDW F27, R22 // 7603791e 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 (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 (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.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 (R29), V0.H[1] // a04b400d
VLD1 (R27), V2.S[0] // 6283400d VLD1 (R27), V2.S[0] // 6283400d
VLD1 (R21), V5.D[1] // a586404d 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 (R3)(R14), V16.B[11] // VLD1.P (R3)(R14*1), V16.B[11] // 700cce4d
VLD1.P 2(R1), V28.H[2] // 3c50df0d VLD1.P 2(R1), V28.H[2] // 3c50df0d
VLD1.P (R13)(R20), V9.H[2] // VLD1.P (R13)(R20*1), V9.H[2] // a951d40d VLD1.P (R13)(R20), V9.H[2] // VLD1.P (R13)(R20*1), V9.H[2] // a951d40d

View file

@ -139,7 +139,7 @@ func (in *Input) Text() string {
return in.text 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 { func (in *Input) hash() bool {
// We have a '#'; it must be followed by a known word (define, include, etc.). // We have a '#'; it must be followed by a known word (define, include, etc.).
tok := in.Stack.Next() tok := in.Stack.Next()

View file

@ -827,6 +827,10 @@ The directives are:
possibly version in the dynamic library, and the optional "<library>" possibly version in the dynamic library, and the optional "<library>"
names the specific library where the symbol should be found. 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 <remote>, # or @ can be used to introduce a symbol version. In the <remote>, # or @ can be used to introduce a symbol version.
Examples: Examples:

View file

@ -246,7 +246,22 @@ func (p *Package) writeDefs() {
init := gccgoInit.String() init := gccgoInit.String()
if init != "" { 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.Fprintln(fc, "static void init(void) {")
fmt.Fprint(fc, init) fmt.Fprint(fc, init)
fmt.Fprintln(fc, "}") fmt.Fprintln(fc, "}")

View file

@ -587,6 +587,7 @@ var knownFormats = map[string]string{
"*cmd/compile/internal/types.Sym %S": "", "*cmd/compile/internal/types.Sym %S": "",
"*cmd/compile/internal/types.Sym %p": "", "*cmd/compile/internal/types.Sym %p": "",
"*cmd/compile/internal/types.Sym %v": "", "*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 %+v": "", "*cmd/compile/internal/types.Type %+v": "",
"*cmd/compile/internal/types.Type %-S": "", "*cmd/compile/internal/types.Type %-S": "",
@ -598,6 +599,7 @@ var knownFormats = map[string]string{
"*cmd/compile/internal/types.Type %v": "", "*cmd/compile/internal/types.Type %v": "",
"*cmd/internal/obj.Addr %v": "", "*cmd/internal/obj.Addr %v": "",
"*cmd/internal/obj.LSym %v": "", "*cmd/internal/obj.LSym %v": "",
"*math/big.Float %f": "",
"*math/big.Int %#x": "", "*math/big.Int %#x": "",
"*math/big.Int %s": "", "*math/big.Int %s": "",
"*math/big.Int %v": "", "*math/big.Int %v": "",
@ -658,6 +660,7 @@ var knownFormats = map[string]string{
"cmd/compile/internal/ssa.rbrank %d": "", "cmd/compile/internal/ssa.rbrank %d": "",
"cmd/compile/internal/ssa.regMask %d": "", "cmd/compile/internal/ssa.regMask %d": "",
"cmd/compile/internal/ssa.register %d": "", "cmd/compile/internal/ssa.register %d": "",
"cmd/compile/internal/syntax.Error %q": "",
"cmd/compile/internal/syntax.Expr %#v": "", "cmd/compile/internal/syntax.Expr %#v": "",
"cmd/compile/internal/syntax.Node %T": "", "cmd/compile/internal/syntax.Node %T": "",
"cmd/compile/internal/syntax.Operator %s": "", "cmd/compile/internal/syntax.Operator %s": "",
@ -705,33 +708,34 @@ var knownFormats = map[string]string{
"interface{} %v": "", "interface{} %v": "",
"map[*cmd/compile/internal/gc.Node]*cmd/compile/internal/ssa.Value %v": "", "map[*cmd/compile/internal/gc.Node]*cmd/compile/internal/ssa.Value %v": "",
"map[cmd/compile/internal/ssa.ID]uint32 %v": "", "map[cmd/compile/internal/ssa.ID]uint32 %v": "",
"reflect.Type %s": "", "math/big.Accuracy %s": "",
"rune %#U": "", "reflect.Type %s": "",
"rune %c": "", "rune %#U": "",
"string %-*s": "", "rune %c": "",
"string %-16s": "", "string %-*s": "",
"string %-6s": "", "string %-16s": "",
"string %.*s": "", "string %-6s": "",
"string %q": "", "string %.*s": "",
"string %s": "", "string %q": "",
"string %v": "", "string %s": "",
"time.Duration %d": "", "string %v": "",
"time.Duration %v": "", "time.Duration %d": "",
"uint %04x": "", "time.Duration %v": "",
"uint %5d": "", "uint %04x": "",
"uint %d": "", "uint %5d": "",
"uint %x": "", "uint %d": "",
"uint16 %d": "", "uint %x": "",
"uint16 %v": "", "uint16 %d": "",
"uint16 %x": "", "uint16 %v": "",
"uint32 %#x": "", "uint16 %x": "",
"uint32 %d": "", "uint32 %#x": "",
"uint32 %v": "", "uint32 %d": "",
"uint32 %x": "", "uint32 %v": "",
"uint64 %08x": "", "uint32 %x": "",
"uint64 %d": "", "uint64 %08x": "",
"uint64 %x": "", "uint64 %d": "",
"uint8 %d": "", "uint64 %x": "",
"uint8 %x": "", "uint8 %d": "",
"uintptr %d": "", "uint8 %x": "",
"uintptr %d": "",
} }

View file

@ -51,110 +51,105 @@ var runtimeDecls = [...]struct {
{"decoderune", funcTag, 50}, {"decoderune", funcTag, 50},
{"countrunes", funcTag, 51}, {"countrunes", funcTag, 51},
{"convI2I", funcTag, 52}, {"convI2I", funcTag, 52},
{"convT2E", funcTag, 53}, {"convT16", funcTag, 54},
{"convT2E16", funcTag, 52}, {"convT32", funcTag, 54},
{"convT2E32", funcTag, 52}, {"convT64", funcTag, 54},
{"convT2E64", funcTag, 52}, {"convTstring", funcTag, 54},
{"convT2Estring", funcTag, 52}, {"convTslice", funcTag, 54},
{"convT2Eslice", funcTag, 52}, {"convT2E", funcTag, 55},
{"convT2Enoptr", funcTag, 53}, {"convT2Enoptr", funcTag, 55},
{"convT2I", funcTag, 53}, {"convT2I", funcTag, 55},
{"convT2I16", funcTag, 52}, {"convT2Inoptr", funcTag, 55},
{"convT2I32", funcTag, 52},
{"convT2I64", funcTag, 52},
{"convT2Istring", funcTag, 52},
{"convT2Islice", funcTag, 52},
{"convT2Inoptr", funcTag, 53},
{"assertE2I", funcTag, 52}, {"assertE2I", funcTag, 52},
{"assertE2I2", funcTag, 54}, {"assertE2I2", funcTag, 56},
{"assertI2I", funcTag, 52}, {"assertI2I", funcTag, 52},
{"assertI2I2", funcTag, 54}, {"assertI2I2", funcTag, 56},
{"panicdottypeE", funcTag, 55}, {"panicdottypeE", funcTag, 57},
{"panicdottypeI", funcTag, 55}, {"panicdottypeI", funcTag, 57},
{"panicnildottype", funcTag, 56}, {"panicnildottype", funcTag, 58},
{"ifaceeq", funcTag, 59}, {"ifaceeq", funcTag, 60},
{"efaceeq", funcTag, 59}, {"efaceeq", funcTag, 60},
{"fastrand", funcTag, 61}, {"fastrand", funcTag, 62},
{"makemap64", funcTag, 63}, {"makemap64", funcTag, 64},
{"makemap", funcTag, 64}, {"makemap", funcTag, 65},
{"makemap_small", funcTag, 65}, {"makemap_small", funcTag, 66},
{"mapaccess1", funcTag, 66}, {"mapaccess1", funcTag, 67},
{"mapaccess1_fast32", funcTag, 67}, {"mapaccess1_fast32", funcTag, 68},
{"mapaccess1_fast64", funcTag, 67}, {"mapaccess1_fast64", funcTag, 68},
{"mapaccess1_faststr", funcTag, 67}, {"mapaccess1_faststr", funcTag, 68},
{"mapaccess1_fat", funcTag, 68}, {"mapaccess1_fat", funcTag, 69},
{"mapaccess2", funcTag, 69}, {"mapaccess2", funcTag, 70},
{"mapaccess2_fast32", funcTag, 70}, {"mapaccess2_fast32", funcTag, 71},
{"mapaccess2_fast64", funcTag, 70}, {"mapaccess2_fast64", funcTag, 71},
{"mapaccess2_faststr", funcTag, 70}, {"mapaccess2_faststr", funcTag, 71},
{"mapaccess2_fat", funcTag, 71}, {"mapaccess2_fat", funcTag, 72},
{"mapassign", funcTag, 66}, {"mapassign", funcTag, 67},
{"mapassign_fast32", funcTag, 67}, {"mapassign_fast32", funcTag, 68},
{"mapassign_fast32ptr", funcTag, 67}, {"mapassign_fast32ptr", funcTag, 68},
{"mapassign_fast64", funcTag, 67}, {"mapassign_fast64", funcTag, 68},
{"mapassign_fast64ptr", funcTag, 67}, {"mapassign_fast64ptr", funcTag, 68},
{"mapassign_faststr", funcTag, 67}, {"mapassign_faststr", funcTag, 68},
{"mapiterinit", funcTag, 72}, {"mapiterinit", funcTag, 73},
{"mapdelete", funcTag, 72}, {"mapdelete", funcTag, 73},
{"mapdelete_fast32", funcTag, 73}, {"mapdelete_fast32", funcTag, 74},
{"mapdelete_fast64", funcTag, 73}, {"mapdelete_fast64", funcTag, 74},
{"mapdelete_faststr", funcTag, 73}, {"mapdelete_faststr", funcTag, 74},
{"mapiternext", funcTag, 74}, {"mapiternext", funcTag, 75},
{"mapclear", funcTag, 75}, {"mapclear", funcTag, 76},
{"makechan64", funcTag, 77}, {"makechan64", funcTag, 78},
{"makechan", funcTag, 78}, {"makechan", funcTag, 79},
{"chanrecv1", funcTag, 80}, {"chanrecv1", funcTag, 81},
{"chanrecv2", funcTag, 81}, {"chanrecv2", funcTag, 82},
{"chansend1", funcTag, 83}, {"chansend1", funcTag, 84},
{"closechan", funcTag, 23}, {"closechan", funcTag, 23},
{"writeBarrier", varTag, 85}, {"writeBarrier", varTag, 86},
{"typedmemmove", funcTag, 86}, {"typedmemmove", funcTag, 87},
{"typedmemclr", funcTag, 87}, {"typedmemclr", funcTag, 88},
{"typedslicecopy", funcTag, 88}, {"typedslicecopy", funcTag, 89},
{"selectnbsend", funcTag, 89}, {"selectnbsend", funcTag, 90},
{"selectnbrecv", funcTag, 90}, {"selectnbrecv", funcTag, 91},
{"selectnbrecv2", funcTag, 92}, {"selectnbrecv2", funcTag, 93},
{"selectsetpc", funcTag, 56}, {"selectsetpc", funcTag, 58},
{"selectgo", funcTag, 93}, {"selectgo", funcTag, 94},
{"block", funcTag, 5}, {"block", funcTag, 5},
{"makeslice", funcTag, 94}, {"makeslice", funcTag, 95},
{"makeslice64", funcTag, 95}, {"makeslice64", funcTag, 96},
{"growslice", funcTag, 97}, {"growslice", funcTag, 98},
{"memmove", funcTag, 98}, {"memmove", funcTag, 99},
{"memclrNoHeapPointers", funcTag, 99}, {"memclrNoHeapPointers", funcTag, 100},
{"memclrHasPointers", funcTag, 99}, {"memclrHasPointers", funcTag, 100},
{"memequal", funcTag, 100}, {"memequal", funcTag, 101},
{"memequal8", funcTag, 101}, {"memequal8", funcTag, 102},
{"memequal16", funcTag, 101}, {"memequal16", funcTag, 102},
{"memequal32", funcTag, 101}, {"memequal32", funcTag, 102},
{"memequal64", funcTag, 101}, {"memequal64", funcTag, 102},
{"memequal128", funcTag, 101}, {"memequal128", funcTag, 102},
{"int64div", funcTag, 102}, {"int64div", funcTag, 103},
{"uint64div", funcTag, 103}, {"uint64div", funcTag, 104},
{"int64mod", funcTag, 102}, {"int64mod", funcTag, 103},
{"uint64mod", funcTag, 103}, {"uint64mod", funcTag, 104},
{"float64toint64", funcTag, 104}, {"float64toint64", funcTag, 105},
{"float64touint64", funcTag, 105}, {"float64touint64", funcTag, 106},
{"float64touint32", funcTag, 106}, {"float64touint32", funcTag, 107},
{"int64tofloat64", funcTag, 107}, {"int64tofloat64", funcTag, 108},
{"uint64tofloat64", funcTag, 108}, {"uint64tofloat64", funcTag, 109},
{"uint32tofloat64", funcTag, 109}, {"uint32tofloat64", funcTag, 110},
{"complex128div", funcTag, 110}, {"complex128div", funcTag, 111},
{"racefuncenter", funcTag, 111}, {"racefuncenter", funcTag, 112},
{"racefuncenterfp", funcTag, 5}, {"racefuncenterfp", funcTag, 5},
{"racefuncexit", funcTag, 5}, {"racefuncexit", funcTag, 5},
{"raceread", funcTag, 111}, {"raceread", funcTag, 112},
{"racewrite", funcTag, 111}, {"racewrite", funcTag, 112},
{"racereadrange", funcTag, 112}, {"racereadrange", funcTag, 113},
{"racewriterange", funcTag, 112}, {"racewriterange", funcTag, 113},
{"msanread", funcTag, 112}, {"msanread", funcTag, 113},
{"msanwrite", funcTag, 112}, {"msanwrite", funcTag, 113},
{"support_popcnt", varTag, 11}, {"support_popcnt", varTag, 11},
{"support_sse41", varTag, 11}, {"support_sse41", varTag, 11},
} }
func runtimeTypes() []*types.Type { func runtimeTypes() []*types.Type {
var typs [113]*types.Type var typs [114]*types.Type
typs[0] = types.Bytetype typs[0] = types.Bytetype
typs[1] = types.NewPtr(typs[0]) typs[1] = types.NewPtr(typs[0])
typs[2] = types.Types[TANY] 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[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[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[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[53] = types.Types[TUNSAFEPTR]
typs[54] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2]), anonfield(typs[11])}) typs[54] = functype(nil, []*Node{anonfield(typs[2])}, []*Node{anonfield(typs[53])})
typs[55] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil) typs[55] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, []*Node{anonfield(typs[2])})
typs[56] = functype(nil, []*Node{anonfield(typs[1])}, nil) typs[56] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2]), anonfield(typs[11])})
typs[57] = types.NewPtr(typs[47]) typs[57] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil)
typs[58] = types.Types[TUNSAFEPTR] typs[58] = functype(nil, []*Node{anonfield(typs[1])}, nil)
typs[59] = functype(nil, []*Node{anonfield(typs[57]), anonfield(typs[58]), anonfield(typs[58])}, []*Node{anonfield(typs[11])}) typs[59] = types.NewPtr(typs[47])
typs[60] = types.Types[TUINT32] typs[60] = functype(nil, []*Node{anonfield(typs[59]), anonfield(typs[53]), anonfield(typs[53])}, []*Node{anonfield(typs[11])})
typs[61] = functype(nil, nil, []*Node{anonfield(typs[60])}) typs[61] = types.Types[TUINT32]
typs[62] = types.NewMap(typs[2], typs[2]) typs[62] = functype(nil, nil, []*Node{anonfield(typs[61])})
typs[63] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[3])}, []*Node{anonfield(typs[62])}) typs[63] = types.NewMap(typs[2], typs[2])
typs[64] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[32]), anonfield(typs[3])}, []*Node{anonfield(typs[62])}) typs[64] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[3])}, []*Node{anonfield(typs[63])})
typs[65] = functype(nil, nil, []*Node{anonfield(typs[62])}) typs[65] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[32]), anonfield(typs[3])}, []*Node{anonfield(typs[63])})
typs[66] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[62]), anonfield(typs[3])}, []*Node{anonfield(typs[3])}) typs[66] = functype(nil, nil, []*Node{anonfield(typs[63])})
typs[67] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[62]), anonfield(typs[2])}, []*Node{anonfield(typs[3])}) 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[62]), anonfield(typs[3]), anonfield(typs[1])}, []*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[62]), anonfield(typs[3])}, []*Node{anonfield(typs[3]), anonfield(typs[11])}) 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[62]), anonfield(typs[2])}, []*Node{anonfield(typs[3]), anonfield(typs[11])}) 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[62]), anonfield(typs[3]), anonfield(typs[1])}, []*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[62]), anonfield(typs[3])}, nil) 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[62]), anonfield(typs[2])}, nil) typs[73] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[63]), anonfield(typs[3])}, nil)
typs[74] = functype(nil, []*Node{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[1]), anonfield(typs[62])}, nil) typs[75] = functype(nil, []*Node{anonfield(typs[3])}, nil)
typs[76] = types.NewChan(typs[2], types.Cboth) typs[76] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[63])}, nil)
typs[77] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[76])}) typs[77] = types.NewChan(typs[2], types.Cboth)
typs[78] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[32])}, []*Node{anonfield(typs[76])}) typs[78] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[77])})
typs[79] = types.NewChan(typs[2], types.Crecv) typs[79] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[32])}, []*Node{anonfield(typs[77])})
typs[80] = functype(nil, []*Node{anonfield(typs[79]), anonfield(typs[3])}, nil) typs[80] = types.NewChan(typs[2], types.Crecv)
typs[81] = functype(nil, []*Node{anonfield(typs[79]), anonfield(typs[3])}, []*Node{anonfield(typs[11])}) typs[81] = functype(nil, []*Node{anonfield(typs[80]), anonfield(typs[3])}, nil)
typs[82] = types.NewChan(typs[2], types.Csend) typs[82] = functype(nil, []*Node{anonfield(typs[80]), anonfield(typs[3])}, []*Node{anonfield(typs[11])})
typs[83] = functype(nil, []*Node{anonfield(typs[82]), anonfield(typs[3])}, nil) typs[83] = types.NewChan(typs[2], types.Csend)
typs[84] = types.NewArray(typs[0], 3) typs[84] = functype(nil, []*Node{anonfield(typs[83]), anonfield(typs[3])}, nil)
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[85] = types.NewArray(typs[0], 3)
typs[86] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil) 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])}, nil) 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[2]), anonfield(typs[2])}, []*Node{anonfield(typs[32])}) typs[88] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, nil)
typs[89] = functype(nil, []*Node{anonfield(typs[82]), anonfield(typs[3])}, []*Node{anonfield(typs[11])}) 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[3]), anonfield(typs[79])}, []*Node{anonfield(typs[11])}) typs[90] = functype(nil, []*Node{anonfield(typs[83]), anonfield(typs[3])}, []*Node{anonfield(typs[11])})
typs[91] = types.NewPtr(typs[11]) typs[91] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[80])}, []*Node{anonfield(typs[11])})
typs[92] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[91]), anonfield(typs[79])}, []*Node{anonfield(typs[11])}) typs[92] = types.NewPtr(typs[11])
typs[93] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[32])}, []*Node{anonfield(typs[32]), anonfield(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[32]), anonfield(typs[32])}, []*Node{anonfield(typs[58])}) 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[15]), anonfield(typs[15])}, []*Node{anonfield(typs[58])}) typs[95] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[32]), anonfield(typs[32])}, []*Node{anonfield(typs[53])})
typs[96] = types.NewSlice(typs[2]) typs[96] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[53])})
typs[97] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[96]), anonfield(typs[32])}, []*Node{anonfield(typs[96])}) typs[97] = types.NewSlice(typs[2])
typs[98] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[47])}, nil) 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[58]), anonfield(typs[47])}, nil) typs[99] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[47])}, nil)
typs[100] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[47])}, []*Node{anonfield(typs[11])}) typs[100] = functype(nil, []*Node{anonfield(typs[53]), anonfield(typs[47])}, nil)
typs[101] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[11])}) 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[15]), anonfield(typs[15])}, []*Node{anonfield(typs[15])}) typs[102] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[11])})
typs[103] = functype(nil, []*Node{anonfield(typs[17]), anonfield(typs[17])}, []*Node{anonfield(typs[17])}) typs[103] = functype(nil, []*Node{anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[15])})
typs[104] = functype(nil, []*Node{anonfield(typs[13])}, []*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[17])}) typs[105] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[15])})
typs[106] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[60])}) typs[106] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[17])})
typs[107] = functype(nil, []*Node{anonfield(typs[15])}, []*Node{anonfield(typs[13])}) typs[107] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[61])})
typs[108] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[13])}) typs[108] = functype(nil, []*Node{anonfield(typs[15])}, []*Node{anonfield(typs[13])})
typs[109] = functype(nil, []*Node{anonfield(typs[60])}, []*Node{anonfield(typs[13])}) typs[109] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[13])})
typs[110] = functype(nil, []*Node{anonfield(typs[19]), anonfield(typs[19])}, []*Node{anonfield(typs[19])}) typs[110] = functype(nil, []*Node{anonfield(typs[61])}, []*Node{anonfield(typs[13])})
typs[111] = functype(nil, []*Node{anonfield(typs[47])}, nil) typs[111] = functype(nil, []*Node{anonfield(typs[19]), anonfield(typs[19])}, []*Node{anonfield(typs[19])})
typs[112] = functype(nil, []*Node{anonfield(typs[47]), anonfield(typs[47])}, nil) typs[112] = functype(nil, []*Node{anonfield(typs[47])}, nil)
typs[113] = functype(nil, []*Node{anonfield(typs[47]), anonfield(typs[47])}, nil)
return typs[:] return typs[:]
} }

View file

@ -61,23 +61,23 @@ func slicestringcopy(to any, fr any) int
func decoderune(string, int) (retv rune, retk int) func decoderune(string, int) (retv rune, retk int)
func countrunes(string) int func countrunes(string) int
// interface conversions // Non-empty-interface to non-empty-interface conversion.
func convI2I(typ *byte, elem any) (ret any) 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 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) func convT2Enoptr(typ *byte, elem *any) (ret any)
// Type to non-empty-interface conversion.
func convT2I(tab *byte, elem *any) (ret any) 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) func convT2Inoptr(tab *byte, elem *any) (ret any)
// interface type assertions x.(T) // interface type assertions x.(T)

View file

@ -314,7 +314,7 @@ func transformclosure(xfunc *Node) {
lineno = lno lineno = lno
} }
// hasemptycvars returns true iff closure clo has an // hasemptycvars reports whether closure clo has an
// empty list of captured vars. // empty list of captured vars.
func hasemptycvars(clo *Node) bool { func hasemptycvars(clo *Node) bool {
xfunc := clo.Func.Closure xfunc := clo.Func.Closure

View file

@ -300,7 +300,7 @@ func beginRange(calls []dwarf.InlCall, p *obj.Prog, ii int, imap map[int]int) *d
} }
callIdx, found := imap[ii] callIdx, found := imap[ii]
if !found { 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] call := &calls[callIdx]

View file

@ -1114,6 +1114,7 @@ var opprec = []int{
OSLICEARR: 8, OSLICEARR: 8,
OSLICE3: 8, OSLICE3: 8,
OSLICE3ARR: 8, OSLICE3ARR: 8,
OSLICEHEADER: 8,
ODOTINTER: 8, ODOTINTER: 8,
ODOTMETH: 8, ODOTMETH: 8,
ODOTPTR: 8, ODOTPTR: 8,
@ -1393,6 +1394,12 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
} }
fmt.Fprint(s, "]") 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: case OCOPY, OCOMPLEX:
mode.Fprintf(s, "%#v(%v, %v)", n.Op, n.Left, n.Right) mode.Fprintf(s, "%#v(%v, %v)", n.Op, n.Left, n.Right)

View file

@ -147,7 +147,6 @@ var asmhdr string
var simtype [NTYPE]types.EType var simtype [NTYPE]types.EType
var ( var (
isforw [NTYPE]bool
isInt [NTYPE]bool isInt [NTYPE]bool
isFloat [NTYPE]bool isFloat [NTYPE]bool
isComplex [NTYPE]bool isComplex [NTYPE]bool

View file

@ -185,24 +185,6 @@ func (pp *Progs) settext(fn *Node) {
ptxt.From.Type = obj.TYPE_MEM ptxt.From.Type = obj.TYPE_MEM
ptxt.From.Name = obj.NAME_EXTERN ptxt.From.Name = obj.NAME_EXTERN
ptxt.From.Sym = fn.Func.lsym 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() { func (f *Func) initLSym() {

View file

@ -909,7 +909,7 @@ func (w *exportWriter) mpfloat(f *big.Float, typ *types.Type) {
manti, acc := mant.Int(nil) manti, acc := mant.Int(nil)
if acc != big.Exact { if acc != big.Exact {
Fatalf("exporter: internal error") Fatalf("mantissa scaling failed for %f (%s)", f, acc)
} }
w.mpint(manti, typ) w.mpint(manti, typ)
if manti.Sign() != 0 { if manti.Sign() != 0 {

View file

@ -38,9 +38,10 @@ import (
const ( const (
inlineMaxBudget = 80 inlineMaxBudget = 80
inlineExtraAppendCost = 0 inlineExtraAppendCost = 0
inlineExtraCallCost = inlineMaxBudget // default is do not inline, -l=4 enables by using 1 instead. // default is to inline if there's at most one call. -l=4 overrides this by using 1 instead.
inlineExtraPanicCost = 1 // do not penalize inlining panics. inlineExtraCallCost = inlineMaxBudget * 3 / 4
inlineExtraThrowCost = inlineMaxBudget // with current (2018-05/1.11) code, inlining runtime.throw does not help. 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". inlineBigFunctionNodes = 5000 // Functions with this many nodes are considered "big".
inlineBigFunctionMaxCost = 20 // Max cost of inlinee when inlining into a "big" function. inlineBigFunctionMaxCost = 20 // Max cost of inlinee when inlining into a "big" function.
@ -141,6 +142,13 @@ func caninl(fn *Node) {
return 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 // The nowritebarrierrec checker currently works at function
// granularity, so inlining yeswritebarrierrec functions can // granularity, so inlining yeswritebarrierrec functions can
// confuse it (#22342). As a workaround, disallow inlining // confuse it (#22342). As a workaround, disallow inlining

View file

@ -55,6 +55,7 @@ func TestIntendedInlining(t *testing.T) {
"isDirectIface", "isDirectIface",
"itabHashFunc", "itabHashFunc",
"noescape", "noescape",
"pcvalueCacheKey",
"readUnaligned32", "readUnaligned32",
"readUnaligned64", "readUnaligned64",
"releasem", "releasem",

View file

@ -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) == 3 && !isQuoted(f[1]) && !isQuoted(f[2]):
case len(f) == 4 && !isQuoted(f[1]) && !isQuoted(f[2]) && isQuoted(f[3]): case len(f) == 4 && !isQuoted(f[1]) && !isQuoted(f[2]) && isQuoted(f[3]):
f[3] = strings.Trim(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: default:
p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_dynamic local [remote ["library"]]`}) p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_dynamic local [remote ["library"]]`})
return return

View file

@ -7,6 +7,7 @@ package gc
import ( import (
"cmd/compile/internal/syntax" "cmd/compile/internal/syntax"
"reflect" "reflect"
"runtime"
"testing" "testing"
) )
@ -49,10 +50,12 @@ func TestPragmaFields(t *testing.T) {
} }
func TestPragcgo(t *testing.T) { func TestPragcgo(t *testing.T) {
var tests = []struct { type testStruct struct {
in string in string
want []string want []string
}{ }
var tests = []testStruct{
{`go:cgo_export_dynamic local`, []string{`cgo_export_dynamic`, `local`}}, {`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`}},
{`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_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`, []string{`cgo_import_dynamic`, `local`}},
{`go:cgo_import_dynamic local remote`, []string{`cgo_import_dynamic`, `local`, `remote`}}, {`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_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/`}}, {`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`}}, {`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{`<unknown position>: usage: //go:cgo_import_dynamic local [remote ["lib.a/object.o"]]`}},
}...)
}
var p noder var p noder
var nopos syntax.Pos var nopos syntax.Pos
for _, tt := range tests { for _, tt := range tests {
p.pragcgobuf = nil
p.pragcgo(nopos, tt.in)
got := p.pragcgobuf p.err = make(chan syntax.Error)
want := [][]string{tt.want} gotch := make(chan [][]string)
if !reflect.DeepEqual(got, want) { go func() {
t.Errorf("pragcgo(%q) = %q; want %q", tt.in, got, want) p.pragcgobuf = nil
continue 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
}
} }
} }
} }

View file

@ -229,6 +229,9 @@ func Main(archInit func(*Arch)) {
flag.BoolVar(&flag_race, "race", false, "enable race detector") flag.BoolVar(&flag_race, "race", false, "enable race detector")
} }
objabi.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s']) 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.StringVar(&pathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths")
flag.BoolVar(&Debug_vlog, "v", false, "increase debug verbosity") flag.BoolVar(&Debug_vlog, "v", false, "increase debug verbosity")
objabi.Flagcount("w", "debug type checking", &Debug['w']) 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. // Phase 1: const, type, and names and types of funcs.
// This will gather all the information about types // This will gather all the information about types
// and methods but doesn't depend on any of it. // 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() defercheckwidth()
// Don't use range--typecheck can add closures to xtop. // Don't use range--typecheck can add closures to xtop.
timings.Start("fe", "typecheck", "top1") timings.Start("fe", "typecheck", "top1")
for i := 0; i < len(xtop); i++ { for i := 0; i < len(xtop); i++ {
n := 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) xtop[i] = typecheck(n, Etop)
} }
} }
@ -506,7 +513,7 @@ func Main(archInit func(*Arch)) {
timings.Start("fe", "typecheck", "top2") timings.Start("fe", "typecheck", "top2")
for i := 0; i < len(xtop); i++ { for i := 0; i < len(xtop); i++ {
n := 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) xtop[i] = typecheck(n, Etop)
} }
} }

View file

@ -273,22 +273,18 @@ func dumpglobls() {
} }
// addGCLocals adds gcargs, gclocals, gcregs, and stack object symbols to Ctxt.Data. // 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, // This is done during the sequential phase after compilation, since
// storing only a single copy of the data, // global symbols can't be declared during parallel compilation.
// failure to remove these duplicates adds a few percent to object file size.
func addGCLocals() { func addGCLocals() {
seen := make(map[string]bool)
for _, s := range Ctxt.Text { for _, s := range Ctxt.Text {
if s.Func == nil { if s.Func == nil {
continue continue
} }
for _, gcsym := range []*obj.LSym{&s.Func.GCArgs, &s.Func.GCLocals, &s.Func.GCRegs} { for _, gcsym := range []*obj.LSym{s.Func.GCArgs, s.Func.GCLocals, s.Func.GCRegs} {
if seen[gcsym.Name] { if gcsym != nil && !gcsym.OnList() {
continue 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 { if x := s.Func.StackObjects; x != nil {
ggloblsym(x, int32(len(x.P)), obj.RODATA|obj.LOCAL) ggloblsym(x, int32(len(x.P)), obj.RODATA|obj.LOCAL)

View file

@ -4,9 +4,9 @@ package gc
import "strconv" 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 { func (i Op) String() string {
if i >= Op(len(_Op_index)-1) { if i >= Op(len(_Op_index)-1) {

View file

@ -1019,7 +1019,7 @@ func (lv *Liveness) epilogue() {
live := lv.livevars[index] live := lv.livevars[index]
if v.Op.IsCall() && live.regs != 0 { if v.Op.IsCall() && live.regs != 0 {
lv.printDebug() 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++ index++
} }
@ -1038,7 +1038,7 @@ func (lv *Liveness) epilogue() {
// input parameters. // input parameters.
for j, n := range lv.vars { for j, n := range lv.vars {
if n.Class() != PPARAM && lv.stackMaps[0].Get(int32(j)) { 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. // 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. // so it doesn't appear live at entry.
if regs := lv.regMaps[0]; regs != 0 { if regs := lv.regMaps[0]; regs != 0 {
lv.printDebug() 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 // 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 // length of the bitmaps. All bitmaps are assumed to be of equal length. The
// remaining bytes are the raw bitmaps. // 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. // Size args bitmaps to be just large enough to hold the largest pointer.
// First, find the largest Xoffset node we care about. // First, find the largest Xoffset node we care about.
// (Nodes without pointers aren't in lv.vars; see livenessShouldTrack.) // (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. // This would require shifting all bitmaps.
maxLocals := lv.stkptrsize maxLocals := lv.stkptrsize
// Temporary symbols for encoding bitmaps.
var argsSymTmp, liveSymTmp, regsSymTmp obj.LSym
args := bvalloc(int32(maxArgs / int64(Widthptr))) args := bvalloc(int32(maxArgs / int64(Widthptr)))
aoff := duint32(argssym, 0, uint32(len(lv.stackMaps))) // number of bitmaps aoff := duint32(&argsSymTmp, 0, uint32(len(lv.stackMaps))) // number of bitmaps
aoff = duint32(argssym, aoff, uint32(args.n)) // number of bits in each bitmap aoff = duint32(&argsSymTmp, aoff, uint32(args.n)) // number of bits in each bitmap
locals := bvalloc(int32(maxLocals / int64(Widthptr))) locals := bvalloc(int32(maxLocals / int64(Widthptr)))
loff := duint32(livesym, 0, uint32(len(lv.stackMaps))) // number of bitmaps loff := duint32(&liveSymTmp, 0, uint32(len(lv.stackMaps))) // number of bitmaps
loff = duint32(livesym, loff, uint32(locals.n)) // number of bits in each bitmap loff = duint32(&liveSymTmp, loff, uint32(locals.n)) // number of bits in each bitmap
for _, live := range lv.stackMaps { for _, live := range lv.stackMaps {
args.Clear() args.Clear()
@ -1503,13 +1506,13 @@ func (lv *Liveness) emit(argssym, livesym, regssym *obj.LSym) {
lv.pointerMap(live, lv.vars, args, locals) lv.pointerMap(live, lv.vars, args, locals)
aoff = dbvec(argssym, aoff, args) aoff = dbvec(&argsSymTmp, aoff, args)
loff = dbvec(livesym, loff, locals) loff = dbvec(&liveSymTmp, loff, locals)
} }
regs := bvalloc(lv.usedRegs()) regs := bvalloc(lv.usedRegs())
roff := duint32(regssym, 0, uint32(len(lv.regMaps))) // number of bitmaps roff := duint32(&regsSymTmp, 0, uint32(len(lv.regMaps))) // number of bitmaps
roff = duint32(regssym, roff, uint32(regs.n)) // number of bits in each bitmap roff = duint32(&regsSymTmp, roff, uint32(regs.n)) // number of bits in each bitmap
if regs.n > 32 { if regs.n > 32 {
// Our uint32 conversion below won't work. // Our uint32 conversion below won't work.
Fatalf("GP registers overflow uint32") Fatalf("GP registers overflow uint32")
@ -1519,25 +1522,29 @@ func (lv *Liveness) emit(argssym, livesym, regssym *obj.LSym) {
for _, live := range lv.regMaps { for _, live := range lv.regMaps {
regs.Clear() regs.Clear()
regs.b[0] = uint32(live) regs.b[0] = uint32(live)
roff = dbvec(regssym, roff, regs) roff = dbvec(&regsSymTmp, roff, regs)
} }
} }
// Give these LSyms content-addressable names, // Give these LSyms content-addressable names,
// so that they can be de-duplicated. // so that they can be de-duplicated.
// This provides significant binary size savings. // This provides significant binary size savings.
// It is safe to rename these LSyms because //
// they are tracked separately from ctxt.hash. // These symbols will be added to Ctxt.Data by addGCLocals
argssym.Name = fmt.Sprintf("gclocals·%x", md5.Sum(argssym.P)) // after parallel compilation is done.
livesym.Name = fmt.Sprintf("gclocals·%x", md5.Sum(livesym.P)) makeSym := func(tmpSym *obj.LSym) *obj.LSym {
regssym.Name = fmt.Sprintf("gclocals·%x", md5.Sum(regssym.P)) 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(&regsSymTmp)
} }
// Entry pointer for liveness analysis. Solves for the liveness of // Entry pointer for liveness analysis. Solves for the liveness of
// pointer variables in the function and emits a runtime data // pointer variables in the function and emits a runtime data
// structure read by the garbage collector. // structure read by the garbage collector.
// Returns a map from GC safe points to their corresponding stack map index. // 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. // Construct the global liveness state.
vars, idx := getvariables(e.curfn) vars, idx := getvariables(e.curfn)
lv := newliveness(e.curfn, f, vars, idx, e.stkptrsize) 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 // Emit the live pointer map data structures
if ls := e.curfn.Func.lsym; ls != nil { 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 return lv.livenessMap
} }

View file

@ -812,7 +812,7 @@ func dcommontype(lsym *obj.LSym, t *types.Type) int {
sptrWeak := true sptrWeak := true
var sptr *obj.LSym var sptr *obj.LSym
if !t.IsPtr() || t.PtrBase != nil { if !t.IsPtr() || t.IsPtrElem() {
tptr := types.NewPtr(t) tptr := types.NewPtr(t)
if t.Sym != nil || methods(tptr) != nil { if t.Sym != nil || methods(tptr) != nil {
sptrWeak = false sptrWeak = false
@ -1137,7 +1137,7 @@ func dtypesym(t *types.Type) *obj.LSym {
return lsym return lsym
} }
// TODO(mdempsky): Investigate whether this can happen. // TODO(mdempsky): Investigate whether this can happen.
if isforw[tbase.Etype] { if tbase.Etype == TFORW {
return lsym return lsym
} }
} }

View file

@ -5051,7 +5051,7 @@ func genssa(f *ssa.Func, pp *Progs) {
e := f.Frontend().(*ssafn) e := f.Frontend().(*ssafn)
s.livenessMap = liveness(e, f) s.livenessMap = liveness(e, f, pp)
emitStackObjects(e, pp) emitStackObjects(e, pp)
// Remember where each block starts. // Remember where each block starts.

View file

@ -929,7 +929,7 @@ type nodeQueue struct {
head, tail int head, tail int
} }
// empty returns true if q contains no Nodes. // empty reports whether q contains no Nodes.
func (q *nodeQueue) empty() bool { func (q *nodeQueue) empty() bool {
return q.head == q.tail return q.head == q.tail
} }

View file

@ -12,6 +12,50 @@ import (
"strings" "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 ( const (
Etop = 1 << iota // evaluated at statement level Etop = 1 << iota // evaluated at statement level
Erv // evaluated in value context Erv // evaluated in value context
@ -31,11 +75,16 @@ const (
var typecheckdefstack []*Node var typecheckdefstack []*Node
// resolve ONONAME to definition, if any. // resolve ONONAME to definition, if any.
func resolve(n *Node) *Node { func resolve(n *Node) (res *Node) {
if n == nil || n.Op != ONONAME { if n == nil || n.Op != ONONAME {
return n return n
} }
// only trace if there's work to do
if enableTrace && trace {
defer tracePrint("resolve", n)(&res)
}
if n.Sym.Pkg != localpkg { if n.Sym.Pkg != localpkg {
if inimport { if inimport {
Fatalf("recursive inimport") Fatalf("recursive inimport")
@ -150,7 +199,7 @@ var typecheck_tcstack []*Node
// typecheck type checks node n. // typecheck type checks node n.
// The result of typecheck MUST be assigned back to n, e.g. // The result of typecheck MUST be assigned back to n, e.g.
// n.Left = typecheck(n.Left, top) // 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 // cannot type check until all the source has been parsed
if !typecheckok { if !typecheckok {
Fatalf("early typecheck") Fatalf("early typecheck")
@ -160,6 +209,11 @@ func typecheck(n *Node, top int) *Node {
return nil return nil
} }
// only trace if there's work to do
if enableTrace && trace {
defer tracePrint("typecheck", n)(&res)
}
lno := setlineno(n) lno := setlineno(n)
// Skip over parens. // Skip over parens.
@ -201,8 +255,16 @@ func typecheck(n *Node, top int) *Node {
// since it would expand indefinitely when aliases // since it would expand indefinitely when aliases
// are substituted. // are substituted.
cycle := cycleFor(n) cycle := cycleFor(n)
for _, n := range cycle { for _, n1 := range cycle {
if n.Name != nil && !n.Name.Param.Alias { 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 lineno = lno
return n return n
} }
@ -294,7 +356,11 @@ func indexlit(n *Node) *Node {
// The result of typecheck1 MUST be assigned back to n, e.g. // The result of typecheck1 MUST be assigned back to n, e.g.
// n.Left = typecheck1(n.Left, top) // 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 { switch n.Op {
case OLITERAL, ONAME, ONONAME, OTYPE: case OLITERAL, ONAME, ONONAME, OTYPE:
if n.Sym == nil { if n.Sym == nil {
@ -1094,11 +1160,15 @@ func typecheck1(n *Node, top int) *Node {
ok |= Erv ok |= Erv
t := n.Type t := n.Type
if t == nil {
Fatalf("no type specified for OSLICEHEADER")
}
if !t.IsSlice() { if !t.IsSlice() {
Fatalf("invalid type %v for OSLICEHEADER", n.Type) 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") 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 // typecheckMethodExpr checks selector expressions (ODOT) where the
// base expression is a type expression (OTYPE). // 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 t := n.Left.Type
// Compute the method set for t. // 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. // The result of typecheckcomplit MUST be assigned back to n, e.g.
// n.Left = typecheckcomplit(n.Left) // 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 lno := lineno
defer func() { defer func() {
lineno = lno 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, // if this assignment is the definition of a var on the left side,
// fill in the var's type. // fill in the var's type.
func typecheckas(n *Node) { func typecheckas(n *Node) {
if enableTrace && trace {
defer tracePrint("typecheckas", n)(nil)
}
// delicate little dance. // delicate little dance.
// the definition of n may refer to this assignment // the definition of n may refer to this assignment
// as its definition, in which case it will call typecheckas. // 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) { func typecheckas2(n *Node) {
if enableTrace && trace {
defer tracePrint("typecheckas2", n)(nil)
}
ls := n.List.Slice() ls := n.List.Slice()
for i1, n1 := range ls { for i1, n1 := range ls {
// delicate little dance. // delicate little dance.
@ -3521,6 +3607,10 @@ out:
// type check function definition // type check function definition
func typecheckfunc(n *Node) { func typecheckfunc(n *Node) {
if enableTrace && trace {
defer tracePrint("typecheckfunc", n)(nil)
}
for _, ln := range n.Func.Dcl { for _, ln := range n.Func.Dcl {
if ln.Op == ONAME && (ln.Class() == PPARAM || ln.Class() == PPARAMOUT) { if ln.Op == ONAME && (ln.Class() == PPARAM || ln.Class() == PPARAMOUT) {
ln.Name.Decldepth = 1 ln.Name.Decldepth = 1
@ -3593,8 +3683,7 @@ func copytype(n *Node, t *types.Type) {
embedlineno := n.Type.ForwardType().Embedlineno embedlineno := n.Type.ForwardType().Embedlineno
l := n.Type.ForwardType().Copyto l := n.Type.ForwardType().Copyto
ptrBase := n.Type.PtrBase cache := n.Type.Cache
sliceOf := n.Type.SliceOf
// TODO(mdempsky): Fix Type rekinding. // TODO(mdempsky): Fix Type rekinding.
*n.Type = *t *n.Type = *t
@ -3615,8 +3704,7 @@ func copytype(n *Node, t *types.Type) {
t.Nod = asTypesNode(n) t.Nod = asTypesNode(n)
t.SetDeferwidth(false) t.SetDeferwidth(false)
t.PtrBase = ptrBase t.Cache = cache
t.SliceOf = sliceOf
// Propagate go:notinheap pragma from the Name to the Type. // Propagate go:notinheap pragma from the Name to the Type.
if n.Name != nil && n.Name.Param != nil && n.Name.Param.Pragma&NotInHeap != 0 { 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) { func typecheckdeftype(n *Node) {
if enableTrace && trace {
defer tracePrint("typecheckdeftype", n)(nil)
}
n.Type.Sym = n.Sym n.Type.Sym = n.Sym
n.SetTypecheck(1) n.SetTypecheck(1)
n.Name.Param.Ntype = typecheck(n.Name.Param.Ntype, Etype) n.Name.Param.Ntype = typecheck(n.Name.Param.Ntype, Etype)
@ -3654,6 +3746,10 @@ func typecheckdeftype(n *Node) {
} }
func typecheckdef(n *Node) { func typecheckdef(n *Node) {
if enableTrace && trace {
defer tracePrint("typecheckdef", n)(nil)
}
lno := setlineno(n) lno := setlineno(n)
if n.Op == ONONAME { if n.Op == ONONAME {
@ -3992,6 +4088,12 @@ func deadcode(fn *Node) {
} }
func deadcodeslice(nn Nodes) { 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() { for i, n := range nn.Slice() {
// Cut is set to true when all nodes after i'th position // Cut is set to true when all nodes after i'th position
// should be removed. // should be removed.
@ -4014,10 +4116,14 @@ func deadcodeslice(nn Nodes) {
// If "then" or "else" branch ends with panic or return statement, // If "then" or "else" branch ends with panic or return statement,
// it is safe to remove all statements after this node. // it is safe to remove all statements after this node.
// isterminating is not used to avoid goto-related complications. // 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 { if body := body.Slice(); len(body) != 0 {
switch body[(len(body) - 1)].Op { switch body[(len(body) - 1)].Op {
case ORETURN, ORETJMP, OPANIC: case ORETURN, ORETJMP, OPANIC:
cut = true if i > lastLabel {
cut = true
}
} }
} }
} }

View file

@ -200,8 +200,6 @@ func typeinit() {
isComplex[TCOMPLEX64] = true isComplex[TCOMPLEX64] = true
isComplex[TCOMPLEX128] = true isComplex[TCOMPLEX128] = true
isforw[TFORW] = true
// initialize okfor // initialize okfor
for et := types.EType(0); et < NTYPE; et++ { for et := types.EType(0); et < NTYPE; et++ {
if isInt[et] || et == TIDEAL { if isInt[et] || et == TIDEAL {

View file

@ -384,41 +384,31 @@ func convFuncName(from, to *types.Type) (fnname string, needsaddr bool) {
tkind := to.Tie() tkind := to.Tie()
switch from.Tie() { switch from.Tie() {
case 'I': case 'I':
switch tkind { if tkind == 'I' {
case 'I':
return "convI2I", false return "convI2I", false
} }
case 'T': 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 { switch tkind {
case 'E': case 'E':
switch { if !types.Haspointers(from) {
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):
return "convT2Enoptr", true return "convT2Enoptr", true
} }
return "convT2E", true return "convT2E", true
case 'I': case 'I':
switch { if !types.Haspointers(from) {
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):
return "convT2Inoptr", true return "convT2Inoptr", true
} }
return "convT2I", true return "convT2I", true
@ -496,7 +486,7 @@ opswitch:
OIND, OSPTR, OITAB, OIDATA, OADDR: OIND, OSPTR, OITAB, OIDATA, OADDR:
n.Left = walkexpr(n.Left, init) 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.Left = walkexpr(n.Left, init)
n.Right = walkexpr(n.Right, init) n.Right = walkexpr(n.Right, init)
@ -548,15 +538,6 @@ opswitch:
n.SetTypecheck(1) 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: case OCOMPLEX:
// Use results from call expression as arguments for complex. // Use results from call expression as arguments for complex.
if n.Left == nil && n.Right == nil { if n.Left == nil && n.Right == nil {
@ -834,16 +815,21 @@ opswitch:
case OCONVIFACE: case OCONVIFACE:
n.Left = walkexpr(n.Left, init) n.Left = walkexpr(n.Left, init)
// Optimize convT2E or convT2I as a two-word copy when T is pointer-shaped. fromType := n.Left.Type
if isdirectiface(n.Left.Type) { toType := n.Type
var t *Node
if n.Type.IsEmptyInterface() { // typeword generates the type word of the interface value.
t = typename(n.Left.Type) typeword := func() *Node {
} else { if toType.IsEmptyInterface() {
t = itabname(n.Left.Type, n.Type) return typename(fromType)
} }
l := nod(OEFACE, t, n.Left) return itabname(fromType, toType)
l.Type = n.Type }
// 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()) l.SetTypecheck(n.Typecheck())
n = l n = l
break break
@ -863,11 +849,11 @@ opswitch:
// or creating one on the stack. // or creating one on the stack.
var value *Node var value *Node
switch { switch {
case n.Left.Type.Size() == 0: case fromType.Size() == 0:
// n.Left is zero-sized. Use zerobase. // n.Left is zero-sized. Use zerobase.
cheapexpr(n.Left, init) // Evaluate n.Left for side-effects. See issue 19246. cheapexpr(n.Left, init) // Evaluate n.Left for side-effects. See issue 19246.
value = zerobase 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 is a bool/byte. Use staticbytes[n.Left].
n.Left = cheapexpr(n.Left, init) n.Left = cheapexpr(n.Left, init)
value = nod(OINDEX, staticbytes, byteindex(n.Left)) 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(): case n.Left.Class() == PEXTERN && n.Left.Name != nil && n.Left.Name.Readonly():
// n.Left is a readonly global; use it directly. // n.Left is a readonly global; use it directly.
value = n.Left 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. // 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)) init.Append(typecheck(nod(OAS, value, n.Left), Etop))
} }
if value != nil { if value != nil {
// Value is identical to n.Left. // Value is identical to n.Left.
// Construct the interface directly: {type/itab, &value}. // Construct the interface directly: {type/itab, &value}.
var t *Node l := nod(OEFACE, typeword(), typecheck(nod(OADDR, value, nil), Erv))
if n.Type.IsEmptyInterface() { l.Type = toType
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.SetTypecheck(n.Typecheck()) l.SetTypecheck(n.Typecheck())
n = l n = l
break break
@ -903,9 +883,9 @@ opswitch:
// tmp = tmp.type // tmp = tmp.type
// } // }
// e = iface{tmp, i.data} // 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. // Evaluate the input interface.
c := temp(n.Left.Type) c := temp(fromType)
init.Append(nod(OAS, c, n.Left)) init.Append(nod(OAS, c, n.Left))
// Get the itab out of the interface. // Get the itab out of the interface.
@ -919,26 +899,43 @@ opswitch:
// Build the result. // Build the result.
e := nod(OEFACE, tmp, ifaceData(c, types.NewPtr(types.Types[TUINT8]))) 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) e.SetTypecheck(1)
n = e n = e
break break
} }
var ll []*Node fnname, needsaddr := convFuncName(fromType, toType)
if n.Type.IsEmptyInterface() {
if !n.Left.Type.IsInterface() { if !needsaddr && !fromType.IsInterface() {
ll = append(ll, typename(n.Left.Type)) // Use a specialized conversion routine that only returns a data pointer.
} // ptr = convT2X(val)
} else { // e = iface{typ/tab, ptr}
if n.Left.Type.IsInterface() { fn := syslook(fnname)
ll = append(ll, typename(n.Type)) dowidth(fromType)
} else { fn = substArgTypes(fn, fromType)
ll = append(ll, itabname(n.Left.Type, n.Type)) 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 v := n.Left
if needsaddr { if needsaddr {
// Types of large or unknown size are passed by reference. // Types of large or unknown size are passed by reference.
@ -952,14 +949,13 @@ opswitch:
} }
v = nod(OADDR, v, nil) v = nod(OADDR, v, nil)
} }
ll = append(ll, v)
dowidth(n.Left.Type) dowidth(fromType)
fn := syslook(fnname) fn := syslook(fnname)
fn = substArgTypes(fn, n.Left.Type, n.Type) fn = substArgTypes(fn, fromType, toType)
dowidth(fn.Type) dowidth(fn.Type)
n = nod(OCALL, fn, nil) n = nod(OCALL, fn, nil)
n.List.Set(ll) n.List.Set2(tab, v)
n = typecheck(n, Erv) n = typecheck(n, Erv)
n = walkexpr(n, init) n = walkexpr(n, init)
@ -1343,14 +1339,17 @@ opswitch:
argtype = types.Types[TINT] argtype = types.Types[TINT]
} }
m := nod(OSLICEHEADER, nil, nil)
m.Type = t
fn := syslook(fnname) fn := syslook(fnname)
n.Left = mkcall1(fn, types.Types[TUNSAFEPTR], init, typename(t.Elem()), conv(len, argtype), conv(cap, argtype)) m.Left = mkcall1(fn, types.Types[TUNSAFEPTR], init, typename(t.Elem()), conv(len, argtype), conv(cap, argtype))
n.Left.SetNonNil(true) m.Left.SetNonNil(true)
n.List.Set2(conv(len, types.Types[TINT]), conv(cap, types.Types[TINT])) m.List.Set2(conv(len, types.Types[TINT]), conv(cap, types.Types[TINT]))
n.Op = OSLICEHEADER
n.Type = t m = typecheck(m, Erv)
n = typecheck(n, Erv) m = walkexpr(m, init)
n = walkexpr(n, init) n = m
} }
case ORUNESTR: case ORUNESTR:

View file

@ -569,7 +569,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
ssa.OpPPC64ROTL, ssa.OpPPC64ROTLW, ssa.OpPPC64ROTL, ssa.OpPPC64ROTLW,
ssa.OpPPC64MULHD, ssa.OpPPC64MULHW, ssa.OpPPC64MULHDU, ssa.OpPPC64MULHWU, ssa.OpPPC64MULHD, ssa.OpPPC64MULHW, ssa.OpPPC64MULHDU, ssa.OpPPC64MULHWU,
ssa.OpPPC64FMUL, ssa.OpPPC64FMULS, ssa.OpPPC64FDIV, ssa.OpPPC64FDIVS, ssa.OpPPC64FCPSGN, 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() r := v.Reg()
r1 := v.Args[0].Reg() r1 := v.Args[0].Reg()
r2 := v.Args[1].Reg() r2 := v.Args[1].Reg()

View file

@ -112,7 +112,7 @@ type Logger interface {
// Logf logs a message from the compiler. // Logf logs a message from the compiler.
Logf(string, ...interface{}) 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. // some logging calls account for more than a few heap allocations.
Log() bool Log() bool

View file

@ -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. // pending.
func canMerge(pending, new VarLoc) bool { func canMerge(pending, new VarLoc) bool {
if pending.absent() && new.absent() { if pending.absent() && new.absent() {

View file

@ -621,7 +621,7 @@ func (f *Func) invalidateCFG() {
f.cachedLoopnest = nil 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) // 1) is empty (this is a special more-quickly implemented case of 3)
// 2) is "y" or "Y" // 2) is "y" or "Y"
// 3) is a suffix of the sha1 hash of name // 3) is a suffix of the sha1 hash of name

View file

@ -518,6 +518,13 @@
(LessEqual (InvertFlags x)) -> (GreaterEqual x) (LessEqual (InvertFlags x)) -> (GreaterEqual x)
(GreaterEqual (InvertFlags x)) -> (LessEqual 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 // Lowering loads
(Load <t> ptr mem) && (is64BitInt(t) || isPtr(t)) -> (MOVDload ptr mem) (Load <t> ptr mem) && (is64BitInt(t) || isPtr(t)) -> (MOVDload ptr mem)
(Load <t> ptr mem) && is32BitInt(t) && isSigned(t) -> (MOVWload ptr mem) (Load <t> ptr mem) && is32BitInt(t) && isSigned(t) -> (MOVWload ptr mem)

View file

@ -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: "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: "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: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true}, // arg0&arg1
{name: "ANDN", argLength: 2, reg: gp21, asm: "ANDN"}, // 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: "ANDCC", argLength: 2, reg: gp21, asm: "ANDCC", commutative: true, typ: "Flags"}, // arg0&arg1 sets CC
{name: "ORN", argLength: 2, reg: gp21, asm: "ORN"}, // arg0|^arg1 {name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true}, // arg0|arg1
{name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true}, // ^(arg0|arg1) {name: "ORN", argLength: 2, reg: gp21, asm: "ORN"}, // arg0|^arg1
{name: "XOR", argLength: 2, reg: gp21, asm: "XOR", typ: "Int64", commutative: true}, // arg0^arg1 {name: "ORCC", argLength: 2, reg: gp21, asm: "ORCC", commutative: true, typ: "Flags"}, // arg0|arg1 sets CC
{name: "EQV", argLength: 2, reg: gp21, asm: "EQV", typ: "Int64", commutative: true}, // arg0^^arg1 {name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true}, // ^(arg0|arg1)
{name: "NEG", argLength: 1, reg: gp11, asm: "NEG"}, // -arg0 (integer) {name: "XOR", argLength: 2, reg: gp21, asm: "XOR", typ: "Int64", commutative: true}, // arg0^arg1
{name: "FNEG", argLength: 1, reg: fp11, asm: "FNEG"}, // -arg0 (floating point) {name: "XORCC", argLength: 2, reg: gp21, asm: "XORCC", commutative: true, typ: "Flags"}, // arg0^arg1 sets CC
{name: "FSQRT", argLength: 1, reg: fp11, asm: "FSQRT"}, // sqrt(arg0) (floating point) {name: "EQV", argLength: 2, reg: gp21, asm: "EQV", typ: "Int64", commutative: true}, // arg0^^arg1
{name: "FSQRTS", argLength: 1, reg: fp11, asm: "FSQRTS"}, // sqrt(arg0) (floating point, single precision) {name: "NEG", argLength: 1, reg: gp11, asm: "NEG"}, // -arg0 (integer)
{name: "FFLOOR", argLength: 1, reg: fp11, asm: "FRIM"}, // floor(arg0), float64 {name: "FNEG", argLength: 1, reg: fp11, asm: "FNEG"}, // -arg0 (floating point)
{name: "FCEIL", argLength: 1, reg: fp11, asm: "FRIP"}, // ceil(arg0), float64 {name: "FSQRT", argLength: 1, reg: fp11, asm: "FSQRT"}, // sqrt(arg0) (floating point)
{name: "FTRUNC", argLength: 1, reg: fp11, asm: "FRIZ"}, // trunc(arg0), float64 {name: "FSQRTS", argLength: 1, reg: fp11, asm: "FSQRTS"}, // sqrt(arg0) (floating point, single precision)
{name: "FROUND", argLength: 1, reg: fp11, asm: "FRIN"}, // round(arg0), float64 {name: "FFLOOR", argLength: 1, reg: fp11, asm: "FRIM"}, // floor(arg0), float64
{name: "FABS", argLength: 1, reg: fp11, asm: "FABS"}, // abs(arg0), float64 {name: "FCEIL", argLength: 1, reg: fp11, asm: "FRIP"}, // ceil(arg0), float64
{name: "FNABS", argLength: 1, reg: fp11, asm: "FNABS"}, // -abs(arg0), float64 {name: "FTRUNC", argLength: 1, reg: fp11, asm: "FRIZ"}, // trunc(arg0), float64
{name: "FCPSGN", argLength: 2, reg: fp21, asm: "FCPSGN"}, // copysign arg0 -> arg1, 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: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int64"}, // arg0|aux
{name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64"}, // arg0^aux {name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64"}, // arg0^aux

View file

@ -1804,11 +1804,25 @@
// Later passes (deadstore, elim unread auto) will remove the A -> B move, if possible. // 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 // This happens most commonly when B is an autotmp inserted earlier
// during compilation to ensure correctness. // during compilation to ensure correctness.
(Move {t1} [s1] dst tmp1 midmem:(Move {t2} [s2] tmp2 src _)) // Take care that overlapping moves are preserved.
&& s1 == s2 // 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 && t1.(*types.Type).Compare(t2.(*types.Type)) == types.CMPeq
&& isSamePtr(tmp1, tmp2) && 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). // 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. // However, this rule is needed to prevent the previous rule from looping forever in such cases.

View file

@ -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: "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: "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: "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: "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. {name: "AtomicOr8", argLength: 3, typ: "Mem", hasSideEffects: true}, // *arg0 |= arg1. arg2=memory. Returns memory.

View file

@ -6,7 +6,7 @@
// This program generates Go code that applies rewrite rules to a Value. // This program generates Go code that applies rewrite rules to a Value.
// The generated code implements a function of type func (v *Value) bool // 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 // Ideas stolen from Swift: http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-2000-2.html
package main 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 { func genMatch(w io.Writer, arch arch, match string, loc string) bool {
return genMatch0(w, arch, match, "v", map[string]struct{}{}, true, loc) return genMatch0(w, arch, match, "v", map[string]struct{}{}, true, loc)
} }
@ -623,7 +623,7 @@ outer:
return r 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 { func isBlock(name string, arch arch) bool {
for _, b := range genericBlocks { for _, b := range genericBlocks {
if b.name == name { 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 { func unbalanced(s string) bool {
var left, right int var left, right int
for _, c := range s { for _, c := range s {

View file

@ -1663,10 +1663,13 @@ const (
OpPPC64MTVSRD OpPPC64MTVSRD
OpPPC64AND OpPPC64AND
OpPPC64ANDN OpPPC64ANDN
OpPPC64ANDCC
OpPPC64OR OpPPC64OR
OpPPC64ORN OpPPC64ORN
OpPPC64ORCC
OpPPC64NOR OpPPC64NOR
OpPPC64XOR OpPPC64XOR
OpPPC64XORCC
OpPPC64EQV OpPPC64EQV
OpPPC64NEG OpPPC64NEG
OpPPC64FNEG 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", name: "OR",
argLen: 2, 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", name: "NOR",
argLen: 2, 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", name: "EQV",
argLen: 2, argLen: 2,

View file

@ -781,7 +781,7 @@ func (po *poset) DotDump(fn string, title string) error {
return nil return nil
} }
// Ordered returns true if n1<n2. It returns false either when it is // Ordered reports whether n1<n2. It returns false either when it is
// certain that n1<n2 is false, or if there is not enough information // certain that n1<n2 is false, or if there is not enough information
// to tell. // to tell.
// Complexity is O(n). // Complexity is O(n).
@ -799,7 +799,7 @@ func (po *poset) Ordered(n1, n2 *Value) bool {
return i1 != i2 && po.dominates(i1, i2, true) return i1 != i2 && po.dominates(i1, i2, true)
} }
// Ordered returns true if n1<=n2. It returns false either when it is // Ordered reports whether n1<=n2. It returns false either when it is
// certain that n1<=n2 is false, or if there is not enough information // certain that n1<=n2 is false, or if there is not enough information
// to tell. // to tell.
// Complexity is O(n). // Complexity is O(n).
@ -818,7 +818,7 @@ func (po *poset) OrderedOrEqual(n1, n2 *Value) bool {
(po.dominates(i2, i1, false) && !po.dominates(i2, i1, true)) (po.dominates(i2, i1, false) && !po.dominates(i2, i1, true))
} }
// Equal returns true if n1==n2. It returns false either when it is // Equal reports whether n1==n2. It returns false either when it is
// certain that n1==n2 is false, or if there is not enough information // certain that n1==n2 is false, or if there is not enough information
// to tell. // to tell.
// Complexity is O(1). // Complexity is O(1).
@ -832,7 +832,7 @@ func (po *poset) Equal(n1, n2 *Value) bool {
return f1 && f2 && i1 == i2 return f1 && f2 && i1 == i2
} }
// NonEqual returns true if n1!=n2. It returns false either when it is // NonEqual reports whether n1!=n2. It returns false either when it is
// certain that n1!=n2 is false, or if there is not enough information // certain that n1!=n2 is false, or if there is not enough information
// to tell. // to tell.
// Complexity is O(n) (because it internally calls Ordered to see if we // Complexity is O(n) (because it internally calls Ordered to see if we

View file

@ -485,7 +485,7 @@ func auxTo64F(i int64) float64 {
return math.Float64frombits(uint64(i)) return math.Float64frombits(uint64(i))
} }
// uaddOvf returns true if unsigned a+b would overflow. // uaddOvf reports whether unsigned a+b would overflow.
func uaddOvf(a, b int64) bool { func uaddOvf(a, b int64) bool {
return uint64(a)+uint64(b) < uint64(a) return uint64(a)+uint64(b) < uint64(a)
} }
@ -530,6 +530,13 @@ func isSamePtr(p1, p2 *Value) bool {
return false return false
} }
func isStackPtr(v *Value) bool {
for v.Op == OpOffPtr || v.Op == OpAddPtr {
v = v.Args[0]
}
return v.Op == OpSP || v.Op == OpLocalAddr
}
// disjoint reports whether the memory region specified by [p1:p1+n1) // disjoint reports whether the memory region specified by [p1:p1+n1)
// does not overlap with [p2:p2+n2). // does not overlap with [p2:p2+n2).
// A return value of false does not imply the regions overlap. // A return value of false does not imply the regions overlap.
@ -542,7 +549,7 @@ func disjoint(p1 *Value, n1 int64, p2 *Value, n2 int64) bool {
} }
baseAndOffset := func(ptr *Value) (base *Value, offset int64) { baseAndOffset := func(ptr *Value) (base *Value, offset int64) {
base, offset = ptr, 0 base, offset = ptr, 0
if base.Op == OpOffPtr { for base.Op == OpOffPtr {
offset += base.AuxInt offset += base.AuxInt
base = base.Args[0] base = base.Args[0]
} }

View file

@ -30996,6 +30996,143 @@ func rewriteBlockPPC64(b *Block) bool {
b.Aux = nil b.Aux = nil
return true return true
} }
// match: (EQ (CMPconst [0] (ANDconst [c] x)) yes no)
// cond:
// result: (EQ (ANDCCconst [c] x) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPconst {
break
}
if v.AuxInt != 0 {
break
}
v_0 := v.Args[0]
if v_0.Op != OpPPC64ANDconst {
break
}
c := v_0.AuxInt
x := v_0.Args[0]
b.Kind = BlockPPC64EQ
v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.TypeFlags)
v0.AuxInt = c
v0.AddArg(x)
b.SetControl(v0)
b.Aux = nil
return true
}
// match: (EQ (CMPWconst [0] (ANDconst [c] x)) yes no)
// cond:
// result: (EQ (ANDCCconst [c] x) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPWconst {
break
}
if v.AuxInt != 0 {
break
}
v_0 := v.Args[0]
if v_0.Op != OpPPC64ANDconst {
break
}
c := v_0.AuxInt
x := v_0.Args[0]
b.Kind = BlockPPC64EQ
v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.TypeFlags)
v0.AuxInt = c
v0.AddArg(x)
b.SetControl(v0)
b.Aux = nil
return true
}
// match: (EQ (CMPconst [0] z:(AND x y)) yes no)
// cond: z.Uses == 1
// result: (EQ (ANDCC x y) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPconst {
break
}
if v.AuxInt != 0 {
break
}
z := v.Args[0]
if z.Op != OpPPC64AND {
break
}
_ = z.Args[1]
x := z.Args[0]
y := z.Args[1]
if !(z.Uses == 1) {
break
}
b.Kind = BlockPPC64EQ
v0 := b.NewValue0(v.Pos, OpPPC64ANDCC, types.TypeFlags)
v0.AddArg(x)
v0.AddArg(y)
b.SetControl(v0)
b.Aux = nil
return true
}
// match: (EQ (CMPconst [0] z:(OR x y)) yes no)
// cond: z.Uses == 1
// result: (EQ (ORCC x y) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPconst {
break
}
if v.AuxInt != 0 {
break
}
z := v.Args[0]
if z.Op != OpPPC64OR {
break
}
_ = z.Args[1]
x := z.Args[0]
y := z.Args[1]
if !(z.Uses == 1) {
break
}
b.Kind = BlockPPC64EQ
v0 := b.NewValue0(v.Pos, OpPPC64ORCC, types.TypeFlags)
v0.AddArg(x)
v0.AddArg(y)
b.SetControl(v0)
b.Aux = nil
return true
}
// match: (EQ (CMPconst [0] z:(XOR x y)) yes no)
// cond: z.Uses == 1
// result: (EQ (XORCC x y) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPconst {
break
}
if v.AuxInt != 0 {
break
}
z := v.Args[0]
if z.Op != OpPPC64XOR {
break
}
_ = z.Args[1]
x := z.Args[0]
y := z.Args[1]
if !(z.Uses == 1) {
break
}
b.Kind = BlockPPC64EQ
v0 := b.NewValue0(v.Pos, OpPPC64XORCC, types.TypeFlags)
v0.AddArg(x)
v0.AddArg(y)
b.SetControl(v0)
b.Aux = nil
return true
}
case BlockPPC64GE: case BlockPPC64GE:
// match: (GE (FlagEQ) yes no) // match: (GE (FlagEQ) yes no)
// cond: // cond:
@ -31051,6 +31188,143 @@ func rewriteBlockPPC64(b *Block) bool {
b.Aux = nil b.Aux = nil
return true return true
} }
// match: (GE (CMPconst [0] (ANDconst [c] x)) yes no)
// cond:
// result: (GE (ANDCCconst [c] x) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPconst {
break
}
if v.AuxInt != 0 {
break
}
v_0 := v.Args[0]
if v_0.Op != OpPPC64ANDconst {
break
}
c := v_0.AuxInt
x := v_0.Args[0]
b.Kind = BlockPPC64GE
v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.TypeFlags)
v0.AuxInt = c
v0.AddArg(x)
b.SetControl(v0)
b.Aux = nil
return true
}
// match: (GE (CMPWconst [0] (ANDconst [c] x)) yes no)
// cond:
// result: (GE (ANDCCconst [c] x) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPWconst {
break
}
if v.AuxInt != 0 {
break
}
v_0 := v.Args[0]
if v_0.Op != OpPPC64ANDconst {
break
}
c := v_0.AuxInt
x := v_0.Args[0]
b.Kind = BlockPPC64GE
v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.TypeFlags)
v0.AuxInt = c
v0.AddArg(x)
b.SetControl(v0)
b.Aux = nil
return true
}
// match: (GE (CMPconst [0] z:(AND x y)) yes no)
// cond: z.Uses == 1
// result: (GE (ANDCC x y) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPconst {
break
}
if v.AuxInt != 0 {
break
}
z := v.Args[0]
if z.Op != OpPPC64AND {
break
}
_ = z.Args[1]
x := z.Args[0]
y := z.Args[1]
if !(z.Uses == 1) {
break
}
b.Kind = BlockPPC64GE
v0 := b.NewValue0(v.Pos, OpPPC64ANDCC, types.TypeFlags)
v0.AddArg(x)
v0.AddArg(y)
b.SetControl(v0)
b.Aux = nil
return true
}
// match: (GE (CMPconst [0] z:(OR x y)) yes no)
// cond: z.Uses == 1
// result: (GE (ORCC x y) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPconst {
break
}
if v.AuxInt != 0 {
break
}
z := v.Args[0]
if z.Op != OpPPC64OR {
break
}
_ = z.Args[1]
x := z.Args[0]
y := z.Args[1]
if !(z.Uses == 1) {
break
}
b.Kind = BlockPPC64GE
v0 := b.NewValue0(v.Pos, OpPPC64ORCC, types.TypeFlags)
v0.AddArg(x)
v0.AddArg(y)
b.SetControl(v0)
b.Aux = nil
return true
}
// match: (GE (CMPconst [0] z:(XOR x y)) yes no)
// cond: z.Uses == 1
// result: (GE (XORCC x y) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPconst {
break
}
if v.AuxInt != 0 {
break
}
z := v.Args[0]
if z.Op != OpPPC64XOR {
break
}
_ = z.Args[1]
x := z.Args[0]
y := z.Args[1]
if !(z.Uses == 1) {
break
}
b.Kind = BlockPPC64GE
v0 := b.NewValue0(v.Pos, OpPPC64XORCC, types.TypeFlags)
v0.AddArg(x)
v0.AddArg(y)
b.SetControl(v0)
b.Aux = nil
return true
}
case BlockPPC64GT: case BlockPPC64GT:
// match: (GT (FlagEQ) yes no) // match: (GT (FlagEQ) yes no)
// cond: // cond:
@ -31107,6 +31381,143 @@ func rewriteBlockPPC64(b *Block) bool {
b.Aux = nil b.Aux = nil
return true return true
} }
// match: (GT (CMPconst [0] (ANDconst [c] x)) yes no)
// cond:
// result: (GT (ANDCCconst [c] x) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPconst {
break
}
if v.AuxInt != 0 {
break
}
v_0 := v.Args[0]
if v_0.Op != OpPPC64ANDconst {
break
}
c := v_0.AuxInt
x := v_0.Args[0]
b.Kind = BlockPPC64GT
v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.TypeFlags)
v0.AuxInt = c
v0.AddArg(x)
b.SetControl(v0)
b.Aux = nil
return true
}
// match: (GT (CMPWconst [0] (ANDconst [c] x)) yes no)
// cond:
// result: (GT (ANDCCconst [c] x) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPWconst {
break
}
if v.AuxInt != 0 {
break
}
v_0 := v.Args[0]
if v_0.Op != OpPPC64ANDconst {
break
}
c := v_0.AuxInt
x := v_0.Args[0]
b.Kind = BlockPPC64GT
v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.TypeFlags)
v0.AuxInt = c
v0.AddArg(x)
b.SetControl(v0)
b.Aux = nil
return true
}
// match: (GT (CMPconst [0] z:(AND x y)) yes no)
// cond: z.Uses == 1
// result: (GT (ANDCC x y) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPconst {
break
}
if v.AuxInt != 0 {
break
}
z := v.Args[0]
if z.Op != OpPPC64AND {
break
}
_ = z.Args[1]
x := z.Args[0]
y := z.Args[1]
if !(z.Uses == 1) {
break
}
b.Kind = BlockPPC64GT
v0 := b.NewValue0(v.Pos, OpPPC64ANDCC, types.TypeFlags)
v0.AddArg(x)
v0.AddArg(y)
b.SetControl(v0)
b.Aux = nil
return true
}
// match: (GT (CMPconst [0] z:(OR x y)) yes no)
// cond: z.Uses == 1
// result: (GT (ORCC x y) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPconst {
break
}
if v.AuxInt != 0 {
break
}
z := v.Args[0]
if z.Op != OpPPC64OR {
break
}
_ = z.Args[1]
x := z.Args[0]
y := z.Args[1]
if !(z.Uses == 1) {
break
}
b.Kind = BlockPPC64GT
v0 := b.NewValue0(v.Pos, OpPPC64ORCC, types.TypeFlags)
v0.AddArg(x)
v0.AddArg(y)
b.SetControl(v0)
b.Aux = nil
return true
}
// match: (GT (CMPconst [0] z:(XOR x y)) yes no)
// cond: z.Uses == 1
// result: (GT (XORCC x y) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPconst {
break
}
if v.AuxInt != 0 {
break
}
z := v.Args[0]
if z.Op != OpPPC64XOR {
break
}
_ = z.Args[1]
x := z.Args[0]
y := z.Args[1]
if !(z.Uses == 1) {
break
}
b.Kind = BlockPPC64GT
v0 := b.NewValue0(v.Pos, OpPPC64XORCC, types.TypeFlags)
v0.AddArg(x)
v0.AddArg(y)
b.SetControl(v0)
b.Aux = nil
return true
}
case BlockIf: case BlockIf:
// match: (If (Equal cc) yes no) // match: (If (Equal cc) yes no)
// cond: // cond:
@ -31318,6 +31729,143 @@ func rewriteBlockPPC64(b *Block) bool {
b.Aux = nil b.Aux = nil
return true return true
} }
// match: (LE (CMPconst [0] (ANDconst [c] x)) yes no)
// cond:
// result: (LE (ANDCCconst [c] x) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPconst {
break
}
if v.AuxInt != 0 {
break
}
v_0 := v.Args[0]
if v_0.Op != OpPPC64ANDconst {
break
}
c := v_0.AuxInt
x := v_0.Args[0]
b.Kind = BlockPPC64LE
v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.TypeFlags)
v0.AuxInt = c
v0.AddArg(x)
b.SetControl(v0)
b.Aux = nil
return true
}
// match: (LE (CMPWconst [0] (ANDconst [c] x)) yes no)
// cond:
// result: (LE (ANDCCconst [c] x) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPWconst {
break
}
if v.AuxInt != 0 {
break
}
v_0 := v.Args[0]
if v_0.Op != OpPPC64ANDconst {
break
}
c := v_0.AuxInt
x := v_0.Args[0]
b.Kind = BlockPPC64LE
v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.TypeFlags)
v0.AuxInt = c
v0.AddArg(x)
b.SetControl(v0)
b.Aux = nil
return true
}
// match: (LE (CMPconst [0] z:(AND x y)) yes no)
// cond: z.Uses == 1
// result: (LE (ANDCC x y) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPconst {
break
}
if v.AuxInt != 0 {
break
}
z := v.Args[0]
if z.Op != OpPPC64AND {
break
}
_ = z.Args[1]
x := z.Args[0]
y := z.Args[1]
if !(z.Uses == 1) {
break
}
b.Kind = BlockPPC64LE
v0 := b.NewValue0(v.Pos, OpPPC64ANDCC, types.TypeFlags)
v0.AddArg(x)
v0.AddArg(y)
b.SetControl(v0)
b.Aux = nil
return true
}
// match: (LE (CMPconst [0] z:(OR x y)) yes no)
// cond: z.Uses == 1
// result: (LE (ORCC x y) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPconst {
break
}
if v.AuxInt != 0 {
break
}
z := v.Args[0]
if z.Op != OpPPC64OR {
break
}
_ = z.Args[1]
x := z.Args[0]
y := z.Args[1]
if !(z.Uses == 1) {
break
}
b.Kind = BlockPPC64LE
v0 := b.NewValue0(v.Pos, OpPPC64ORCC, types.TypeFlags)
v0.AddArg(x)
v0.AddArg(y)
b.SetControl(v0)
b.Aux = nil
return true
}
// match: (LE (CMPconst [0] z:(XOR x y)) yes no)
// cond: z.Uses == 1
// result: (LE (XORCC x y) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPconst {
break
}
if v.AuxInt != 0 {
break
}
z := v.Args[0]
if z.Op != OpPPC64XOR {
break
}
_ = z.Args[1]
x := z.Args[0]
y := z.Args[1]
if !(z.Uses == 1) {
break
}
b.Kind = BlockPPC64LE
v0 := b.NewValue0(v.Pos, OpPPC64XORCC, types.TypeFlags)
v0.AddArg(x)
v0.AddArg(y)
b.SetControl(v0)
b.Aux = nil
return true
}
case BlockPPC64LT: case BlockPPC64LT:
// match: (LT (FlagEQ) yes no) // match: (LT (FlagEQ) yes no)
// cond: // cond:
@ -31374,6 +31922,143 @@ func rewriteBlockPPC64(b *Block) bool {
b.Aux = nil b.Aux = nil
return true return true
} }
// match: (LT (CMPconst [0] (ANDconst [c] x)) yes no)
// cond:
// result: (LT (ANDCCconst [c] x) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPconst {
break
}
if v.AuxInt != 0 {
break
}
v_0 := v.Args[0]
if v_0.Op != OpPPC64ANDconst {
break
}
c := v_0.AuxInt
x := v_0.Args[0]
b.Kind = BlockPPC64LT
v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.TypeFlags)
v0.AuxInt = c
v0.AddArg(x)
b.SetControl(v0)
b.Aux = nil
return true
}
// match: (LT (CMPWconst [0] (ANDconst [c] x)) yes no)
// cond:
// result: (LT (ANDCCconst [c] x) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPWconst {
break
}
if v.AuxInt != 0 {
break
}
v_0 := v.Args[0]
if v_0.Op != OpPPC64ANDconst {
break
}
c := v_0.AuxInt
x := v_0.Args[0]
b.Kind = BlockPPC64LT
v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.TypeFlags)
v0.AuxInt = c
v0.AddArg(x)
b.SetControl(v0)
b.Aux = nil
return true
}
// match: (LT (CMPconst [0] z:(AND x y)) yes no)
// cond: z.Uses == 1
// result: (LT (ANDCC x y) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPconst {
break
}
if v.AuxInt != 0 {
break
}
z := v.Args[0]
if z.Op != OpPPC64AND {
break
}
_ = z.Args[1]
x := z.Args[0]
y := z.Args[1]
if !(z.Uses == 1) {
break
}
b.Kind = BlockPPC64LT
v0 := b.NewValue0(v.Pos, OpPPC64ANDCC, types.TypeFlags)
v0.AddArg(x)
v0.AddArg(y)
b.SetControl(v0)
b.Aux = nil
return true
}
// match: (LT (CMPconst [0] z:(OR x y)) yes no)
// cond: z.Uses == 1
// result: (LT (ORCC x y) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPconst {
break
}
if v.AuxInt != 0 {
break
}
z := v.Args[0]
if z.Op != OpPPC64OR {
break
}
_ = z.Args[1]
x := z.Args[0]
y := z.Args[1]
if !(z.Uses == 1) {
break
}
b.Kind = BlockPPC64LT
v0 := b.NewValue0(v.Pos, OpPPC64ORCC, types.TypeFlags)
v0.AddArg(x)
v0.AddArg(y)
b.SetControl(v0)
b.Aux = nil
return true
}
// match: (LT (CMPconst [0] z:(XOR x y)) yes no)
// cond: z.Uses == 1
// result: (LT (XORCC x y) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPconst {
break
}
if v.AuxInt != 0 {
break
}
z := v.Args[0]
if z.Op != OpPPC64XOR {
break
}
_ = z.Args[1]
x := z.Args[0]
y := z.Args[1]
if !(z.Uses == 1) {
break
}
b.Kind = BlockPPC64LT
v0 := b.NewValue0(v.Pos, OpPPC64XORCC, types.TypeFlags)
v0.AddArg(x)
v0.AddArg(y)
b.SetControl(v0)
b.Aux = nil
return true
}
case BlockPPC64NE: case BlockPPC64NE:
// match: (NE (CMPWconst [0] (Equal cc)) yes no) // match: (NE (CMPWconst [0] (Equal cc)) yes no)
// cond: // cond:
@ -31689,6 +32374,143 @@ func rewriteBlockPPC64(b *Block) bool {
b.Aux = nil b.Aux = nil
return true return true
} }
// match: (NE (CMPconst [0] (ANDconst [c] x)) yes no)
// cond:
// result: (NE (ANDCCconst [c] x) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPconst {
break
}
if v.AuxInt != 0 {
break
}
v_0 := v.Args[0]
if v_0.Op != OpPPC64ANDconst {
break
}
c := v_0.AuxInt
x := v_0.Args[0]
b.Kind = BlockPPC64NE
v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.TypeFlags)
v0.AuxInt = c
v0.AddArg(x)
b.SetControl(v0)
b.Aux = nil
return true
}
// match: (NE (CMPWconst [0] (ANDconst [c] x)) yes no)
// cond:
// result: (NE (ANDCCconst [c] x) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPWconst {
break
}
if v.AuxInt != 0 {
break
}
v_0 := v.Args[0]
if v_0.Op != OpPPC64ANDconst {
break
}
c := v_0.AuxInt
x := v_0.Args[0]
b.Kind = BlockPPC64NE
v0 := b.NewValue0(v.Pos, OpPPC64ANDCCconst, types.TypeFlags)
v0.AuxInt = c
v0.AddArg(x)
b.SetControl(v0)
b.Aux = nil
return true
}
// match: (NE (CMPconst [0] z:(AND x y)) yes no)
// cond: z.Uses == 1
// result: (NE (ANDCC x y) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPconst {
break
}
if v.AuxInt != 0 {
break
}
z := v.Args[0]
if z.Op != OpPPC64AND {
break
}
_ = z.Args[1]
x := z.Args[0]
y := z.Args[1]
if !(z.Uses == 1) {
break
}
b.Kind = BlockPPC64NE
v0 := b.NewValue0(v.Pos, OpPPC64ANDCC, types.TypeFlags)
v0.AddArg(x)
v0.AddArg(y)
b.SetControl(v0)
b.Aux = nil
return true
}
// match: (NE (CMPconst [0] z:(OR x y)) yes no)
// cond: z.Uses == 1
// result: (NE (ORCC x y) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPconst {
break
}
if v.AuxInt != 0 {
break
}
z := v.Args[0]
if z.Op != OpPPC64OR {
break
}
_ = z.Args[1]
x := z.Args[0]
y := z.Args[1]
if !(z.Uses == 1) {
break
}
b.Kind = BlockPPC64NE
v0 := b.NewValue0(v.Pos, OpPPC64ORCC, types.TypeFlags)
v0.AddArg(x)
v0.AddArg(y)
b.SetControl(v0)
b.Aux = nil
return true
}
// match: (NE (CMPconst [0] z:(XOR x y)) yes no)
// cond: z.Uses == 1
// result: (NE (XORCC x y) yes no)
for {
v := b.Control
if v.Op != OpPPC64CMPconst {
break
}
if v.AuxInt != 0 {
break
}
z := v.Args[0]
if z.Op != OpPPC64XOR {
break
}
_ = z.Args[1]
x := z.Args[0]
y := z.Args[1]
if !(z.Uses == 1) {
break
}
b.Kind = BlockPPC64NE
v0 := b.NewValue0(v.Pos, OpPPC64XORCC, types.TypeFlags)
v0.AddArg(x)
v0.AddArg(y)
b.SetControl(v0)
b.Aux = nil
return true
}
} }
return false return false
} }

View file

@ -17234,6 +17234,8 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
func rewriteValuegeneric_OpMove_20(v *Value) bool { func rewriteValuegeneric_OpMove_20(v *Value) bool {
b := v.Block b := v.Block
_ = b _ = b
config := b.Func.Config
_ = config
// match: (Move {t1} [n] dst p1 mem:(VarDef (Store {t2} (OffPtr <tt2> [o2] p2) d1 (Store {t3} (OffPtr <tt3> [o3] p3) d2 (Store {t4} (OffPtr <tt4> [o4] p4) d3 (Store {t5} (OffPtr <tt5> [o5] p5) d4 (Zero {t6} [n] p6 _))))))) // match: (Move {t1} [n] dst p1 mem:(VarDef (Store {t2} (OffPtr <tt2> [o2] p2) d1 (Store {t3} (OffPtr <tt3> [o3] p3) d2 (Store {t4} (OffPtr <tt4> [o4] p4) d3 (Store {t5} (OffPtr <tt5> [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) // 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 <tt2> [o2] dst) d1 (Store {t3} (OffPtr <tt3> [o3] dst) d2 (Store {t4} (OffPtr <tt4> [o4] dst) d3 (Store {t5} (OffPtr <tt5> [o5] dst) d4 (Zero {t1} [n] dst mem))))) // result: (Store {t2} (OffPtr <tt2> [o2] dst) d1 (Store {t3} (OffPtr <tt3> [o3] dst) d2 (Store {t4} (OffPtr <tt4> [o4] dst) d3 (Store {t5} (OffPtr <tt5> [o5] dst) d4 (Zero {t1} [n] dst mem)))))
@ -17355,11 +17357,11 @@ func rewriteValuegeneric_OpMove_20(v *Value) bool {
v.AddArg(v1) v.AddArg(v1)
return true return true
} }
// match: (Move {t1} [s1] dst tmp1 midmem:(Move {t2} [s2] tmp2 src _)) // match: (Move {t1} [s] dst tmp1 midmem:(Move {t2} [s] tmp2 src _))
// cond: s1 == s2 && t1.(*types.Type).Compare(t2.(*types.Type)) == types.CMPeq && isSamePtr(tmp1, tmp2) // 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} [s1] dst src midmem) // result: (Move {t1} [s] dst src midmem)
for { for {
s1 := v.AuxInt s := v.AuxInt
t1 := v.Aux t1 := v.Aux
_ = v.Args[2] _ = v.Args[2]
dst := v.Args[0] dst := v.Args[0]
@ -17368,16 +17370,53 @@ func rewriteValuegeneric_OpMove_20(v *Value) bool {
if midmem.Op != OpMove { if midmem.Op != OpMove {
break break
} }
s2 := midmem.AuxInt if midmem.AuxInt != s {
break
}
t2 := midmem.Aux t2 := midmem.Aux
_ = midmem.Args[2] _ = midmem.Args[2]
tmp2 := midmem.Args[0] tmp2 := midmem.Args[0]
src := midmem.Args[1] 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 break
} }
v.reset(OpMove) 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.Aux = t1
v.AddArg(dst) v.AddArg(dst)
v.AddArg(src) v.AddArg(src)

View file

@ -58,11 +58,13 @@
87: if a == 0 { //gdb-opt=(a,n,t) 87: if a == 0 { //gdb-opt=(a,n,t)
86: for i, a := range hist { 86: for i, a := range hist {
87: if a == 0 { //gdb-opt=(a,n,t) 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 91: n += a
90: t += i * 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) 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 { 86: for i, a := range hist {
87: if a == 0 { //gdb-opt=(a,n,t) 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 91: n += a
90: t += i * 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) 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) 87: if a == 0 { //gdb-opt=(a,n,t)
86: for i, a := range hist { 86: for i, a := range hist {
87: if a == 0 { //gdb-opt=(a,n,t) 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 91: n += a
90: t += i * 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) 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 { 86: for i, a := range hist {
87: if a == 0 { //gdb-opt=(a,n,t) 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 91: n += a
90: t += i * 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) 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)

View file

@ -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) 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 91: n += a
90: t += i * 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 { 86: for i, a := range hist {
87: if a == 0 { //gdb-opt=(a,n,t) 87: if a == 0 { //gdb-opt=(a,n,t)
a = 3 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) 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 91: n += a
90: t += i * 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 { 86: for i, a := range hist {
87: if a == 0 { //gdb-opt=(a,n,t) 87: if a == 0 { //gdb-opt=(a,n,t)
a = 0 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) 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 91: n += a
90: t += i * 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 { 86: for i, a := range hist {
87: if a == 0 { //gdb-opt=(a,n,t) 87: if a == 0 { //gdb-opt=(a,n,t)
a = 1 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) 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 91: n += a
90: t += i * 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 { 86: for i, a := range hist {
87: if a == 0 { //gdb-opt=(a,n,t) 87: if a == 0 { //gdb-opt=(a,n,t)
a = 0 a = 0

View file

@ -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 // instructions
func emptyBlock(b *Block) bool { func emptyBlock(b *Block) bool {
for _, v := range b.Values { for _, v := range b.Values {
@ -105,7 +105,7 @@ func emptyBlock(b *Block) bool {
return true 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: // subject to the following criteria:
// - it should not be the first block // - it should not be the first block
// - it should be BlockPlain // - it should be BlockPlain

View file

@ -149,8 +149,11 @@ type Type struct {
Nod *Node // canonical OTYPE node Nod *Node // canonical OTYPE node
Orig *Type // original type (type literal or predefined type) Orig *Type // original type (type literal or predefined type)
SliceOf *Type // Cache of composite types, with this type being the element type.
PtrBase *Type Cache struct {
ptr *Type // *T, or nil
slice *Type // []T, or nil
}
Sym *Sym // symbol containing name, for named types Sym *Sym // symbol containing name, for named types
Vargen int32 // unique name for OTYPE/ONAME 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. // NewSlice returns the slice Type with element type elem.
func NewSlice(elem *Type) *Type { func NewSlice(elem *Type) *Type {
if t := elem.SliceOf; t != nil { if t := elem.Cache.slice; t != nil {
if t.Elem() != elem { if t.Elem() != elem {
Fatalf("elem mismatch") Fatalf("elem mismatch")
} }
@ -497,7 +500,7 @@ func NewSlice(elem *Type) *Type {
t := New(TSLICE) t := New(TSLICE)
t.Extra = Slice{Elem: elem} t.Extra = Slice{Elem: elem}
elem.SliceOf = t elem.Cache.slice = t
return t return t
} }
@ -551,7 +554,7 @@ func NewPtr(elem *Type) *Type {
Fatalf("NewPtr: pointer to elem Type is nil") 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 { if t.Elem() != elem {
Fatalf("NewPtr: elem mismatch") Fatalf("NewPtr: elem mismatch")
} }
@ -563,7 +566,7 @@ func NewPtr(elem *Type) *Type {
t.Width = int64(Widthptr) t.Width = int64(Widthptr)
t.Align = uint8(Widthptr) t.Align = uint8(Widthptr)
if NewPtrCacheEnabled { if NewPtrCacheEnabled {
elem.PtrBase = t elem.Cache.ptr = t
} }
return t return t
} }
@ -662,23 +665,18 @@ func SubstAny(t *Type, types *[]*Type) *Type {
} }
case TSTRUCT: 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() fields := t.FieldSlice()
var nfs []*Field nfs := make([]*Field, len(fields))
for i, f := range fields { for i, f := range fields {
nft := SubstAny(f.Type, types) nft := SubstAny(f.Type, types)
if nft == f.Type {
continue
}
if nfs == nil {
nfs = append([]*Field(nil), fields...)
}
nfs[i] = f.Copy() nfs[i] = f.Copy()
nfs[i].Type = nft nfs[i].Type = nft
} }
if nfs != nil { t = t.copy()
t = t.copy() t.SetFields(nfs)
t.SetFields(nfs)
}
} }
return t return t
@ -1258,6 +1256,11 @@ func (t *Type) IsPtr() bool {
return t.Etype == TPTR 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. // IsUnsafePtr reports whether t is an unsafe pointer.
func (t *Type) IsUnsafePtr() bool { func (t *Type) IsUnsafePtr() bool {
return t.Etype == TUNSAFEPTR return t.Etype == TUNSAFEPTR

View file

@ -478,7 +478,7 @@ func newPkgDot(pos token.Pos, pkg, name string) ast.Expr {
} }
// renameTop renames all references to the top-level name old. // 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 { func renameTop(f *ast.File, old, new string) bool {
var fixed bool var fixed bool

View file

@ -972,6 +972,8 @@
// and -dropreplace editing flags may be repeated, and the changes // and -dropreplace editing flags may be repeated, and the changes
// are applied in the order given. // 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 // The -print flag prints the final go.mod in its text format instead of
// writing it back to go.mod. // writing it back to go.mod.
// //
@ -984,7 +986,8 @@
// } // }
// //
// type GoMod struct { // type GoMod struct {
// Module Module // Module Module
// Go string
// Require []Require // Require []Require
// Exclude []Module // Exclude []Module
// Replace []Replace // Replace []Replace
@ -1604,17 +1607,20 @@
// verb followed by arguments. For example: // verb followed by arguments. For example:
// //
// module my/thing // module my/thing
// go 1.12
// require other/thing v1.0.2 // 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 // exclude old/thing v1.2.3
// replace bad/thing v1.4.5 => good/thing v1.4.5 // replace bad/thing v1.4.5 => good/thing v1.4.5
// //
// The verbs are module, to define the module path; require, to require // The verbs are
// a particular module at a given version or later; exclude, to exclude // module, to define the module path;
// a particular module version from use; and replace, to replace a module // go, to set the expected language version;
// version with a different module version. Exclude and replace apply only // require, to require a particular module at a given version or later;
// in the main module's go.mod and are ignored in dependencies. // exclude, to exclude a particular module version from use; and
// See https://research.swtch.com/vgo-mvs for details. // 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, // The leading verb can be factored out of adjacent lines to create a block,
// like in Go imports: // like in Go imports:

View file

@ -123,7 +123,7 @@ var hashFileCache struct {
m map[string][HashSize]byte 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, // It caches repeated lookups for a given file,
// and the cache entry for a file can be initialized // and the cache entry for a file can be initialized
// using SetFileHash. // using SetFileHash.

View file

@ -79,15 +79,15 @@ func AddKnownFlags(cmd string, defns []*Defn) {
// Parse sees if argument i is present in the definitions and if so, // Parse sees if argument i is present in the definitions and if so,
// returns its definition, value, and whether it consumed an extra word. // 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. // If the flag begins (cmd.Name()+".") 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) { func Parse(cmd string, usage func(), defns []*Defn, args []string, i int) (f *Defn, value string, extra bool) {
arg := args[i] arg := args[i]
if strings.HasPrefix(arg, "--") { // reduce two minuses to one if strings.HasPrefix(arg, "--") { // reduce two minuses to one
arg = arg[1:] arg = arg[1:]
} }
switch arg { switch arg {
case "-?", "-h", "-help": case "-?", "-h", "-help":
base.Usage() usage()
} }
if arg == "" || arg[0] != '-' { if arg == "" || arg[0] != '-' {
return return

View file

@ -62,6 +62,8 @@ The -require, -droprequire, -exclude, -dropexclude, -replace,
and -dropreplace editing flags may be repeated, and the changes and -dropreplace editing flags may be repeated, and the changes
are applied in the order given. 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 The -print flag prints the final go.mod in its text format instead of
writing it back to go.mod. 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 { type GoMod struct {
Module Module Module Module
Go string
Require []Require Require []Require
Exclude []Module Exclude []Module
Replace []Replace Replace []Replace
@ -102,8 +105,8 @@ by invoking 'go mod edit' with -require, -exclude, and so on.
} }
var ( var (
editFmt = cmdEdit.Flag.Bool("fmt", false, "") editFmt = cmdEdit.Flag.Bool("fmt", false, "")
// editGo = cmdEdit.Flag.String("go", "", "") editGo = cmdEdit.Flag.String("go", "", "")
editJSON = cmdEdit.Flag.Bool("json", false, "") editJSON = cmdEdit.Flag.Bool("json", false, "")
editPrint = cmdEdit.Flag.Bool("print", false, "") editPrint = cmdEdit.Flag.Bool("print", false, "")
editModule = cmdEdit.Flag.String("module", "", "") editModule = cmdEdit.Flag.String("module", "", "")
@ -131,6 +134,7 @@ func init() {
func runEdit(cmd *base.Command, args []string) { func runEdit(cmd *base.Command, args []string) {
anyFlags := anyFlags :=
*editModule != "" || *editModule != "" ||
*editGo != "" ||
*editJSON || *editJSON ||
*editPrint || *editPrint ||
*editFmt || *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) data, err := ioutil.ReadFile(gomod)
if err != nil { if err != nil {
@ -177,6 +185,12 @@ func runEdit(cmd *base.Command, args []string) {
modFile.AddModuleStmt(modload.CmdModModule) modFile.AddModuleStmt(modload.CmdModModule)
} }
if *editGo != "" {
if err := modFile.AddGoStmt(*editGo); err != nil {
base.Fatalf("go: internal error: %v", err)
}
}
if len(edits) > 0 { if len(edits) > 0 {
for _, edit := range edits { for _, edit := range edits {
edit(modFile) edit(modFile)
@ -344,6 +358,7 @@ func flagDropReplace(arg string) {
// fileJSON is the -json output data structure. // fileJSON is the -json output data structure.
type fileJSON struct { type fileJSON struct {
Module module.Version Module module.Version
Go string `json:",omitempty"`
Require []requireJSON Require []requireJSON
Exclude []module.Version Exclude []module.Version
Replace []replaceJSON Replace []replaceJSON
@ -364,6 +379,9 @@ type replaceJSON struct {
func editPrintJSON(modFile *modfile.File) { func editPrintJSON(modFile *modfile.File) {
var f fileJSON var f fileJSON
f.Module = modFile.Module.Mod f.Module = modFile.Module.Mod
if modFile.Go != nil {
f.Go = modFile.Go.Version
}
for _, r := range modFile.Require { for _, r := range modFile.Require {
f.Require = append(f.Require, requireJSON{Path: r.Mod.Path, Version: r.Mod.Version, Indirect: r.Indirect}) f.Require = append(f.Require, requireJSON{Path: r.Mod.Path, Version: r.Mod.Version, Indirect: r.Indirect})
} }

View file

@ -154,7 +154,7 @@ func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (*File
return f, nil 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) { 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. // 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) fmt.Fprintf(errs, "%s:%d: repeated go statement\n", f.Syntax.Name, line.Start.Line)
return 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) fmt.Fprintf(errs, "%s:%d: usage: go 1.23\n", f.Syntax.Name, line.Start.Line)
return return
} }
@ -477,6 +477,22 @@ func (f *File) Cleanup() {
f.Syntax.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 { func (f *File) AddRequire(path, vers string) error {
need := true need := true
for _, r := range f.Require { for _, r := range f.Require {

View file

@ -393,17 +393,20 @@ no /* */ comments. Each line holds a single directive, made up of a
verb followed by arguments. For example: verb followed by arguments. For example:
module my/thing module my/thing
go 1.12
require other/thing v1.0.2 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 exclude old/thing v1.2.3
replace bad/thing v1.4.5 => good/thing v1.4.5 replace bad/thing v1.4.5 => good/thing v1.4.5
The verbs are module, to define the module path; require, to require The verbs are
a particular module at a given version or later; exclude, to exclude module, to define the module path;
a particular module version from use; and replace, to replace a module go, to set the expected language version;
version with a different module version. Exclude and replace apply only require, to require a particular module at a given version or later;
in the main module's go.mod and are ignored in dependencies. exclude, to exclude a particular module version from use; and
See https://research.swtch.com/vgo-mvs for details. 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, The leading verb can be factored out of adjacent lines to create a block,
like in Go imports: like in Go imports:

View file

@ -19,6 +19,7 @@ import (
"cmd/go/internal/search" "cmd/go/internal/search"
"encoding/json" "encoding/json"
"fmt" "fmt"
"go/build"
"io/ioutil" "io/ioutil"
"os" "os"
"path" "path"
@ -335,6 +336,8 @@ func legacyModInit() {
modFile.AddModuleStmt(path) modFile.AddModuleStmt(path)
} }
addGoStmt()
for _, name := range altConfigs { for _, name := range altConfigs {
cfg := filepath.Join(ModRoot, name) cfg := filepath.Join(ModRoot, name)
data, err := ioutil.ReadFile(cfg) 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{ var altConfigs = []string{
"Gopkg.lock", "Gopkg.lock",

View file

@ -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 so a successful package test result will be cached and reused
regardless of -timeout setting. 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: In addition to the build flags, the flags handled by 'go test' itself are:
-args -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 still runs (unless -c or -i is specified).
The test binary also accepts flags that control execution of the test; these 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. For more about build flags, see 'go help build'.
func Usage() { For more about specifying packages, see 'go help packages'.
os.Stderr.WriteString("usage: " + testUsage + "\n\n" +
strings.TrimSpace(testFlag1) + "\n\n\t" + See also: go build, go vet.
strings.TrimSpace(testFlag2) + "\n") `,
os.Exit(2)
} }
var HelpTestflag = &base.Command{ 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 The following flags are recognized by the 'go test' command and
control the execution of any test: control the execution of any test:
` + strings.TrimSpace(testFlag2) + `
`,
}
const testFlag2 = `
-bench regexp -bench regexp
Run only those benchmarks matching a regular expression. Run only those benchmarks matching a regular expression.
By default, no benchmarks are run. 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. 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 In the second example, the argument math is passed through to the test
binary, instead of being interpreted as the package list. binary, instead of being interpreted as the package list.
` `,
}
var HelpTestfunc = &base.Command{ var HelpTestfunc = &base.Command{
UsageLine: "testfunc", UsageLine: "testfunc",
@ -532,7 +516,7 @@ var testVetFlags = []string{
func runTest(cmd *base.Command, args []string) { func runTest(cmd *base.Command, args []string) {
modload.LoadTests = true modload.LoadTests = true
pkgArgs, testArgs = testFlags(args) pkgArgs, testArgs = testFlags(cmd.Usage, args)
work.FindExecCmd() // initialize cached result work.FindExecCmd() // initialize cached result

View file

@ -87,7 +87,7 @@ func init() {
// to allow both // to allow both
// go test fmt -custom-flag-for-fmt-test // go test fmt -custom-flag-for-fmt-test
// go test -x math // 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) args = str.StringList(cmdflag.FindGOFLAGS(testFlagDefn), args)
inPkg := false inPkg := false
var explicitArgs []string var explicitArgs []string
@ -108,7 +108,7 @@ func testFlags(args []string) (packageNames, passToTest []string) {
inPkg = false inPkg = false
} }
f, value, extraWord := cmdflag.Parse(cmd, testFlagDefn, args, i) f, value, extraWord := cmdflag.Parse(cmd, usage, testFlagDefn, args, i)
if f == nil { if f == nil {
// This is a flag we do not know; we must assume // This is a flag we do not know; we must assume
// that any args we see after this might be flag // that any args we see after this might be flag

View file

@ -38,7 +38,7 @@ See also: go fmt, go fix.
func runVet(cmd *base.Command, args []string) { func runVet(cmd *base.Command, args []string) {
modload.LoadTests = true modload.LoadTests = true
vetFlags, pkgArgs := vetFlags(args) vetFlags, pkgArgs := vetFlags(cmd.Usage, args)
work.BuildInit() work.BuildInit()
work.VetFlags = vetFlags work.VetFlags = vetFlags

View file

@ -23,24 +23,43 @@ import (
// go vet flag processing // go vet flag processing
// //
// We query the flags of the tool specified by GOVETTOOL (default: // We query the flags of the tool specified by -vettool and accept any
// cmd/vet) and accept any of those flags plus any flag valid for 'go // of those flags plus any flag valid for 'go build'. The tool must
// build'. The tool must support -flags, which prints a description of // support -flags, which prints a description of its flags in JSON to
// its flags in JSON to stdout. // stdout.
// GOVETTOOL specifies the vet command to run. // vetTool specifies the vet command to run.
// This must be an environment variable because // Any tool that supports the (still unpublished) vet
// we need it before flag processing, as we execute // command-line protocol may be supplied; see
// $GOVETTOOL to discover the set of flags it supports. // 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 // The default behavior (vetTool=="") runs 'go tool vet'.
// to (and later, opt out of) the new cmd/vet analysis driver during the //
// transition. It is also used by tests. var vetTool string // -vettool
var vetTool = os.Getenv("GOVETTOOL")
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 // vetFlags processes the command line, splitting it at the first non-flag
// into the list of flags and list of packages. // 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. // Query the vet command for its flags.
tool := vetTool tool := vetTool
if tool != "" { if tool != "" {
@ -94,6 +113,9 @@ func vetFlags(args []string) (passToVet, packageNames []string) {
// Add build flags to vetFlagDefn. // Add build flags to vetFlagDefn.
var cmd base.Command var cmd base.Command
work.AddBuildFlags(&cmd) 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) { cmd.Flag.VisitAll(func(f *flag.Flag) {
vetFlagDefn = append(vetFlagDefn, &cmdflag.Defn{ vetFlagDefn = append(vetFlagDefn, &cmdflag.Defn{
Name: f.Name, Name: f.Name,
@ -108,7 +130,7 @@ func vetFlags(args []string) (passToVet, packageNames []string) {
return args[:i], args[i:] 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 { if f == nil {
fmt.Fprintf(os.Stderr, "vet: flag %q not defined\n", args[i]) fmt.Fprintf(os.Stderr, "vet: flag %q not defined\n", args[i])
fmt.Fprintf(os.Stderr, "Run \"go help vet\" for more information\n") fmt.Fprintf(os.Stderr, "Run \"go help vet\" for more information\n")

View file

@ -178,7 +178,8 @@ func (b *Builder) toolID(name string) string {
path := base.Tool(name) path := base.Tool(name)
desc := "go 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 != "" { if name == "vet" && VetTool != "" {
path = VetTool path = VetTool
desc = VetTool desc = VetTool

View file

@ -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) 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 { if err := b.Mkdir(a.Objdir); err != nil {
return err return err
} }
@ -638,12 +634,19 @@ func (b *Builder) build(a *Action) (err error) {
objpkg := objdir + "_pkg_.a" objpkg := objdir + "_pkg_.a"
ofile, out, err := BuildToolchain.gc(b, a, objpkg, icfg.Bytes(), len(sfiles) > 0, gofiles) ofile, out, err := BuildToolchain.gc(b, a, objpkg, icfg.Bytes(), len(sfiles) > 0, gofiles)
if len(out) > 0 { 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 { if err != nil {
return errPrintedOutput return errPrintedOutput
} }
} }
if err != nil { 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 return err
} }
if ofile != objpkg { if ofile != objpkg {

View file

@ -53,6 +53,9 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg []byte, a
pkgpath = "main" pkgpath = "main"
} }
gcargs := []string{"-p", pkgpath} 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 { if p.Standard {
gcargs = append(gcargs, "-std") gcargs = append(gcargs, "-std")
} }

View file

@ -235,17 +235,6 @@ func init() {
} }
func mainUsage() { 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) help.PrintUsage(os.Stderr, base.Go)
os.Exit(2) os.Exit(2)
} }

View file

@ -11,6 +11,7 @@ import (
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
"go/build"
"internal/testenv" "internal/testenv"
"io/ioutil" "io/ioutil"
"os" "os"
@ -104,6 +105,7 @@ func (ts *testScript) setup() {
"GOROOT=" + testGOROOT, "GOROOT=" + testGOROOT,
tempEnvName() + "=" + filepath.Join(ts.workdir, "tmp"), tempEnvName() + "=" + filepath.Join(ts.workdir, "tmp"),
"devnull=" + os.DevNull, "devnull=" + os.DevNull,
"goversion=" + goVersion(ts),
":=" + string(os.PathListSeparator), ":=" + 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 var execCache par.Cache
// run runs the test script. // run runs the test script.
@ -331,6 +343,7 @@ var scriptCmds = map[string]func(*testScript, bool, []string){
"addcrlf": (*testScript).cmdAddcrlf, "addcrlf": (*testScript).cmdAddcrlf,
"cd": (*testScript).cmdCd, "cd": (*testScript).cmdCd,
"cmp": (*testScript).cmdCmp, "cmp": (*testScript).cmdCmp,
"cmpenv": (*testScript).cmdCmpenv,
"cp": (*testScript).cmdCp, "cp": (*testScript).cmdCp,
"env": (*testScript).cmdEnv, "env": (*testScript).cmdEnv,
"exec": (*testScript).cmdExec, "exec": (*testScript).cmdExec,
@ -396,7 +409,21 @@ func (ts *testScript) cmdCmp(neg bool, args []string) {
if len(args) != 2 { if len(args) != 2 {
ts.fatalf("usage: cmp file1 file2") 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] name1, name2 := args[0], args[1]
var text1, text2 string var text1, text2 string
if name1 == "stdout" { if name1 == "stdout" {
@ -413,6 +440,11 @@ func (ts *testScript) cmdCmp(neg bool, args []string) {
ts.check(err) ts.check(err)
text2 = string(data) text2 = string(data)
if env {
text1 = ts.expand(text1)
text2 = ts.expand(text2)
}
if text1 == text2 { if text1 == text2 {
return return
} }

View file

@ -36,6 +36,7 @@ Scripts also have access to these other environment variables:
PATH=<actual PATH> PATH=<actual PATH>
TMPDIR=$WORK/tmp TMPDIR=$WORK/tmp
devnull=<value of os.DevNull> devnull=<value of os.DevNull>
goversion=<current Go version; for example, 1.12>
The environment variable $exe (lowercase) is an empty string on most systems, ".exe" on Windows. 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. from the most recent exec or go command.
(If the files have differing content, the failure prints a diff.) (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 - cp src... dst
Copy the listed files to the target file or existing directory. Copy the listed files to the target file or existing directory.

View file

@ -35,6 +35,12 @@ stderr 'Run ''go help mod'' for usage.'
stderr 'usage: go vet' stderr 'usage: go vet'
stderr 'Run ''go help vet'' for details' 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 shows usage for get
go help get go help get
stdout 'usage: go get' stdout 'usage: go get'

View file

@ -10,37 +10,37 @@ stderr 'cannot determine module path'
go mod init x.x/y/z go mod init x.x/y/z
stderr 'creating new go.mod: module 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 ! go mod init
cmp go.mod $WORK/go.mod.init cmpenv go.mod $WORK/go.mod.init
# go mod edits # 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' 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 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
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
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 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 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 go mod edit -dropreplace=x.1
cmp go.mod $WORK/go.mod.edit5 cmpenv go.mod $WORK/go.mod.edit5
# go mod edit -fmt # go mod edit -fmt
cp $WORK/go.mod.badfmt go.mod cp $WORK/go.mod.badfmt go.mod
go mod edit -fmt -print # -print should avoid writing file 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 cmp go.mod $WORK/go.mod.badfmt
go mod edit -fmt # without -print, should write file (and nothing to stdout) go mod edit -fmt # without -print, should write file (and nothing to stdout)
! stdout . ! stdout .
cmp go.mod $WORK/go.mod.edit4 cmpenv go.mod $WORK/go.mod.edit6
-- x.go -- -- x.go --
package x package x
@ -50,9 +50,13 @@ package w
-- $WORK/go.mod.init -- -- $WORK/go.mod.init --
module x.x/y/z module x.x/y/z
go $goversion
-- $WORK/go.mod.edit1 -- -- $WORK/go.mod.edit1 --
module x.x/y/z module x.x/y/z
go $goversion
require x.1 v1.0.0 require x.1 v1.0.0
exclude ( exclude (
@ -67,6 +71,8 @@ replace (
-- $WORK/go.mod.edit2 -- -- $WORK/go.mod.edit2 --
module x.x/y/z module x.x/y/z
go $goversion
exclude x.1 v1.2.0 exclude x.1 v1.2.0
replace x.1 v1.4.0 => ../z replace x.1 v1.4.0 => ../z
@ -77,6 +83,7 @@ require x.3 v1.99.0
"Module": { "Module": {
"Path": "x.x/y/z" "Path": "x.x/y/z"
}, },
"Go": "$goversion",
"Require": [ "Require": [
{ {
"Path": "x.3", "Path": "x.3",
@ -104,6 +111,8 @@ require x.3 v1.99.0
-- $WORK/go.mod.edit3 -- -- $WORK/go.mod.edit3 --
module x.x/y/z module x.x/y/z
go $goversion
exclude x.1 v1.2.0 exclude x.1 v1.2.0
replace ( replace (
@ -115,6 +124,8 @@ require x.3 v1.99.0
-- $WORK/go.mod.edit4 -- -- $WORK/go.mod.edit4 --
module x.x/y/z module x.x/y/z
go $goversion
exclude x.1 v1.2.0 exclude x.1 v1.2.0
replace x.1 => y.1/v2 v2.3.6 replace x.1 => y.1/v2 v2.3.6
@ -123,12 +134,26 @@ require x.3 v1.99.0
-- $WORK/go.mod.edit5 -- -- $WORK/go.mod.edit5 --
module x.x/y/z module x.x/y/z
go $goversion
exclude x.1 v1.2.0 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 require x.3 v1.99.0
-- $WORK/go.mod.badfmt -- -- $WORK/go.mod.badfmt --
module x.x/y/z module x.x/y/z
go 1.10
exclude x.1 v1.2.0 exclude x.1 v1.2.0
replace x.1 => y.1/v2 v2.3.6 replace x.1 => y.1/v2 v2.3.6

View file

@ -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

View file

@ -3,9 +3,10 @@
env GO111MODULE=on env GO111MODULE=on
go list go list
! go build go build
stderr 'module requires Go 1.999'
go build sub.1 go build sub.1
go build subver.1
! stderr 'module requires'
! go build badsub.1 ! go build badsub.1
stderr 'module requires Go 1.11111' stderr 'module requires Go 1.11111'
@ -19,11 +20,13 @@ module m
go 1.999 go 1.999
require ( require (
sub.1 v1.0.0 sub.1 v1.0.0
subver.1 v1.0.0
badsub.1 v1.0.0 badsub.1 v1.0.0
versioned.1 v1.0.0 versioned.1 v1.0.0
) )
replace ( replace (
sub.1 => ./sub sub.1 => ./sub
subver.1 => ./subver
badsub.1 => ./badsub badsub.1 => ./badsub
versioned.1 v1.0.0 => ./versioned1 versioned.1 v1.0.0 => ./versioned1
versioned.1 v1.1.0 => ./versioned2 versioned.1 v1.1.0 => ./versioned2
@ -39,12 +42,20 @@ go 1.11
-- sub/x.go -- -- sub/x.go --
package x package x
-- subver/go.mod --
module m
go 1.11111
-- subver/x.go --
package x
-- badsub/go.mod -- -- badsub/go.mod --
module m module m
go 1.11111 go 1.11111
-- badsub/x.go -- -- badsub/x.go --
package x package x
invalid syntax
-- versioned1/go.mod -- -- versioned1/go.mod --
module versioned module versioned
@ -59,3 +70,4 @@ go 1.99999
-- versioned2/x.go -- -- versioned2/x.go --
package x package x
invalid syntax

View file

@ -37,6 +37,8 @@ cmp go.mod go.mod.inconsistent
-- go.mod -- -- go.mod --
module m module m
go 1.20
-- x.go -- -- x.go --
package x package x
import _ "rsc.io/quote" import _ "rsc.io/quote"

View file

@ -5,6 +5,9 @@ go mod tidy -v
stderr '^unused y.1' stderr '^unused y.1'
! stderr '^unused [^y]' ! stderr '^unused [^y]'
# tidy should not touch existing go line
grep 'go 1.10' go.mod
go list -m all go list -m all
! stdout '^y' ! stdout '^y'
stdout '^w.1 v1.2.0' stdout '^w.1 v1.2.0'
@ -12,11 +15,17 @@ stdout '^z.1 v1.2.0'
# empty tidy should not crash # empty tidy should not crash
cd triv cd triv
! grep 'go ' go.mod
go mod tidy go mod tidy
# tidy should add missing go line
grep 'go ' go.mod
-- go.mod -- -- go.mod --
module m module m
go 1.10
require ( require (
x.1 v1.0.0 x.1 v1.0.0
y.1 v1.0.0 y.1 v1.0.0

View file

@ -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 { func HasChildren(die *DWDie) bool {
return abbrevs[die.Abbrev].children != 0 return abbrevs[die.Abbrev].children != 0
} }

View file

@ -414,6 +414,8 @@ const (
C_BITCON // bitfield and logical immediate masks C_BITCON // bitfield and logical immediate masks
C_ADDCON2 // 24-bit constant C_ADDCON2 // 24-bit constant
C_LCON // 32-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_VCON // 64-bit constant
C_FCON // floating-point constant C_FCON // floating-point constant
C_VCONADDR // 64-bit memory address C_VCONADDR // 64-bit memory address

View file

@ -30,6 +30,8 @@ var cnames7 = []string{
"BITCON", "BITCON",
"ADDCON2", "ADDCON2",
"LCON", "LCON",
"MOVCON2",
"MOVCON3",
"VCON", "VCON",
"FCON", "FCON",
"VCONADDR", "VCONADDR",

View file

@ -198,9 +198,15 @@ var optab = []Optab{
{ACMP, C_BITCON, C_RSP, C_NONE, C_NONE, 62, 8, 0, 0, 0}, {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_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_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_MOVCON2, C_RSP, C_NONE, C_RSP, 13, 12, 0, 0, 0},
{AADD, C_VCON, C_NONE, C_NONE, C_RSP, 13, 8, 0, LFROM, 0}, {AADD, C_MOVCON2, C_NONE, C_NONE, C_RSP, 13, 12, 0, 0, 0},
{ACMP, C_VCON, C_REG, C_NONE, C_NONE, 13, 8, 0, LFROM, 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_REG, C_NONE, C_REG, 3, 4, 0, 0, 0},
{AADD, C_SHIFT, C_NONE, 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}, {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_REG, C_NONE, C_REG, 62, 8, 0, 0, 0},
{AANDS, C_MOVCON, C_NONE, 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}, {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_MOVCON2, C_REG, C_NONE, C_REG, 28, 12, 0, 0, 0},
{AAND, C_VCON, C_NONE, C_NONE, C_REG, 28, 8, 0, LFROM, 0}, {AAND, C_MOVCON2, C_NONE, C_NONE, C_REG, 28, 12, 0, 0, 0},
{AANDS, C_VCON, C_REG, C_NONE, C_REG, 28, 8, 0, LFROM, 0}, {AAND, C_MOVCON3, C_REG, C_NONE, C_REG, 28, 16, 0, 0, 0},
{AANDS, C_VCON, C_NONE, C_NONE, C_REG, 28, 8, 0, LFROM, 0}, {AAND, C_MOVCON3, C_NONE, C_NONE, C_REG, 28, 16, 0, 0, 0},
{ATST, C_VCON, C_REG, C_NONE, C_NONE, 28, 8, 0, LFROM, 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_REG, C_NONE, C_REG, 3, 4, 0, 0, 0},
{AAND, C_SHIFT, C_NONE, 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}, {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}, {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}, {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}, {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}, {AMOVW, C_MOVCON2, C_NONE, C_NONE, C_REG, 12, 8, 0, 0, 0},
{AMOVD, C_VCON, C_NONE, C_NONE, C_REG, 12, 4, 0, LFROM, 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}, {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}, {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}, {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_NSAUTO, 20, 4, REGSP, 0, 0},
{AMOVW, C_REG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 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_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_NSAUTO, 20, 4, REGSP, 0, 0},
{AFMOVS, C_FREG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 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 */ /* scaled 12-bit unsigned displacement load */
{AMOVB, C_UAUTO4K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, {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_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_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_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_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_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}, {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 */ /* unscaled 9-bit signed displacement load */
{AMOVB, C_NSAUTO, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, {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_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_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_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_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_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}, {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 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 { func isANDWop(op obj.As) bool {
switch op { switch op {
case AANDW, AORRW, AEORW, AANDSW, ATSTW, case AANDW, AORRW, AEORW, AANDSW, ATSTW,
@ -1114,6 +1141,14 @@ func isANDWop(op obj.As) bool {
return false 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 { func isADDWop(op obj.As) bool {
switch op { switch op {
case AADDW, AADDSW, ASUBW, ASUBSW, ACMNW, ACMPW: case AADDW, AADDSW, ASUBW, ASUBSW, ACMNW, ACMPW:
@ -1445,6 +1480,12 @@ func (c *ctxt7) con32class(a *obj.Addr) int {
if isbitcon(uint64(v)) { if isbitcon(uint64(v)) {
return C_ABCON return C_ABCON
} }
if movcon(int64(v)) >= 0 {
return C_AMCON
}
if movcon(int64(^v)) >= 0 {
return C_AMCON
}
return C_ADDCON return C_ADDCON
} }
@ -1474,6 +1515,29 @@ func (c *ctxt7) con32class(a *obj.Addr) int {
return C_LCON 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 { func (c *ctxt7) aclass(a *obj.Addr) int {
switch a.Type { switch a.Type {
case obj.TYPE_NONE: case obj.TYPE_NONE:
@ -1689,21 +1753,18 @@ func (c *ctxt7) oplook(p *obj.Prog) *Optab {
a1 = ra0 + 1 a1 = ra0 + 1
p.From.Class = int8(a1) p.From.Class = int8(a1)
} }
if isANDWop(p.As) { if isANDWop(p.As) && a0 != C_BITCON {
switch p.As { // For 32-bit logical instruction with constant,
case AANDW, AORRW, AEORW, AANDSW, ATSTW: // the BITCON test is special in that it looks at
// For 32-bit logical instruction with constant, // the 64-bit which has the high 32-bit as a copy
// rewrite the high 32-bit to be a copy of the low // of the low 32-bit. We have handled that and
// 32-bit, so that the BITCON test can be shared // don't pass it to con32class.
// for both 32-bit and 64-bit. a1 = c.con32class(&p.From) + 1
if a0 == C_BITCON { p.From.Class = int8(a1)
break }
} if ((p.As == AMOVD) || isANDop(p.As) || isADDop(p.As)) && (a0 == C_LCON || a0 == C_VCON) {
fallthrough a1 = c.con64class(&p.From) + 1
default: p.From.Class = int8(a1)
a1 = c.con32class(&p.From) + 1
p.From.Class = int8(a1)
}
} }
} }
} }
@ -1800,6 +1861,9 @@ func cmp(a int, b int) bool {
return true return true
} }
case C_MOVCON2:
return cmp(C_LCON, b)
case C_VCON: case C_VCON:
return cmp(C_LCON, b) 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) { func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
var os [5]uint32
o1 := uint32(0) o1 := uint32(0)
o2 := uint32(0) o2 := uint32(0)
o3 := 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 */ 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 */ case 13: /* addop $vcon, [R], R (64 bit literal); cmp $lcon,R -> addop $lcon,R, ZR */
o1 = c.omovlit(AMOVD, p, &p.From, REGTMP) o := uint32(0)
num := uint8(0)
if o1 == 0 { cls := oclass(&p.From)
break 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) rt := int(p.To.Reg)
if p.To.Type == obj.TYPE_NONE { if p.To.Type == obj.TYPE_NONE {
@ -2924,16 +3005,23 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
r = rt r = rt
} }
if p.To.Type != obj.TYPE_NONE && (p.To.Reg == REGSP || r == REGSP) { if p.To.Type != obj.TYPE_NONE && (p.To.Reg == REGSP || r == REGSP) {
o2 = c.opxrrr(p, p.As, false) o = c.opxrrr(p, p.As, false)
o2 |= REGTMP & 31 << 16 o |= REGTMP & 31 << 16
o2 |= LSL0_64 o |= LSL0_64
} else { } else {
o2 = c.oprrr(p, p.As) o = c.oprrr(p, p.As)
o2 |= REGTMP & 31 << 16 /* shift is 0 */ o |= REGTMP & 31 << 16 /* shift is 0 */
} }
o2 |= uint32(r&31) << 5 o |= uint32(r&31) << 5
o2 |= uint32(rt & 31) 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 */ case 14: /* word */
if c.aclass(&p.To) == C_ADDR { 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) o1 |= (uint32(r&31) << 5) | uint32(rt&31)
case 28: /* logop $vcon, [R], R (64 bit literal) */ 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 { if num == 0 {
break c.ctxt.Diag("invalid constant: %v", p)
} }
rt := int(p.To.Reg) rt := int(p.To.Reg)
if p.To.Type == obj.TYPE_NONE { 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 { if r == 0 {
r = rt r = rt
} }
o2 = c.oprrr(p, p.As) o = c.oprrr(p, p.As)
o2 |= REGTMP & 31 << 16 /* shift is 0 */ o |= REGTMP & 31 << 16 /* shift is 0 */
o2 |= uint32(r&31) << 5 o |= uint32(r&31) << 5
o2 |= uint32(rt & 31) 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 */ case 29: /* op Rn, Rd */
fc := c.aclass(&p.From) 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) o1 |= MOVCONST(d, s, rt)
} }
return o1 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 { func (c *ctxt7) opbfm(p *obj.Prog, a obj.As, r int, s int, rf int, rt int) uint32 {
var b uint32 var b uint32
o := c.opirr(p, a) o := c.opirr(p, a)

View file

@ -89,7 +89,7 @@ such as str, stur, strb, sturb, strh, sturh stlr, stlrb. stlrh, st1.
Examples: Examples:
MOVD R29, 384(R19) <=> str x29, [x19,#384] MOVD R29, 384(R19) <=> str x29, [x19,#384]
MOVB.P R30, 30(R4) <=> strb w30, [x4],#30 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 <Rm>, <Ra>, <Rn>, <Rd> (2) MADD, MADDW, MSUB, MSUBW, SMADDL, SMSUBL, UMADDL, UMSUBL <Rm>, <Ra>, <Rn>, <Rd>
@ -127,7 +127,7 @@ such as str, stur, strb, sturb, strh, sturh stlr, stlrb. stlrh, st1.
Examples: Examples:
CCMN VS, R13, R22, $10 <=> ccmn x13, x22, #0xa, vs 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 <cond>, <Rn>, <Rm>, <Rd> ; (9) CSEL, CSELW, CSNEG, CSNEGW, CSINC, CSINCW <cond>, <Rn>, <Rm>, <Rd> ;
FCSELD, FCSELS <cond>, <Fn>, <Fm>, <Fd> FCSELD, FCSELS <cond>, <Fn>, <Fm>, <Fd>
@ -144,12 +144,12 @@ FCSELD, FCSELS <cond>, <Fn>, <Fm>, <Fd>
Examples: Examples:
STLXR ZR, (R15), R16 <=> stlxr w16, xzr, [x15] 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 (<Rf1>, <Rf2>), (<Rn|RSP>), <Rs> (12) STLXP, STLXPW, STXP, STXPW (<Rf1>, <Rf2>), (<Rn|RSP>), <Rs>
Examples: 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] STXPW (R30, R25), (R22), R13 <=> stxp w13, w30, w25, [x22]
2. Expressions for special arguments. 2. Expressions for special arguments.
@ -173,7 +173,7 @@ Extended registers are written as <Rm>{.<extend>{<<<amount>}}.
<extend> can be UXTB, UXTH, UXTW, UXTX, SXTB, SXTH, SXTW or SXTX. <extend> can be UXTB, UXTH, UXTW, UXTX, SXTB, SXTH, SXTW or SXTX.
Examples: 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 ADDSW R14.SXTX, R14, R6 <=> adds w6, w14, w14, sxtx
Memory references: [<Xn|SP>{,#0}] is written as (Rn|RSP), a base register and an immediate Memory references: [<Xn|SP>{,#0}] is written as (Rn|RSP), a base register and an immediate

View file

@ -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 // shared for both 32-bit and 64-bit. 32-bit ops
// will zero the high 32-bit of the destination // will zero the high 32-bit of the destination
// register anyway. // register anyway.
switch p.As { if isANDWop(p.As) && p.From.Type == obj.TYPE_CONST {
case AANDW, AORRW, AEORW, AANDSW, ATSTW: v := p.From.Offset & 0xffffffff
if p.From.Type == obj.TYPE_CONST { p.From.Offset = v | v<<32
v := p.From.Offset & 0xffffffff
p.From.Offset = v | v<<32
}
} }
if c.ctxt.Flag_dynlink { if c.ctxt.Flag_dynlink {

View file

@ -403,9 +403,9 @@ type FuncInfo struct {
dwarfAbsFnSym *LSym dwarfAbsFnSym *LSym
dwarfIsStmtSym *LSym dwarfIsStmtSym *LSym
GCArgs LSym GCArgs *LSym
GCLocals LSym GCLocals *LSym
GCRegs LSym GCRegs *LSym
StackObjects *LSym StackObjects *LSym
} }

View file

@ -25,12 +25,6 @@ type objWriter struct {
// Temporary buffer for zigzag int writing. // Temporary buffer for zigzag int writing.
varintbuf [10]uint8 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. // Number of objects written of each type.
nRefs int nRefs int
nData int nData int
@ -79,10 +73,8 @@ func (w *objWriter) writeLengths() {
func newObjWriter(ctxt *Link, b *bufio.Writer) *objWriter { func newObjWriter(ctxt *Link, b *bufio.Writer) *objWriter {
return &objWriter{ return &objWriter{
ctxt: ctxt, ctxt: ctxt,
wr: b, wr: b,
vrefIdx: make(map[string]int),
refIdx: make(map[string]int),
} }
} }
@ -157,17 +149,6 @@ func (w *objWriter) writeRef(s *LSym, isPath bool) {
if s == nil || s.RefIdx != 0 { if s == nil || s.RefIdx != 0 {
return 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) w.wr.WriteByte(symPrefix)
if isPath { if isPath {
w.writeString(filepath.ToSlash(s.Name)) w.writeString(filepath.ToSlash(s.Name))
@ -178,7 +159,6 @@ func (w *objWriter) writeRef(s *LSym, isPath bool) {
w.writeBool(s.Static()) w.writeBool(s.Static())
w.nRefs++ w.nRefs++
s.RefIdx = w.nRefs s.RefIdx = w.nRefs
m[s.Name] = w.nRefs
} }
func (w *objWriter) writeRefs(s *LSym) { func (w *objWriter) writeRefs(s *LSym) {

View file

@ -147,18 +147,6 @@ func (ctxt *Link) InitTextSym(s *LSym, flag int) {
isstmt.Type = objabi.SDWARFMISC isstmt.Type = objabi.SDWARFMISC
isstmt.Set(AttrDuplicateOK, s.DuplicateOK()) isstmt.Set(AttrDuplicateOK, s.DuplicateOK())
ctxt.Data = append(ctxt.Data, isstmt) 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) { func (ctxt *Link) Globl(s *LSym, size int64, flag int) {

View file

@ -246,7 +246,7 @@ const (
REG_RET1 REG_RET1
REG_RET2 REG_RET2
REG_RET3 REG_RET3
REG_RUN REG_PAUSE
// locals // locals
REG_R0 REG_R0

View file

@ -16,16 +16,16 @@ import (
) )
var Register = map[string]int16{ var Register = map[string]int16{
"PC_F": REG_PC_F, "PC_F": REG_PC_F,
"PC_B": REG_PC_B, "PC_B": REG_PC_B,
"SP": REG_SP, "SP": REG_SP,
"CTXT": REG_CTXT, "CTXT": REG_CTXT,
"g": REG_g, "g": REG_g,
"RET0": REG_RET0, "RET0": REG_RET0,
"RET1": REG_RET1, "RET1": REG_RET1,
"RET2": REG_RET2, "RET2": REG_RET2,
"RET3": REG_RET3, "RET3": REG_RET3,
"RUN": REG_RUN, "PAUSE": REG_PAUSE,
"R0": REG_R0, "R0": REG_R0,
"R1": REG_R1, "R1": REG_R1,
@ -777,7 +777,7 @@ func assemble(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
} }
reg := p.From.Reg reg := p.From.Reg
switch { switch {
case reg >= REG_PC_F && reg <= REG_RUN: case reg >= REG_PC_F && reg <= REG_PAUSE:
w.WriteByte(0x23) // get_global w.WriteByte(0x23) // get_global
writeUleb128(w, uint64(reg-REG_PC_F)) writeUleb128(w, uint64(reg-REG_PC_F))
case reg >= REG_R0 && reg <= REG_R15: 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 reg := p.To.Reg
switch { switch {
case reg >= REG_PC_F && reg <= REG_RUN: case reg >= REG_PC_F && reg <= REG_PAUSE:
w.WriteByte(0x24) // set_global w.WriteByte(0x24) // set_global
writeUleb128(w, uint64(reg-REG_PC_F)) writeUleb128(w, uint64(reg-REG_PC_F))
case reg >= REG_R0 && reg <= REG_F15: case reg >= REG_R0 && reg <= REG_F15:

View file

@ -4704,7 +4704,9 @@ func (ab *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
r = obj.Addrel(cursym) r = obj.Addrel(cursym)
r.Off = int32(p.Pc + int64(ab.Len())) r.Off = int32(p.Pc + int64(ab.Len()))
r.Sym = p.To.Sym 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 r.Siz = 4
ab.PutInt32(0) ab.PutInt32(0)
break break

View file

@ -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 // (https://sourceware.org/bugzilla/show_bug.cgi?id=18270). So
// we convert the adrp; ld64 + R_ARM64_GOTPCREL into adrp; // we convert the adrp; ld64 + R_ARM64_GOTPCREL into adrp;
// add + R_ADDRARM64. // 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 { if o2&0xffc00000 != 0xf9400000 {
ld.Errorf(s, "R_ARM64_GOTPCREL against unexpected instruction %x", o2) ld.Errorf(s, "R_ARM64_GOTPCREL against unexpected instruction %x", o2)
} }

View file

@ -342,6 +342,26 @@ func lookupOrDiag(ctxt *Link, n string) *sym.Symbol {
return s 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 { func dotypedef(ctxt *Link, parent *dwarf.DWDie, name string, def *dwarf.DWDie) *dwarf.DWDie {
// Only emit typedefs for real names. // Only emit typedefs for real names.
if strings.HasPrefix(name, "map[") { 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)) dv := newdie(ctxt, ctxt.compUnitByPackage[lib].dwinfo, dwarf.DW_ABRV_VARIABLE, str, int(s.Version))
newabslocexprattr(dv, v, s) newabslocexprattr(dv, v, s)
if s.Version == 0 { if !s.IsFileLocal() {
newattr(dv, dwarf.DW_AT_external, dwarf.DW_CLS_FLAG, 1, 0) newattr(dv, dwarf.DW_AT_external, dwarf.DW_CLS_FLAG, 1, 0)
} }
dt := defgotype(ctxt, gotype) 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. // indexes (created by numberfile) to CU-local indexes.
fileNums := make(map[int]int) fileNums := make(map[int]int)
for _, s := range unit.lib.Textp { // textp has been dead-code-eliminated already. 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 { for _, f := range s.FuncInfo.File {
if _, ok := fileNums[int(f.Value)]; ok { if _, ok := fileNums[int(f.Value)]; ok {
continue continue
@ -1756,12 +1776,12 @@ func dwarfGenerateDebugInfo(ctxt *Link) {
// referenced abstract functions. // referenced abstract functions.
// Collect all debug_range symbols in unit.rangeSyms // Collect all debug_range symbols in unit.rangeSyms
for _, s := range lib.Textp { // textp has been dead-code-eliminated already. 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.Attr |= sym.AttrNotInSymbolTable | sym.AttrReachable
dsym.Type = sym.SDWARFINFO dsym.Type = sym.SDWARFINFO
unit.funcDIEs = append(unit.funcDIEs, dsym) 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 { if rangeSym != nil && rangeSym.Size > 0 {
rangeSym.Attr |= sym.AttrReachable | sym.AttrNotInSymbolTable rangeSym.Attr |= sym.AttrReachable | sym.AttrNotInSymbolTable
rangeSym.Type = sym.SDWARFRANGE rangeSym.Type = sym.SDWARFRANGE

View file

@ -2130,7 +2130,7 @@ func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int6
if s.Attr.NotInSymbolTable() { if s.Attr.NotInSymbolTable() {
continue 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 continue
} }
switch s.Type { switch s.Type {

View file

@ -704,7 +704,7 @@ func (f *peFile) writeSymbols(ctxt *Link) {
} }
} }
class := IMAGE_SYM_CLASS_EXTERNAL 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 class = IMAGE_SYM_CLASS_STATIC
} }
f.writeSymbol(ctxt.Out, s, value, sect, typ, uint8(class)) f.writeSymbol(ctxt.Out, s, value, sect, typ, uint8(class))

View file

@ -128,7 +128,7 @@ func putelfsym(ctxt *Link, x *sym.Symbol, s string, t SymbolType, addr int64, go
// maybe one day STB_WEAK. // maybe one day STB_WEAK.
bind := STB_GLOBAL 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 bind = STB_LOCAL
} }
@ -224,7 +224,7 @@ func putplan9sym(ctxt *Link, x *sym.Symbol, s string, typ SymbolType, addr int64
t := int(typ) t := int(typ)
switch typ { switch typ {
case TextSym, DataSym, BSSSym: case TextSym, DataSym, BSSSym:
if x.Version != 0 { if x.IsFileLocal() {
t += 'a' - 'A' t += 'a' - 'A'
} }
fallthrough fallthrough

View file

@ -51,6 +51,10 @@ type AuxSymbol struct {
elftype elf.SymType elftype elf.SymType
} }
const (
SymVerStatic = 10 // Minimum version used by static (file-local) syms
)
func (s *Symbol) String() string { func (s *Symbol) String() string {
if s.Version == 0 { if s.Version == 0 {
return s.Name return s.Name
@ -58,6 +62,10 @@ func (s *Symbol) String() string {
return fmt.Sprintf("%s<%d>", s.Name, s.Version) return fmt.Sprintf("%s<%d>", s.Name, s.Version)
} }
func (s *Symbol) IsFileLocal() bool {
return s.Version >= SymVerStatic
}
func (s *Symbol) ElfsymForReloc() int32 { func (s *Symbol) ElfsymForReloc() int32 {
// If putelfsym created a local version of this symbol, use that in all // If putelfsym created a local version of this symbol, use that in all
// relocations. // relocations.

View file

@ -40,12 +40,11 @@ type Symbols struct {
} }
func NewSymbols() *Symbols { 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{ return &Symbols{
hash: []map[string]*Symbol{ hash: hash,
// preallocate about 2mb for hash of
// non static symbols
make(map[string]*Symbol, 100000),
},
Allsym: make([]*Symbol, 0, 100000), Allsym: make([]*Symbol, 0, 100000),
} }
} }

Some files were not shown because too many files have changed in this diff Show more