[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>
<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>R29</code> is the frame pointer.
<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 Test26066(t *testing.T) { test26066(t) }
func Test26213(t *testing.T) { test26213(t) }
func Test27660(t *testing.T) { test27660(t) }
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
func BenchmarkGoString(b *testing.B) { benchGoString(b) }

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
pprof
internal
binutils
testdata
+
driver
testdata
+

View file

@ -79,6 +79,10 @@
console.warn("exit code:", code);
}
};
this._exitPromise = new Promise((resolve) => {
this._resolveExitPromise = resolve;
});
this._pendingCallback = null;
this._callbackTimeouts = new Map();
this._nextCallbackTimeoutID = 1;
@ -194,6 +198,11 @@
const timeOrigin = Date.now() - performance.now();
this.importObject = {
go: {
// Go's SP does not change as long as no Go code is running. Some operations (e.g. calls, getters and setters)
// may trigger a synchronous callback to Go. This makes Go code get executed in the middle of the imported
// function. A goroutine can switch to a new stack if the current stack is too small (see morestack function).
// This changes the SP, thus we have to update the SP used by the imported function.
// func wasmExit(code int32)
"runtime.wasmExit": (sp) => {
const code = mem().getInt32(sp + 8, true);
@ -229,7 +238,7 @@
const id = this._nextCallbackTimeoutID;
this._nextCallbackTimeoutID++;
this._callbackTimeouts.set(id, setTimeout(
() => { this._resolveCallbackPromise(); },
() => { this._resume(); },
getInt64(sp + 8) + 1, // setTimeout has been seen to fire up to 1 millisecond early
));
mem().setInt32(sp + 16, id, true);
@ -254,7 +263,9 @@
// func valueGet(v ref, p string) ref
"syscall/js.valueGet": (sp) => {
storeValue(sp + 32, Reflect.get(loadValue(sp + 8), loadString(sp + 16)));
const result = Reflect.get(loadValue(sp + 8), loadString(sp + 16));
sp = this._inst.exports.getsp(); // see comment above
storeValue(sp + 32, result);
},
// func valueSet(v ref, p string, x ref)
@ -278,7 +289,9 @@
const v = loadValue(sp + 8);
const m = Reflect.get(v, loadString(sp + 16));
const args = loadSliceOfValues(sp + 32);
storeValue(sp + 56, Reflect.apply(m, v, args));
const result = Reflect.apply(m, v, args);
sp = this._inst.exports.getsp(); // see comment above
storeValue(sp + 56, result);
mem().setUint8(sp + 64, 1);
} catch (err) {
storeValue(sp + 56, err);
@ -291,7 +304,9 @@
try {
const v = loadValue(sp + 8);
const args = loadSliceOfValues(sp + 16);
storeValue(sp + 40, Reflect.apply(v, undefined, args));
const result = Reflect.apply(v, undefined, args);
sp = this._inst.exports.getsp(); // see comment above
storeValue(sp + 40, result);
mem().setUint8(sp + 48, 1);
} catch (err) {
storeValue(sp + 40, err);
@ -304,7 +319,9 @@
try {
const v = loadValue(sp + 8);
const args = loadSliceOfValues(sp + 16);
storeValue(sp + 40, Reflect.construct(v, args));
const result = Reflect.construct(v, args);
sp = this._inst.exports.getsp(); // see comment above
storeValue(sp + 40, result);
mem().setUint8(sp + 48, 1);
} catch (err) {
storeValue(sp + 40, err);
@ -355,7 +372,6 @@
this,
];
this._refs = new Map();
this._callbackShutdown = false;
this.exited = false;
const mem = new DataView(this._inst.exports.mem.buffer)
@ -390,42 +406,30 @@
offset += 8;
});
while (true) {
const callbackPromise = new Promise((resolve) => {
this._resolveCallbackPromise = () => {
if (this.exited) {
throw new Error("bad callback: Go program has already exited");
}
setTimeout(resolve, 0); // make sure it is asynchronous
};
});
this._inst.exports.run(argc, argv);
if (this.exited) {
break;
}
await callbackPromise;
this._inst.exports.run(argc, argv);
if (this.exited) {
this._resolveExitPromise();
}
await this._exitPromise;
}
_resume() {
if (this.exited) {
throw new Error("bad callback: Go program has already exited");
}
this._inst.exports.resume();
if (this.exited) {
this._resolveExitPromise();
}
}
static _makeCallbackHelper(id, pendingCallbacks, go) {
_makeCallbackHelper(id) {
const go = this;
return function () {
pendingCallbacks.push({ id: id, args: arguments });
go._resolveCallbackPromise();
};
}
static _makeEventCallbackHelper(preventDefault, stopPropagation, stopImmediatePropagation, fn) {
return function (event) {
if (preventDefault) {
event.preventDefault();
}
if (stopPropagation) {
event.stopPropagation();
}
if (stopImmediatePropagation) {
event.stopImmediatePropagation();
}
fn(event);
const cb = { id: id, this: this, args: arguments };
go._pendingCallback = cb;
go._resume();
return cb.result;
};
}
}
@ -444,8 +448,8 @@
process.on("exit", (code) => { // Node.js exits if no callback is pending
if (code === 0 && !go.exited) {
// deadlock, make Go print error and stack traces
go._callbackShutdown = true;
go._inst.exports.run();
go._pendingCallback = { id: 0 };
go._resume();
}
});
return go.run(result.instance);

View file

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

View file

@ -12,6 +12,13 @@ import (
"unicode/utf8"
)
// Equal returns a boolean reporting whether a and b
// are the same length and contain the same bytes.
// A nil argument is equivalent to an empty slice.
func Equal(a, b []byte) bool {
return bytealg.Equal(a, b)
}
func equalPortable(a, b []byte) bool {
if len(a) != len(b) {
return false
@ -24,6 +31,13 @@ func equalPortable(a, b []byte) bool {
return true
}
// Compare returns an integer comparing two byte slices lexicographically.
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
// A nil argument is equivalent to an empty slice.
func Compare(a, b []byte) int {
return bytealg.Compare(a, b)
}
// explode splits s into a slice of UTF-8 sequences, one per Unicode code point (still slices of bytes),
// up to a maximum of n byte slices. Invalid UTF-8 sequences are chopped into individual bytes.
func explode(s []byte, n int) [][]byte {
@ -83,6 +97,11 @@ func ContainsRune(b []byte, r rune) bool {
return IndexRune(b, r) >= 0
}
// IndexByte returns the index of the first instance of c in b, or -1 if c is not present in b.
func IndexByte(b []byte, c byte) int {
return bytealg.IndexByte(b, c)
}
func indexBytePortable(s []byte, c byte) int {
for i, b := range s {
if b == c {

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 {
log.Fatal(err)
}
defer f.Close()
tab, err := f.PCLineTable()
if err != nil {

View file

@ -258,6 +258,9 @@ func archArm64() *Arch {
for i := arm64.REG_R0; i <= arm64.REG_R31; i++ {
register[obj.Rconv(i)] = int16(i)
}
// Rename R18 to R18_PLATFORM to avoid accidental use.
register["R18_PLATFORM"] = register["R18"]
delete(register, "R18")
for i := arm64.REG_F0; i <= arm64.REG_F31; i++ {
register[obj.Rconv(i)] = int16(i)
}

View file

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

View file

@ -47,8 +47,8 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
ADD R2.SXTX<<1, RSP, RSP // ffe7228b
ADD ZR.SXTX<<1, R2, R3 // 43e43f8b
ADDW R2.SXTW, R10, R12 // 4cc1220b
ADD R18.UXTX, R14, R17 // d161328b
ADDSW R18.UXTW, R14, R17 // d141322b
ADD R19.UXTX, R14, R17 // d161338b
ADDSW R19.UXTW, R14, R17 // d141332b
ADDS R12.SXTX, R3, R1 // 61e02cab
SUB R19.UXTH<<4, R2, R21 // 553033cb
SUBW R1.UXTX<<1, R3, R2 // 6264214b
@ -144,7 +144,7 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
MOVD (R2)(R6.SXTW), R4 // 44c866f8
MOVD (R3)(R6), R5 // MOVD (R3)(R6*1), R5 // 656866f8
MOVD (R2)(R6), R4 // MOVD (R2)(R6*1), R4 // 446866f8
MOVWU (R19)(R18<<2), R18 // 727a72b8
MOVWU (R19)(R20<<2), R20 // 747a74b8
MOVD (R2)(R6<<3), R4 // 447866f8
MOVD (R3)(R7.SXTX<<3), R8 // 68f867f8
MOVWU (R5)(R4.UXTW), R10 // aa4864b8
@ -154,7 +154,7 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
MOVHU (R1)(R2<<1), R5 // 25786278
MOVB (R9)(R3.UXTW), R6 // 2649a338
MOVB (R10)(R6), R15 // MOVB (R10)(R6*1), R15 // 4f69a638
MOVH (R5)(R7.SXTX<<1), R18 // b2f8a778
MOVH (R5)(R7.SXTX<<1), R19 // b3f8a778
MOVH (R8)(R4<<1), R10 // 0a79a478
MOVW (R9)(R8.SXTW<<2), R19 // 33d9a8b8
MOVW (R1)(R4.SXTX), R11 // 2be8a4b8
@ -195,6 +195,11 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
CMPW $27745, R2 // 3b8c8d525f001b6b
CMNW $0x3fffffc0, R2 // CMNW $1073741760, R2 // fb5f1a325f001b2b
CMPW $0xffff0, R1 // CMPW $1048560, R1 // fb3f1c323f001b6b
CMP $0xffffffffffa0, R3 // CMP $281474976710560, R3 // fb0b80921b00e0f27f001beb
CMP $0xf4240, R1 // CMP $1000000, R1 // 1b4888d2fb01a0f23f001beb
ADD $0x186a0, R2, R5 // ADD $100000, R2, R5 // 45801a91a5604091
SUB $0xe7791f700, R3, R1 // SUB $62135596800, R3, R1 // 1be09ed23bf2aef2db01c0f261001bcb
CMP $3343198598084851058, R3 // 5bae8ed2db8daef23badcdf2bbcce5f27f001beb
ADD $0x3fffffffc000, R5 // ADD $70368744161280, R5 // fb7f72b2a5001b8b
// LTYPE1 imsr ',' spreg ','
// {
@ -222,6 +227,13 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
EOR $(1<<63), R1 // EOR $-9223372036854775808, R1 // 210041d2
EOR $(1<<63-1), R1 // EOR $9223372036854775807, R1 // 21f840d2
ANDW $0x3ff00000, R2 // ANDW $1072693248, R2 // 42240c12
BICW $0x3ff00000, R2 // BICW $1072693248, R2 // 42540212
ORRW $0x3ff00000, R2 // ORRW $1072693248, R2 // 42240c32
ORNW $0x3ff00000, R2 // ORNW $1072693248, R2 // 42540232
EORW $0x3ff00000, R2 // EORW $1072693248, R2 // 42240c52
EONW $0x3ff00000, R2 // EONW $1072693248, R2 // 42540252
AND $0x22220000, R3, R4 // AND $572653568, R3, R4 // 5b44a4d264001b8a
ORR $0x22220000, R3, R4 // ORR $572653568, R3, R4 // 5b44a4d264001baa
EOR $0x22220000, R3, R4 // EOR $572653568, R3, R4 // 5b44a4d264001bca
@ -233,12 +245,21 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
EOR $0xe03fffffffffffff, R20, R22 // EOR $-2287828610704211969, R20, R22 // 96e243d2
TSTW $0x600000006, R1 // TSTW $25769803782, R1 // 3f041f72
TST $0x4900000049, R0 // TST $313532612681, R0 // 3b0980d23b09c0f21f001bea
ORR $0x170000, R2, R1 // ORR $1507328, R2, R1 // fb02a0d241001baa
AND $0xff00ff, R2 // AND $16711935, R2 // fb1f80d2fb1fa0f242001b8a
AND $0xff00ffff, R1 // AND $4278255615, R1 // fbff9fd21be0bff221001b8a
ANDS $0xffff, R2 // ANDS $65535, R2 // 423c40f2
AND $0x7fffffff, R3 // AND $2147483647, R3 // 63784092
ANDS $0x0ffffffff80000000, R2 // ANDS $-2147483648, R2 // 428061f2
AND $0xfffff, R2 // AND $1048575, R2 // 424c4092
ANDW $0xf00fffff, R1 // ANDW $4027580415, R1 // 215c0412
ANDSW $0xff00ffff, R1 // ANDSW $4278255615, R1 // 215c0872
TST $0x11223344, R2 // TST $287454020, R2 // 9b6886d25b24a2f25f001bea
TSTW $0xa000, R3 // TSTW $40960, R3 // 1b0094527f001b6a
BICW $0xa000, R3 // BICW $40960, R3 // 1b00945263003b0a
ORRW $0x1b000, R2, R3 // ORRW $110592, R2, R3 // 1b0096523b00a07243001b2a
TSTW $0x500000, R1 // TSTW $5242880, R1 // 1b0aa0523f001b6a
TSTW $0xff00ff, R1 // TSTW $16711935, R1 // 3f9c0072
AND $8, R0, RSP // 1f007d92
@ -249,13 +270,20 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
EON $8, R0, RSP // 1ff87cd2
MOVD $0x3fffffffc000, R0 // MOVD $70368744161280, R0 // e07f72b2
MOVW $1000000, R4 // 04488852e401a072
MOVW $0xaaaa0000, R1 // MOVW $2863267840, R1 // 4155b552
MOVW $0xaaaaffff, R1 // MOVW $2863333375, R1 // a1aaaa12
MOVW $0xaaaa, R1 // MOVW $43690, R1 // 41559552
MOVW $0xffffaaaa, R1 // MOVW $4294945450, R1 // a1aa8a12
MOVW $0xffff0000, R1 // MOVW $4294901760, R1 // e1ffbf52
MOVD $0xffff00000000000, R1 // MOVD $1152903912420802560, R1 // e13f54b2
MOVD $0x1111000000001111, R1 // MOVD $1229764173248860433, R1 // 212282d22122e2f2
MOVD $0x1111ffff1111ffff, R1 // MOVD $1230045644216991743, R1 // c1ddbd922122e2f2
MOVD $0x1111222233334444, R1 // MOVD $1229801703532086340, R1 // 818888d26166a6f24144c4f22122e2f2
MOVD $0xaaaaffff, R1 // MOVD $2863333375, R1 // e1ff9fd24155b5f2
MOVD $0x11110000, R1 // MOVD $286326784, R1 // 2122a2d2
MOVD $0xaaaa0000aaaa1111, R1 // MOVD $-6149102338357718767, R1 // 212282d24155b5f24155f5f2
MOVD $0x1111ffff1111aaaa, R1 // MOVD $1230045644216969898, R1 // a1aa8a922122a2f22122e2f2
MOVD $0, R1 // 010080d2
MOVD $-1, R1 // 01008092
MOVD $0x210000, R0 // MOVD $2162688, R0 // 2004a0d2

View file

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

View file

@ -139,7 +139,7 @@ func (in *Input) Text() string {
return in.text
}
// hash processes a # preprocessor directive. It returns true iff it completes.
// hash processes a # preprocessor directive. It reports whether it completes.
func (in *Input) hash() bool {
// We have a '#'; it must be followed by a known word (define, include, etc.).
tok := in.Stack.Next()

View file

@ -827,6 +827,10 @@ The directives are:
possibly version in the dynamic library, and the optional "<library>"
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.
Examples:

View file

@ -246,7 +246,22 @@ func (p *Package) writeDefs() {
init := gccgoInit.String()
if init != "" {
fmt.Fprintln(fc, "static void init(void) __attribute__ ((constructor));")
// The init function does nothing but simple
// assignments, so it won't use much stack space, so
// it's OK to not split the stack. Splitting the stack
// can run into a bug in clang (as of 2018-11-09):
// this is a leaf function, and when clang sees a leaf
// function it won't emit the split stack prologue for
// the function. However, if this function refers to a
// non-split-stack function, which will happen if the
// cgo code refers to a C function not compiled with
// -fsplit-stack, then the linker will think that it
// needs to adjust the split stack prologue, but there
// won't be one. Marking the function explicitly
// no_split_stack works around this problem by telling
// the linker that it's OK if there is no split stack
// prologue.
fmt.Fprintln(fc, "static void init(void) __attribute__ ((constructor, no_split_stack));")
fmt.Fprintln(fc, "static void init(void) {")
fmt.Fprint(fc, init)
fmt.Fprintln(fc, "}")

View file

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

View file

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

View file

@ -61,23 +61,23 @@ func slicestringcopy(to any, fr any) int
func decoderune(string, int) (retv rune, retk int)
func countrunes(string) int
// interface conversions
// Non-empty-interface to non-empty-interface conversion.
func convI2I(typ *byte, elem any) (ret any)
// Specialized type-to-interface conversion.
// These return only a data pointer.
func convT16(val any) unsafe.Pointer // val must be uint16-like (same size and alignment as a uint16)
func convT32(val any) unsafe.Pointer // val must be uint32-like (same size and alignment as a uint32)
func convT64(val any) unsafe.Pointer // val must be uint64-like (same size and alignment as a uint64 and contains no pointers)
func convTstring(val any) unsafe.Pointer // val must be a string
func convTslice(val any) unsafe.Pointer // val must be a slice
// Type to empty-interface conversion.
func convT2E(typ *byte, elem *any) (ret any)
func convT2E16(typ *byte, val any) (ret any)
func convT2E32(typ *byte, val any) (ret any)
func convT2E64(typ *byte, val any) (ret any)
func convT2Estring(typ *byte, val any) (ret any) // val must be a string
func convT2Eslice(typ *byte, val any) (ret any) // val must be a slice
func convT2Enoptr(typ *byte, elem *any) (ret any)
// Type to non-empty-interface conversion.
func convT2I(tab *byte, elem *any) (ret any)
func convT2I16(tab *byte, val any) (ret any)
func convT2I32(tab *byte, val any) (ret any)
func convT2I64(tab *byte, val any) (ret any)
func convT2Istring(tab *byte, val any) (ret any) // val must be a string
func convT2Islice(tab *byte, val any) (ret any) // val must be a slice
func convT2Inoptr(tab *byte, elem *any) (ret any)
// interface type assertions x.(T)

View file

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

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

View file

@ -1114,6 +1114,7 @@ var opprec = []int{
OSLICEARR: 8,
OSLICE3: 8,
OSLICE3ARR: 8,
OSLICEHEADER: 8,
ODOTINTER: 8,
ODOTMETH: 8,
ODOTPTR: 8,
@ -1393,6 +1394,12 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
}
fmt.Fprint(s, "]")
case OSLICEHEADER:
if n.List.Len() != 2 {
Fatalf("bad OSLICEHEADER list length %d", n.List.Len())
}
mode.Fprintf(s, "sliceheader{%v,%v,%v}", n.Left, n.List.First(), n.List.Second())
case OCOPY, OCOMPLEX:
mode.Fprintf(s, "%#v(%v, %v)", n.Op, n.Left, n.Right)

View file

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

View file

@ -185,24 +185,6 @@ func (pp *Progs) settext(fn *Node) {
ptxt.From.Type = obj.TYPE_MEM
ptxt.From.Name = obj.NAME_EXTERN
ptxt.From.Sym = fn.Func.lsym
p := pp.Prog(obj.AFUNCDATA)
Addrconst(&p.From, objabi.FUNCDATA_ArgsPointerMaps)
p.To.Type = obj.TYPE_MEM
p.To.Name = obj.NAME_EXTERN
p.To.Sym = &fn.Func.lsym.Func.GCArgs
p = pp.Prog(obj.AFUNCDATA)
Addrconst(&p.From, objabi.FUNCDATA_LocalsPointerMaps)
p.To.Type = obj.TYPE_MEM
p.To.Name = obj.NAME_EXTERN
p.To.Sym = &fn.Func.lsym.Func.GCLocals
p = pp.Prog(obj.AFUNCDATA)
Addrconst(&p.From, objabi.FUNCDATA_RegPointerMaps)
p.To.Type = obj.TYPE_MEM
p.To.Name = obj.NAME_EXTERN
p.To.Sym = &fn.Func.lsym.Func.GCRegs
}
func (f *Func) initLSym() {

View file

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

View file

@ -38,9 +38,10 @@ import (
const (
inlineMaxBudget = 80
inlineExtraAppendCost = 0
inlineExtraCallCost = inlineMaxBudget // default is do not inline, -l=4 enables by using 1 instead.
inlineExtraPanicCost = 1 // do not penalize inlining panics.
inlineExtraThrowCost = inlineMaxBudget // with current (2018-05/1.11) code, inlining runtime.throw does not help.
// default is to inline if there's at most one call. -l=4 overrides this by using 1 instead.
inlineExtraCallCost = inlineMaxBudget * 3 / 4
inlineExtraPanicCost = 1 // do not penalize inlining panics.
inlineExtraThrowCost = inlineMaxBudget // with current (2018-05/1.11) code, inlining runtime.throw does not help.
inlineBigFunctionNodes = 5000 // Functions with this many nodes are considered "big".
inlineBigFunctionMaxCost = 20 // Max cost of inlinee when inlining into a "big" function.
@ -141,6 +142,13 @@ func caninl(fn *Node) {
return
}
// If marked as "go:uintptrescapes", don't inline, since the
// escape information is lost during inlining.
if fn.Func.Pragma&UintptrEscapes != 0 {
reason = "marked as having an escaping uintptr argument"
return
}
// The nowritebarrierrec checker currently works at function
// granularity, so inlining yeswritebarrierrec functions can
// confuse it (#22342). As a workaround, disallow inlining

View file

@ -55,6 +55,7 @@ func TestIntendedInlining(t *testing.T) {
"isDirectIface",
"itabHashFunc",
"noescape",
"pcvalueCacheKey",
"readUnaligned32",
"readUnaligned64",
"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) == 4 && !isQuoted(f[1]) && !isQuoted(f[2]) && isQuoted(f[3]):
f[3] = strings.Trim(f[3], `"`)
if objabi.GOOS == "aix" && f[3] != "" {
// On Aix, library pattern must be "lib.a/object.o"
n := strings.Split(f[3], "/")
if len(n) != 2 || !strings.HasSuffix(n[0], ".a") || !strings.HasSuffix(n[1], ".o") {
p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_dynamic local [remote ["lib.a/object.o"]]`})
return
}
}
default:
p.error(syntax.Error{Pos: pos, Msg: `usage: //go:cgo_import_dynamic local [remote ["library"]]`})
return

View file

@ -7,6 +7,7 @@ package gc
import (
"cmd/compile/internal/syntax"
"reflect"
"runtime"
"testing"
)
@ -49,10 +50,12 @@ func TestPragmaFields(t *testing.T) {
}
func TestPragcgo(t *testing.T) {
var tests = []struct {
type testStruct struct {
in string
want []string
}{
}
var tests = []testStruct{
{`go:cgo_export_dynamic local`, []string{`cgo_export_dynamic`, `local`}},
{`go:cgo_export_dynamic local remote`, []string{`cgo_export_dynamic`, `local`, `remote`}},
{`go:cgo_export_dynamic local' remote'`, []string{`cgo_export_dynamic`, `local'`, `remote'`}},
@ -61,8 +64,6 @@ func TestPragcgo(t *testing.T) {
{`go:cgo_export_static local' remote'`, []string{`cgo_export_static`, `local'`, `remote'`}},
{`go:cgo_import_dynamic local`, []string{`cgo_import_dynamic`, `local`}},
{`go:cgo_import_dynamic local remote`, []string{`cgo_import_dynamic`, `local`, `remote`}},
{`go:cgo_import_dynamic local remote "library"`, []string{`cgo_import_dynamic`, `local`, `remote`, `library`}},
{`go:cgo_import_dynamic local' remote' "lib rary"`, []string{`cgo_import_dynamic`, `local'`, `remote'`, `lib rary`}},
{`go:cgo_import_static local`, []string{`cgo_import_static`, `local`}},
{`go:cgo_import_static local'`, []string{`cgo_import_static`, `local'`}},
{`go:cgo_dynamic_linker "/path/"`, []string{`cgo_dynamic_linker`, `/path/`}},
@ -71,17 +72,50 @@ func TestPragcgo(t *testing.T) {
{`go:cgo_ldflag "a rg"`, []string{`cgo_ldflag`, `a rg`}},
}
if runtime.GOOS != "aix" {
tests = append(tests, []testStruct{
{`go:cgo_import_dynamic local remote "library"`, []string{`cgo_import_dynamic`, `local`, `remote`, `library`}},
{`go:cgo_import_dynamic local' remote' "lib rary"`, []string{`cgo_import_dynamic`, `local'`, `remote'`, `lib rary`}},
}...)
} else {
// cgo_import_dynamic with a library is slightly different on AIX
// as the library field must follow the pattern [libc.a/object.o].
tests = append(tests, []testStruct{
{`go:cgo_import_dynamic local remote "lib.a/obj.o"`, []string{`cgo_import_dynamic`, `local`, `remote`, `lib.a/obj.o`}},
// This test must fail.
{`go:cgo_import_dynamic local' remote' "library"`, []string{`<unknown position>: usage: //go:cgo_import_dynamic local [remote ["lib.a/object.o"]]`}},
}...)
}
var p noder
var nopos syntax.Pos
for _, tt := range tests {
p.pragcgobuf = nil
p.pragcgo(nopos, tt.in)
got := p.pragcgobuf
want := [][]string{tt.want}
if !reflect.DeepEqual(got, want) {
t.Errorf("pragcgo(%q) = %q; want %q", tt.in, got, want)
continue
p.err = make(chan syntax.Error)
gotch := make(chan [][]string)
go func() {
p.pragcgobuf = nil
p.pragcgo(nopos, tt.in)
if p.pragcgobuf != nil {
gotch <- p.pragcgobuf
}
}()
select {
case e := <-p.err:
want := tt.want[0]
if e.Error() != want {
t.Errorf("pragcgo(%q) = %q; want %q", tt.in, e, want)
continue
}
case got := <-gotch:
want := [][]string{tt.want}
if !reflect.DeepEqual(got, want) {
t.Errorf("pragcgo(%q) = %q; want %q", tt.in, got, want)
continue
}
}
}
}

View file

@ -229,6 +229,9 @@ func Main(archInit func(*Arch)) {
flag.BoolVar(&flag_race, "race", false, "enable race detector")
}
objabi.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s'])
if enableTrace {
flag.BoolVar(&trace, "t", false, "trace type-checking")
}
flag.StringVar(&pathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths")
flag.BoolVar(&Debug_vlog, "v", false, "increase debug verbosity")
objabi.Flagcount("w", "debug type checking", &Debug['w'])
@ -488,13 +491,17 @@ func Main(archInit func(*Arch)) {
// Phase 1: const, type, and names and types of funcs.
// This will gather all the information about types
// and methods but doesn't depend on any of it.
//
// We also defer type alias declarations until phase 2
// to avoid cycles like #18640.
// TODO(gri) Remove this again once we have a fix for #25838.
defercheckwidth()
// Don't use range--typecheck can add closures to xtop.
timings.Start("fe", "typecheck", "top1")
for i := 0; i < len(xtop); i++ {
n := xtop[i]
if op := n.Op; op != ODCL && op != OAS && op != OAS2 {
if op := n.Op; op != ODCL && op != OAS && op != OAS2 && (op != ODCLTYPE || !n.Left.Name.Param.Alias) {
xtop[i] = typecheck(n, Etop)
}
}
@ -506,7 +513,7 @@ func Main(archInit func(*Arch)) {
timings.Start("fe", "typecheck", "top2")
for i := 0; i < len(xtop); i++ {
n := xtop[i]
if op := n.Op; op == ODCL || op == OAS || op == OAS2 {
if op := n.Op; op == ODCL || op == OAS || op == OAS2 || op == ODCLTYPE && n.Left.Name.Param.Alias {
xtop[i] = typecheck(n, Etop)
}
}

View file

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

View file

@ -4,9 +4,9 @@ package gc
import "strconv"
const _Op_name = "XXXNAMENONAMETYPEPACKLITERALADDSUBORXORADDSTRADDRANDANDAPPENDARRAYBYTESTRARRAYBYTESTRTMPARRAYRUNESTRSTRARRAYBYTESTRARRAYBYTETMPSTRARRAYRUNEASAS2AS2FUNCAS2RECVAS2MAPRAS2DOTTYPEASOPCALLCALLFUNCCALLMETHCALLINTERCALLPARTCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDCLFIELDDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTINDINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMULDIVMODLSHRSHANDANDNOTNEWNOTCOMPLUSMINUSORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICEHEADERSLICE3SLICE3ARRRECOVERRECVRUNESTRSELRECVSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFBLOCKBREAKCASEXCASECONTINUEDEFEREMPTYFALLFORFORUNTILGOTOIFLABELPROCRANGERETURNSELECTSWITCHTYPESWTCHANTMAPTSTRUCTTINTERTFUNCTARRAYDDDDDDARGINLCALLEFACEITABIDATASPTRCLOSUREVARCFUNCCHECKNILVARDEFVARKILLVARLIVEINDREGSPRETJMPGETGEND"
const _Op_name = "XXXNAMENONAMETYPEPACKLITERALADDSUBORXORADDSTRADDRANDANDAPPENDARRAYBYTESTRARRAYBYTESTRTMPARRAYRUNESTRSTRARRAYBYTESTRARRAYBYTETMPSTRARRAYRUNEASAS2AS2FUNCAS2RECVAS2MAPRAS2DOTTYPEASOPCALLCALLFUNCCALLMETHCALLINTERCALLPARTCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDCLFIELDDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTINDINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMULDIVMODLSHRSHANDANDNOTNEWNOTCOMPLUSMINUSORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECVRUNESTRSELRECVSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFBLOCKBREAKCASEXCASECONTINUEDEFEREMPTYFALLFORFORUNTILGOTOIFLABELPROCRANGERETURNSELECTSWITCHTYPESWTCHANTMAPTSTRUCTTINTERTFUNCTARRAYDDDDDDARGINLCALLEFACEITABIDATASPTRCLOSUREVARCFUNCCHECKNILVARDEFVARKILLVARLIVEINDREGSPRETJMPGETGEND"
var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 36, 39, 45, 49, 55, 61, 73, 88, 100, 112, 127, 139, 141, 144, 151, 158, 165, 175, 179, 183, 191, 199, 208, 216, 219, 224, 231, 238, 244, 253, 261, 269, 275, 279, 288, 295, 299, 302, 309, 317, 325, 332, 338, 341, 347, 354, 362, 366, 373, 381, 383, 385, 387, 389, 391, 393, 396, 401, 409, 412, 421, 424, 428, 436, 443, 452, 455, 458, 461, 464, 467, 470, 476, 479, 482, 485, 489, 494, 498, 503, 508, 514, 519, 523, 528, 536, 544, 555, 561, 570, 577, 581, 588, 595, 603, 607, 611, 615, 622, 629, 637, 643, 648, 653, 657, 662, 670, 675, 680, 684, 687, 695, 699, 701, 706, 710, 715, 721, 727, 733, 739, 744, 748, 755, 761, 766, 772, 775, 781, 788, 793, 797, 802, 806, 816, 821, 829, 835, 842, 849, 857, 863, 867, 870}
var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 36, 39, 45, 49, 55, 61, 73, 88, 100, 112, 127, 139, 141, 144, 151, 158, 165, 175, 179, 183, 191, 199, 208, 216, 219, 224, 231, 238, 244, 253, 261, 269, 275, 279, 288, 295, 299, 302, 309, 317, 325, 332, 338, 341, 347, 354, 362, 366, 373, 381, 383, 385, 387, 389, 391, 393, 396, 401, 409, 412, 421, 424, 428, 436, 443, 452, 455, 458, 461, 464, 467, 470, 476, 479, 482, 485, 489, 494, 498, 503, 508, 514, 519, 523, 528, 536, 544, 550, 559, 570, 577, 581, 588, 595, 603, 607, 611, 615, 622, 629, 637, 643, 648, 653, 657, 662, 670, 675, 680, 684, 687, 695, 699, 701, 706, 710, 715, 721, 727, 733, 739, 744, 748, 755, 761, 766, 772, 775, 781, 788, 793, 797, 802, 806, 816, 821, 829, 835, 842, 849, 857, 863, 867, 870}
func (i Op) String() string {
if i >= Op(len(_Op_index)-1) {

View file

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

View file

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

View file

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

View file

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

View file

@ -12,6 +12,50 @@ import (
"strings"
)
// To enable tracing support (-t flag), set enableTrace to true.
const enableTrace = false
var trace bool
var traceIndent []byte
func tracePrint(title string, n *Node) func(np **Node) {
indent := traceIndent
// guard against nil
var pos, op string
var tc uint8
if n != nil {
pos = linestr(n.Pos)
op = n.Op.String()
tc = n.Typecheck()
}
fmt.Printf("%s: %s%s %p %s %v tc=%d\n", pos, indent, title, n, op, n, tc)
traceIndent = append(traceIndent, ". "...)
return func(np **Node) {
traceIndent = traceIndent[:len(traceIndent)-2]
// if we have a result, use that
if np != nil {
n = *np
}
// guard against nil
// use outer pos, op so we don't get empty pos/op if n == nil (nicer output)
var tc uint8
var typ *types.Type
if n != nil {
pos = linestr(n.Pos)
op = n.Op.String()
tc = n.Typecheck()
typ = n.Type
}
fmt.Printf("%s: %s=> %p %s %v tc=%d type=%#L\n", pos, indent, n, op, n, tc, typ)
}
}
const (
Etop = 1 << iota // evaluated at statement level
Erv // evaluated in value context
@ -31,11 +75,16 @@ const (
var typecheckdefstack []*Node
// resolve ONONAME to definition, if any.
func resolve(n *Node) *Node {
func resolve(n *Node) (res *Node) {
if n == nil || n.Op != ONONAME {
return n
}
// only trace if there's work to do
if enableTrace && trace {
defer tracePrint("resolve", n)(&res)
}
if n.Sym.Pkg != localpkg {
if inimport {
Fatalf("recursive inimport")
@ -150,7 +199,7 @@ var typecheck_tcstack []*Node
// typecheck type checks node n.
// The result of typecheck MUST be assigned back to n, e.g.
// n.Left = typecheck(n.Left, top)
func typecheck(n *Node, top int) *Node {
func typecheck(n *Node, top int) (res *Node) {
// cannot type check until all the source has been parsed
if !typecheckok {
Fatalf("early typecheck")
@ -160,6 +209,11 @@ func typecheck(n *Node, top int) *Node {
return nil
}
// only trace if there's work to do
if enableTrace && trace {
defer tracePrint("typecheck", n)(&res)
}
lno := setlineno(n)
// Skip over parens.
@ -201,8 +255,16 @@ func typecheck(n *Node, top int) *Node {
// since it would expand indefinitely when aliases
// are substituted.
cycle := cycleFor(n)
for _, n := range cycle {
if n.Name != nil && !n.Name.Param.Alias {
for _, n1 := range cycle {
if n1.Name != nil && !n1.Name.Param.Alias {
// Cycle is ok. But if n is an alias type and doesn't
// have a type yet, we have a recursive type declaration
// with aliases that we can't handle properly yet.
// Report an error rather than crashing later.
if n.Name != nil && n.Name.Param.Alias && n.Type == nil {
lineno = n.Pos
Fatalf("cannot handle alias type declaration (issue #25838): %v", n)
}
lineno = lno
return n
}
@ -294,7 +356,11 @@ func indexlit(n *Node) *Node {
// The result of typecheck1 MUST be assigned back to n, e.g.
// n.Left = typecheck1(n.Left, top)
func typecheck1(n *Node, top int) *Node {
func typecheck1(n *Node, top int) (res *Node) {
if enableTrace && trace {
defer tracePrint("typecheck1", n)(&res)
}
switch n.Op {
case OLITERAL, ONAME, ONONAME, OTYPE:
if n.Sym == nil {
@ -1094,11 +1160,15 @@ func typecheck1(n *Node, top int) *Node {
ok |= Erv
t := n.Type
if t == nil {
Fatalf("no type specified for OSLICEHEADER")
}
if !t.IsSlice() {
Fatalf("invalid type %v for OSLICEHEADER", n.Type)
}
if !n.Left.Type.IsUnsafePtr() {
if n.Left == nil || n.Left.Type == nil || !n.Left.Type.IsUnsafePtr() {
Fatalf("need unsafe.Pointer for OSLICEHEADER")
}
@ -2381,7 +2451,11 @@ func lookdot1(errnode *Node, s *types.Sym, t *types.Type, fs *types.Fields, dost
// typecheckMethodExpr checks selector expressions (ODOT) where the
// base expression is a type expression (OTYPE).
func typecheckMethodExpr(n *Node) *Node {
func typecheckMethodExpr(n *Node) (res *Node) {
if enableTrace && trace {
defer tracePrint("typecheckMethodExpr", n)(&res)
}
t := n.Left.Type
// Compute the method set for t.
@ -2924,7 +2998,11 @@ func pushtype(n *Node, t *types.Type) {
// The result of typecheckcomplit MUST be assigned back to n, e.g.
// n.Left = typecheckcomplit(n.Left)
func typecheckcomplit(n *Node) *Node {
func typecheckcomplit(n *Node) (res *Node) {
if enableTrace && trace {
defer tracePrint("typecheckcomplit", n)(&res)
}
lno := lineno
defer func() {
lineno = lno
@ -3337,6 +3415,10 @@ func samesafeexpr(l *Node, r *Node) bool {
// if this assignment is the definition of a var on the left side,
// fill in the var's type.
func typecheckas(n *Node) {
if enableTrace && trace {
defer tracePrint("typecheckas", n)(nil)
}
// delicate little dance.
// the definition of n may refer to this assignment
// as its definition, in which case it will call typecheckas.
@ -3393,6 +3475,10 @@ func checkassignto(src *types.Type, dst *Node) {
}
func typecheckas2(n *Node) {
if enableTrace && trace {
defer tracePrint("typecheckas2", n)(nil)
}
ls := n.List.Slice()
for i1, n1 := range ls {
// delicate little dance.
@ -3521,6 +3607,10 @@ out:
// type check function definition
func typecheckfunc(n *Node) {
if enableTrace && trace {
defer tracePrint("typecheckfunc", n)(nil)
}
for _, ln := range n.Func.Dcl {
if ln.Op == ONAME && (ln.Class() == PPARAM || ln.Class() == PPARAMOUT) {
ln.Name.Decldepth = 1
@ -3593,8 +3683,7 @@ func copytype(n *Node, t *types.Type) {
embedlineno := n.Type.ForwardType().Embedlineno
l := n.Type.ForwardType().Copyto
ptrBase := n.Type.PtrBase
sliceOf := n.Type.SliceOf
cache := n.Type.Cache
// TODO(mdempsky): Fix Type rekinding.
*n.Type = *t
@ -3615,8 +3704,7 @@ func copytype(n *Node, t *types.Type) {
t.Nod = asTypesNode(n)
t.SetDeferwidth(false)
t.PtrBase = ptrBase
t.SliceOf = sliceOf
t.Cache = cache
// Propagate go:notinheap pragma from the Name to the Type.
if n.Name != nil && n.Name.Param != nil && n.Name.Param.Pragma&NotInHeap != 0 {
@ -3637,6 +3725,10 @@ func copytype(n *Node, t *types.Type) {
}
func typecheckdeftype(n *Node) {
if enableTrace && trace {
defer tracePrint("typecheckdeftype", n)(nil)
}
n.Type.Sym = n.Sym
n.SetTypecheck(1)
n.Name.Param.Ntype = typecheck(n.Name.Param.Ntype, Etype)
@ -3654,6 +3746,10 @@ func typecheckdeftype(n *Node) {
}
func typecheckdef(n *Node) {
if enableTrace && trace {
defer tracePrint("typecheckdef", n)(nil)
}
lno := setlineno(n)
if n.Op == ONONAME {
@ -3992,6 +4088,12 @@ func deadcode(fn *Node) {
}
func deadcodeslice(nn Nodes) {
var lastLabel = -1
for i, n := range nn.Slice() {
if n != nil && n.Op == OLABEL {
lastLabel = i
}
}
for i, n := range nn.Slice() {
// Cut is set to true when all nodes after i'th position
// should be removed.
@ -4014,10 +4116,14 @@ func deadcodeslice(nn Nodes) {
// If "then" or "else" branch ends with panic or return statement,
// it is safe to remove all statements after this node.
// isterminating is not used to avoid goto-related complications.
// We must be careful not to deadcode-remove labels, as they
// might be the target of a goto. See issue 28616.
if body := body.Slice(); len(body) != 0 {
switch body[(len(body) - 1)].Op {
case ORETURN, ORETJMP, OPANIC:
cut = true
if i > lastLabel {
cut = true
}
}
}
}

View file

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

View file

@ -384,41 +384,31 @@ func convFuncName(from, to *types.Type) (fnname string, needsaddr bool) {
tkind := to.Tie()
switch from.Tie() {
case 'I':
switch tkind {
case 'I':
if tkind == 'I' {
return "convI2I", false
}
case 'T':
switch {
case from.Size() == 2 && from.Align == 2:
return "convT16", false
case from.Size() == 4 && from.Align == 4 && !types.Haspointers(from):
return "convT32", false
case from.Size() == 8 && from.Align == types.Types[TUINT64].Align && !types.Haspointers(from):
return "convT64", false
case from.IsString():
return "convTstring", false
case from.IsSlice():
return "convTslice", false
}
switch tkind {
case 'E':
switch {
case from.Size() == 2 && from.Align == 2:
return "convT2E16", false
case from.Size() == 4 && from.Align == 4 && !types.Haspointers(from):
return "convT2E32", false
case from.Size() == 8 && from.Align == types.Types[TUINT64].Align && !types.Haspointers(from):
return "convT2E64", false
case from.IsString():
return "convT2Estring", false
case from.IsSlice():
return "convT2Eslice", false
case !types.Haspointers(from):
if !types.Haspointers(from) {
return "convT2Enoptr", true
}
return "convT2E", true
case 'I':
switch {
case from.Size() == 2 && from.Align == 2:
return "convT2I16", false
case from.Size() == 4 && from.Align == 4 && !types.Haspointers(from):
return "convT2I32", false
case from.Size() == 8 && from.Align == types.Types[TUINT64].Align && !types.Haspointers(from):
return "convT2I64", false
case from.IsString():
return "convT2Istring", false
case from.IsSlice():
return "convT2Islice", false
case !types.Haspointers(from):
if !types.Haspointers(from) {
return "convT2Inoptr", true
}
return "convT2I", true
@ -496,7 +486,7 @@ opswitch:
OIND, OSPTR, OITAB, OIDATA, OADDR:
n.Left = walkexpr(n.Left, init)
case OEFACE, OAND, OSUB, OMUL, OADD, OOR, OXOR:
case OEFACE, OAND, OSUB, OMUL, OADD, OOR, OXOR, OLSH, ORSH:
n.Left = walkexpr(n.Left, init)
n.Right = walkexpr(n.Right, init)
@ -548,15 +538,6 @@ opswitch:
n.SetTypecheck(1)
}
case OLSH, ORSH:
n.Left = walkexpr(n.Left, init)
n.Right = walkexpr(n.Right, init)
t := n.Left.Type
n.SetBounded(bounded(n.Right, 8*t.Width))
if Debug['m'] != 0 && n.Bounded() && !Isconst(n.Right, CTINT) {
Warn("shift bounds check elided")
}
case OCOMPLEX:
// Use results from call expression as arguments for complex.
if n.Left == nil && n.Right == nil {
@ -834,16 +815,21 @@ opswitch:
case OCONVIFACE:
n.Left = walkexpr(n.Left, init)
// Optimize convT2E or convT2I as a two-word copy when T is pointer-shaped.
if isdirectiface(n.Left.Type) {
var t *Node
if n.Type.IsEmptyInterface() {
t = typename(n.Left.Type)
} else {
t = itabname(n.Left.Type, n.Type)
fromType := n.Left.Type
toType := n.Type
// typeword generates the type word of the interface value.
typeword := func() *Node {
if toType.IsEmptyInterface() {
return typename(fromType)
}
l := nod(OEFACE, t, n.Left)
l.Type = n.Type
return itabname(fromType, toType)
}
// Optimize convT2E or convT2I as a two-word copy when T is pointer-shaped.
if isdirectiface(fromType) {
l := nod(OEFACE, typeword(), n.Left)
l.Type = toType
l.SetTypecheck(n.Typecheck())
n = l
break
@ -863,11 +849,11 @@ opswitch:
// or creating one on the stack.
var value *Node
switch {
case n.Left.Type.Size() == 0:
case fromType.Size() == 0:
// n.Left is zero-sized. Use zerobase.
cheapexpr(n.Left, init) // Evaluate n.Left for side-effects. See issue 19246.
value = zerobase
case n.Left.Type.IsBoolean() || (n.Left.Type.Size() == 1 && n.Left.Type.IsInteger()):
case fromType.IsBoolean() || (fromType.Size() == 1 && fromType.IsInteger()):
// n.Left is a bool/byte. Use staticbytes[n.Left].
n.Left = cheapexpr(n.Left, init)
value = nod(OINDEX, staticbytes, byteindex(n.Left))
@ -875,23 +861,17 @@ opswitch:
case n.Left.Class() == PEXTERN && n.Left.Name != nil && n.Left.Name.Readonly():
// n.Left is a readonly global; use it directly.
value = n.Left
case !n.Left.Type.IsInterface() && n.Esc == EscNone && n.Left.Type.Width <= 1024:
case !fromType.IsInterface() && n.Esc == EscNone && fromType.Width <= 1024:
// n.Left does not escape. Use a stack temporary initialized to n.Left.
value = temp(n.Left.Type)
value = temp(fromType)
init.Append(typecheck(nod(OAS, value, n.Left), Etop))
}
if value != nil {
// Value is identical to n.Left.
// Construct the interface directly: {type/itab, &value}.
var t *Node
if n.Type.IsEmptyInterface() {
t = typename(n.Left.Type)
} else {
t = itabname(n.Left.Type, n.Type)
}
l := nod(OEFACE, t, typecheck(nod(OADDR, value, nil), Erv))
l.Type = n.Type
l := nod(OEFACE, typeword(), typecheck(nod(OADDR, value, nil), Erv))
l.Type = toType
l.SetTypecheck(n.Typecheck())
n = l
break
@ -903,9 +883,9 @@ opswitch:
// tmp = tmp.type
// }
// e = iface{tmp, i.data}
if n.Type.IsEmptyInterface() && n.Left.Type.IsInterface() && !n.Left.Type.IsEmptyInterface() {
if toType.IsEmptyInterface() && fromType.IsInterface() && !fromType.IsEmptyInterface() {
// Evaluate the input interface.
c := temp(n.Left.Type)
c := temp(fromType)
init.Append(nod(OAS, c, n.Left))
// Get the itab out of the interface.
@ -919,26 +899,43 @@ opswitch:
// Build the result.
e := nod(OEFACE, tmp, ifaceData(c, types.NewPtr(types.Types[TUINT8])))
e.Type = n.Type // assign type manually, typecheck doesn't understand OEFACE.
e.Type = toType // assign type manually, typecheck doesn't understand OEFACE.
e.SetTypecheck(1)
n = e
break
}
var ll []*Node
if n.Type.IsEmptyInterface() {
if !n.Left.Type.IsInterface() {
ll = append(ll, typename(n.Left.Type))
}
} else {
if n.Left.Type.IsInterface() {
ll = append(ll, typename(n.Type))
} else {
ll = append(ll, itabname(n.Left.Type, n.Type))
}
fnname, needsaddr := convFuncName(fromType, toType)
if !needsaddr && !fromType.IsInterface() {
// Use a specialized conversion routine that only returns a data pointer.
// ptr = convT2X(val)
// e = iface{typ/tab, ptr}
fn := syslook(fnname)
dowidth(fromType)
fn = substArgTypes(fn, fromType)
dowidth(fn.Type)
call := nod(OCALL, fn, nil)
call.List.Set1(n.Left)
call = typecheck(call, Erv)
call = walkexpr(call, init)
call = safeexpr(call, init)
e := nod(OEFACE, typeword(), call)
e.Type = toType
e.SetTypecheck(1)
n = e
break
}
var tab *Node
if fromType.IsInterface() {
// convI2I
tab = typename(toType)
} else {
// convT2x
tab = typeword()
}
fnname, needsaddr := convFuncName(n.Left.Type, n.Type)
v := n.Left
if needsaddr {
// Types of large or unknown size are passed by reference.
@ -952,14 +949,13 @@ opswitch:
}
v = nod(OADDR, v, nil)
}
ll = append(ll, v)
dowidth(n.Left.Type)
dowidth(fromType)
fn := syslook(fnname)
fn = substArgTypes(fn, n.Left.Type, n.Type)
fn = substArgTypes(fn, fromType, toType)
dowidth(fn.Type)
n = nod(OCALL, fn, nil)
n.List.Set(ll)
n.List.Set2(tab, v)
n = typecheck(n, Erv)
n = walkexpr(n, init)
@ -1343,14 +1339,17 @@ opswitch:
argtype = types.Types[TINT]
}
m := nod(OSLICEHEADER, nil, nil)
m.Type = t
fn := syslook(fnname)
n.Left = mkcall1(fn, types.Types[TUNSAFEPTR], init, typename(t.Elem()), conv(len, argtype), conv(cap, argtype))
n.Left.SetNonNil(true)
n.List.Set2(conv(len, types.Types[TINT]), conv(cap, types.Types[TINT]))
n.Op = OSLICEHEADER
n.Type = t
n = typecheck(n, Erv)
n = walkexpr(n, init)
m.Left = mkcall1(fn, types.Types[TUNSAFEPTR], init, typename(t.Elem()), conv(len, argtype), conv(cap, argtype))
m.Left.SetNonNil(true)
m.List.Set2(conv(len, types.Types[TINT]), conv(cap, types.Types[TINT]))
m = typecheck(m, Erv)
m = walkexpr(m, init)
n = m
}
case ORUNESTR:

View file

@ -569,7 +569,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
ssa.OpPPC64ROTL, ssa.OpPPC64ROTLW,
ssa.OpPPC64MULHD, ssa.OpPPC64MULHW, ssa.OpPPC64MULHDU, ssa.OpPPC64MULHWU,
ssa.OpPPC64FMUL, ssa.OpPPC64FMULS, ssa.OpPPC64FDIV, ssa.OpPPC64FDIVS, ssa.OpPPC64FCPSGN,
ssa.OpPPC64AND, ssa.OpPPC64OR, ssa.OpPPC64ANDN, ssa.OpPPC64ORN, ssa.OpPPC64NOR, ssa.OpPPC64XOR, ssa.OpPPC64EQV:
ssa.OpPPC64AND, ssa.OpPPC64ANDCC, ssa.OpPPC64OR, ssa.OpPPC64ORCC, ssa.OpPPC64ANDN, ssa.OpPPC64ORN, ssa.OpPPC64NOR, ssa.OpPPC64XOR, ssa.OpPPC64XORCC, ssa.OpPPC64EQV:
r := v.Reg()
r1 := v.Args[0].Reg()
r2 := v.Args[1].Reg()

View file

@ -112,7 +112,7 @@ type Logger interface {
// Logf logs a message from the compiler.
Logf(string, ...interface{})
// Log returns true if logging is not a no-op
// Log reports whether logging is not a no-op
// some logging calls account for more than a few heap allocations.
Log() bool

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

View file

@ -621,7 +621,7 @@ func (f *Func) invalidateCFG() {
f.cachedLoopnest = nil
}
// DebugHashMatch returns true if environment variable evname
// DebugHashMatch reports whether environment variable evname
// 1) is empty (this is a special more-quickly implemented case of 3)
// 2) is "y" or "Y"
// 3) is a suffix of the sha1 hash of name

View file

@ -518,6 +518,13 @@
(LessEqual (InvertFlags x)) -> (GreaterEqual x)
(GreaterEqual (InvertFlags x)) -> (LessEqual x)
// Elide compares of bit tests // TODO need to make both CC and result of ANDCC available.
((EQ|NE|LT|LE|GT|GE) (CMPconst [0] (ANDconst [c] x)) yes no) -> ((EQ|NE|LT|LE|GT|GE) (ANDCCconst [c] x) yes no)
((EQ|NE|LT|LE|GT|GE) (CMPWconst [0] (ANDconst [c] x)) yes no) -> ((EQ|NE|LT|LE|GT|GE) (ANDCCconst [c] x) yes no)
((EQ|NE|LT|LE|GT|GE) (CMPconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> ((EQ|NE|LT|LE|GT|GE) (ANDCC x y) yes no)
((EQ|NE|LT|LE|GT|GE) (CMPconst [0] z:(OR x y)) yes no) && z.Uses == 1 -> ((EQ|NE|LT|LE|GT|GE) (ORCC x y) yes no)
((EQ|NE|LT|LE|GT|GE) (CMPconst [0] z:(XOR x y)) yes no) && z.Uses == 1 -> ((EQ|NE|LT|LE|GT|GE) (XORCC x y) yes no)
// Lowering loads
(Load <t> ptr mem) && (is64BitInt(t) || isPtr(t)) -> (MOVDload 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: "MTVSRD", argLength: 1, reg: gpfp, asm: "MTVSRD", typ: "Float64"}, // move 64 bits of G register into F register
{name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true}, // arg0&arg1
{name: "ANDN", argLength: 2, reg: gp21, asm: "ANDN"}, // arg0&^arg1
{name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true}, // arg0|arg1
{name: "ORN", argLength: 2, reg: gp21, asm: "ORN"}, // arg0|^arg1
{name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true}, // ^(arg0|arg1)
{name: "XOR", argLength: 2, reg: gp21, asm: "XOR", typ: "Int64", commutative: true}, // arg0^arg1
{name: "EQV", argLength: 2, reg: gp21, asm: "EQV", typ: "Int64", commutative: true}, // arg0^^arg1
{name: "NEG", argLength: 1, reg: gp11, asm: "NEG"}, // -arg0 (integer)
{name: "FNEG", argLength: 1, reg: fp11, asm: "FNEG"}, // -arg0 (floating point)
{name: "FSQRT", argLength: 1, reg: fp11, asm: "FSQRT"}, // sqrt(arg0) (floating point)
{name: "FSQRTS", argLength: 1, reg: fp11, asm: "FSQRTS"}, // sqrt(arg0) (floating point, single precision)
{name: "FFLOOR", argLength: 1, reg: fp11, asm: "FRIM"}, // floor(arg0), float64
{name: "FCEIL", argLength: 1, reg: fp11, asm: "FRIP"}, // ceil(arg0), float64
{name: "FTRUNC", argLength: 1, reg: fp11, asm: "FRIZ"}, // trunc(arg0), float64
{name: "FROUND", argLength: 1, reg: fp11, asm: "FRIN"}, // round(arg0), float64
{name: "FABS", argLength: 1, reg: fp11, asm: "FABS"}, // abs(arg0), float64
{name: "FNABS", argLength: 1, reg: fp11, asm: "FNABS"}, // -abs(arg0), float64
{name: "FCPSGN", argLength: 2, reg: fp21, asm: "FCPSGN"}, // copysign arg0 -> arg1, float64
{name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true}, // arg0&arg1
{name: "ANDN", argLength: 2, reg: gp21, asm: "ANDN"}, // arg0&^arg1
{name: "ANDCC", argLength: 2, reg: gp21, asm: "ANDCC", commutative: true, typ: "Flags"}, // arg0&arg1 sets CC
{name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true}, // arg0|arg1
{name: "ORN", argLength: 2, reg: gp21, asm: "ORN"}, // arg0|^arg1
{name: "ORCC", argLength: 2, reg: gp21, asm: "ORCC", commutative: true, typ: "Flags"}, // arg0|arg1 sets CC
{name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true}, // ^(arg0|arg1)
{name: "XOR", argLength: 2, reg: gp21, asm: "XOR", typ: "Int64", commutative: true}, // arg0^arg1
{name: "XORCC", argLength: 2, reg: gp21, asm: "XORCC", commutative: true, typ: "Flags"}, // arg0^arg1 sets CC
{name: "EQV", argLength: 2, reg: gp21, asm: "EQV", typ: "Int64", commutative: true}, // arg0^^arg1
{name: "NEG", argLength: 1, reg: gp11, asm: "NEG"}, // -arg0 (integer)
{name: "FNEG", argLength: 1, reg: fp11, asm: "FNEG"}, // -arg0 (floating point)
{name: "FSQRT", argLength: 1, reg: fp11, asm: "FSQRT"}, // sqrt(arg0) (floating point)
{name: "FSQRTS", argLength: 1, reg: fp11, asm: "FSQRTS"}, // sqrt(arg0) (floating point, single precision)
{name: "FFLOOR", argLength: 1, reg: fp11, asm: "FRIM"}, // floor(arg0), float64
{name: "FCEIL", argLength: 1, reg: fp11, asm: "FRIP"}, // ceil(arg0), float64
{name: "FTRUNC", argLength: 1, reg: fp11, asm: "FRIZ"}, // trunc(arg0), float64
{name: "FROUND", argLength: 1, reg: fp11, asm: "FRIN"}, // round(arg0), float64
{name: "FABS", argLength: 1, reg: fp11, asm: "FABS"}, // abs(arg0), float64
{name: "FNABS", argLength: 1, reg: fp11, asm: "FNABS"}, // -abs(arg0), float64
{name: "FCPSGN", argLength: 2, reg: fp21, asm: "FCPSGN"}, // copysign arg0 -> arg1, float64
{name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int64"}, // arg0|aux
{name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64"}, // arg0^aux

View file

@ -1804,11 +1804,25 @@
// Later passes (deadstore, elim unread auto) will remove the A -> B move, if possible.
// This happens most commonly when B is an autotmp inserted earlier
// during compilation to ensure correctness.
(Move {t1} [s1] dst tmp1 midmem:(Move {t2} [s2] tmp2 src _))
&& s1 == s2
// Take care that overlapping moves are preserved.
// Restrict this optimization to the stack, to avoid duplicating loads from the heap;
// see CL 145208 for discussion.
(Move {t1} [s] dst tmp1 midmem:(Move {t2} [s] tmp2 src _))
&& t1.(*types.Type).Compare(t2.(*types.Type)) == types.CMPeq
&& isSamePtr(tmp1, tmp2)
-> (Move {t1} [s1] dst src midmem)
&& isStackPtr(src)
&& disjoint(src, s, tmp2, s)
&& (disjoint(src, s, dst, s) || isInlinableMemmove(dst, src, s, config))
-> (Move {t1} [s] dst src midmem)
// Same, but for large types that require VarDefs.
(Move {t1} [s] dst tmp1 midmem:(VarDef (Move {t2} [s] tmp2 src _)))
&& t1.(*types.Type).Compare(t2.(*types.Type)) == types.CMPeq
&& isSamePtr(tmp1, tmp2)
&& isStackPtr(src)
&& disjoint(src, s, tmp2, s)
&& (disjoint(src, s, dst, s) || isInlinableMemmove(dst, src, s, config))
-> (Move {t1} [s] dst src midmem)
// Elide self-moves. This only happens rarely (e.g test/fixedbugs/bug277.go).
// However, this rule is needed to prevent the previous rule from looping forever in such cases.

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: "AtomicCompareAndSwap32", argLength: 4, typ: "(Bool,Mem)", hasSideEffects: true}, // if *arg0==arg1, then set *arg0=arg2. Returns true if store happens and new memory.
{name: "AtomicCompareAndSwap64", argLength: 4, typ: "(Bool,Mem)", hasSideEffects: true}, // if *arg0==arg1, then set *arg0=arg2. Returns true if store happens and new memory.
{name: "AtomicCompareAndSwapRel32", argLength: 4, typ: "(Bool,Mem)", hasSideEffects: true}, // if *arg0==arg1, then set *arg0=arg2. Lock release, returns true if store happens and new memory.
{name: "AtomicCompareAndSwapRel32", argLength: 4, typ: "(Bool,Mem)", hasSideEffects: true}, // if *arg0==arg1, then set *arg0=arg2. Lock release, reports whether store happens and new memory.
{name: "AtomicAnd8", argLength: 3, typ: "Mem", hasSideEffects: true}, // *arg0 &= arg1. arg2=memory. Returns memory.
{name: "AtomicOr8", argLength: 3, typ: "Mem", hasSideEffects: true}, // *arg0 |= arg1. arg2=memory. Returns memory.

View file

@ -6,7 +6,7 @@
// This program generates Go code that applies rewrite rules to a Value.
// The generated code implements a function of type func (v *Value) bool
// which returns true iff if did something.
// which reports whether if did something.
// Ideas stolen from Swift: http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-2000-2.html
package main
@ -386,7 +386,7 @@ func genRules(arch arch) {
}
}
// genMatch returns true if the match can fail.
// genMatch reports whether the match can fail.
func genMatch(w io.Writer, arch arch, match string, loc string) bool {
return genMatch0(w, arch, match, "v", map[string]struct{}{}, true, loc)
}
@ -623,7 +623,7 @@ outer:
return r
}
// isBlock returns true if this op is a block opcode.
// isBlock reports whether this op is a block opcode.
func isBlock(name string, arch arch) bool {
for _, b := range genericBlocks {
if b.name == name {
@ -768,7 +768,7 @@ func typeName(typ string) string {
}
}
// unbalanced returns true if there aren't the same number of ( and ) in the string.
// unbalanced reports whether there aren't the same number of ( and ) in the string.
func unbalanced(s string) bool {
var left, right int
for _, c := range s {

View file

@ -1663,10 +1663,13 @@ const (
OpPPC64MTVSRD
OpPPC64AND
OpPPC64ANDN
OpPPC64ANDCC
OpPPC64OR
OpPPC64ORN
OpPPC64ORCC
OpPPC64NOR
OpPPC64XOR
OpPPC64XORCC
OpPPC64EQV
OpPPC64NEG
OpPPC64FNEG
@ -22202,6 +22205,21 @@ var opcodeTable = [...]opInfo{
},
},
},
{
name: "ANDCC",
argLen: 2,
commutative: true,
asm: ppc64.AANDCC,
reg: regInfo{
inputs: []inputInfo{
{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
{1, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
},
outputs: []outputInfo{
{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
},
},
},
{
name: "OR",
argLen: 2,
@ -22231,6 +22249,21 @@ var opcodeTable = [...]opInfo{
},
},
},
{
name: "ORCC",
argLen: 2,
commutative: true,
asm: ppc64.AORCC,
reg: regInfo{
inputs: []inputInfo{
{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
{1, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
},
outputs: []outputInfo{
{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
},
},
},
{
name: "NOR",
argLen: 2,
@ -22261,6 +22294,21 @@ var opcodeTable = [...]opInfo{
},
},
},
{
name: "XORCC",
argLen: 2,
commutative: true,
asm: ppc64.AXORCC,
reg: regInfo{
inputs: []inputInfo{
{0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
{1, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
},
outputs: []outputInfo{
{0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
},
},
},
{
name: "EQV",
argLen: 2,

View file

@ -781,7 +781,7 @@ func (po *poset) DotDump(fn string, title string) error {
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
// to tell.
// Complexity is O(n).
@ -799,7 +799,7 @@ func (po *poset) Ordered(n1, n2 *Value) bool {
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
// to tell.
// 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))
}
// 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
// to tell.
// Complexity is O(1).
@ -832,7 +832,7 @@ func (po *poset) Equal(n1, n2 *Value) bool {
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
// to tell.
// 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))
}
// uaddOvf returns true if unsigned a+b would overflow.
// uaddOvf reports whether unsigned a+b would overflow.
func uaddOvf(a, b int64) bool {
return uint64(a)+uint64(b) < uint64(a)
}
@ -530,6 +530,13 @@ func isSamePtr(p1, p2 *Value) bool {
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)
// does not overlap with [p2:p2+n2).
// 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) {
base, offset = ptr, 0
if base.Op == OpOffPtr {
for base.Op == OpOffPtr {
offset += base.AuxInt
base = base.Args[0]
}

View file

@ -30996,6 +30996,143 @@ func rewriteBlockPPC64(b *Block) bool {
b.Aux = nil
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:
// match: (GE (FlagEQ) yes no)
// cond:
@ -31051,6 +31188,143 @@ func rewriteBlockPPC64(b *Block) bool {
b.Aux = nil
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:
// match: (GT (FlagEQ) yes no)
// cond:
@ -31107,6 +31381,143 @@ func rewriteBlockPPC64(b *Block) bool {
b.Aux = nil
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:
// match: (If (Equal cc) yes no)
// cond:
@ -31318,6 +31729,143 @@ func rewriteBlockPPC64(b *Block) bool {
b.Aux = nil
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:
// match: (LT (FlagEQ) yes no)
// cond:
@ -31374,6 +31922,143 @@ func rewriteBlockPPC64(b *Block) bool {
b.Aux = nil
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:
// match: (NE (CMPWconst [0] (Equal cc)) yes no)
// cond:
@ -31689,6 +32374,143 @@ func rewriteBlockPPC64(b *Block) bool {
b.Aux = nil
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
}

View file

@ -17234,6 +17234,8 @@ func rewriteValuegeneric_OpMove_10(v *Value) bool {
func rewriteValuegeneric_OpMove_20(v *Value) bool {
b := v.Block
_ = 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 _)))))))
// 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)))))
@ -17355,11 +17357,11 @@ func rewriteValuegeneric_OpMove_20(v *Value) bool {
v.AddArg(v1)
return true
}
// match: (Move {t1} [s1] dst tmp1 midmem:(Move {t2} [s2] tmp2 src _))
// cond: s1 == s2 && t1.(*types.Type).Compare(t2.(*types.Type)) == types.CMPeq && isSamePtr(tmp1, tmp2)
// result: (Move {t1} [s1] dst src midmem)
// match: (Move {t1} [s] dst tmp1 midmem:(Move {t2} [s] tmp2 src _))
// cond: t1.(*types.Type).Compare(t2.(*types.Type)) == types.CMPeq && isSamePtr(tmp1, tmp2) && isStackPtr(src) && disjoint(src, s, tmp2, s) && (disjoint(src, s, dst, s) || isInlinableMemmove(dst, src, s, config))
// result: (Move {t1} [s] dst src midmem)
for {
s1 := v.AuxInt
s := v.AuxInt
t1 := v.Aux
_ = v.Args[2]
dst := v.Args[0]
@ -17368,16 +17370,53 @@ func rewriteValuegeneric_OpMove_20(v *Value) bool {
if midmem.Op != OpMove {
break
}
s2 := midmem.AuxInt
if midmem.AuxInt != s {
break
}
t2 := midmem.Aux
_ = midmem.Args[2]
tmp2 := midmem.Args[0]
src := midmem.Args[1]
if !(s1 == s2 && t1.(*types.Type).Compare(t2.(*types.Type)) == types.CMPeq && isSamePtr(tmp1, tmp2)) {
if !(t1.(*types.Type).Compare(t2.(*types.Type)) == types.CMPeq && isSamePtr(tmp1, tmp2) && isStackPtr(src) && disjoint(src, s, tmp2, s) && (disjoint(src, s, dst, s) || isInlinableMemmove(dst, src, s, config))) {
break
}
v.reset(OpMove)
v.AuxInt = s1
v.AuxInt = s
v.Aux = t1
v.AddArg(dst)
v.AddArg(src)
v.AddArg(midmem)
return true
}
// match: (Move {t1} [s] dst tmp1 midmem:(VarDef (Move {t2} [s] tmp2 src _)))
// cond: t1.(*types.Type).Compare(t2.(*types.Type)) == types.CMPeq && isSamePtr(tmp1, tmp2) && isStackPtr(src) && disjoint(src, s, tmp2, s) && (disjoint(src, s, dst, s) || isInlinableMemmove(dst, src, s, config))
// result: (Move {t1} [s] dst src midmem)
for {
s := v.AuxInt
t1 := v.Aux
_ = v.Args[2]
dst := v.Args[0]
tmp1 := v.Args[1]
midmem := v.Args[2]
if midmem.Op != OpVarDef {
break
}
midmem_0 := midmem.Args[0]
if midmem_0.Op != OpMove {
break
}
if midmem_0.AuxInt != s {
break
}
t2 := midmem_0.Aux
_ = midmem_0.Args[2]
tmp2 := midmem_0.Args[0]
src := midmem_0.Args[1]
if !(t1.(*types.Type).Compare(t2.(*types.Type)) == types.CMPeq && isSamePtr(tmp1, tmp2) && isStackPtr(src) && disjoint(src, s, tmp2, s) && (disjoint(src, s, dst, s) || isInlinableMemmove(dst, src, s, config))) {
break
}
v.reset(OpMove)
v.AuxInt = s
v.Aux = t1
v.AddArg(dst)
v.AddArg(src)

View file

@ -58,11 +58,13 @@
87: if a == 0 { //gdb-opt=(a,n,t)
86: for i, a := range hist {
87: if a == 0 { //gdb-opt=(a,n,t)
92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
91: n += a
90: t += i * a
92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
86: for i, a := range hist {
87: if a == 0 { //gdb-opt=(a,n,t)
92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
91: n += a
90: t += i * a
92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
@ -70,11 +72,13 @@
87: if a == 0 { //gdb-opt=(a,n,t)
86: for i, a := range hist {
87: if a == 0 { //gdb-opt=(a,n,t)
92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
91: n += a
90: t += i * a
92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
86: for i, a := range hist {
87: if a == 0 { //gdb-opt=(a,n,t)
92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
91: n += a
90: t += i * a
92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)

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)
91: n += a
90: t += i * a
92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
86: for i, a := range hist {
87: if a == 0 { //gdb-opt=(a,n,t)
a = 3
@ -131,6 +132,7 @@ t = 3
92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
91: n += a
90: t += i * a
92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
86: for i, a := range hist {
87: if a == 0 { //gdb-opt=(a,n,t)
a = 0
@ -144,6 +146,7 @@ t = 9
92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
91: n += a
90: t += i * a
92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
86: for i, a := range hist {
87: if a == 0 { //gdb-opt=(a,n,t)
a = 1
@ -152,6 +155,7 @@ t = 17
92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
91: n += a
90: t += i * a
92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t)
86: for i, a := range hist {
87: if a == 0 { //gdb-opt=(a,n,t)
a = 0

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

View file

@ -149,8 +149,11 @@ type Type struct {
Nod *Node // canonical OTYPE node
Orig *Type // original type (type literal or predefined type)
SliceOf *Type
PtrBase *Type
// Cache of composite types, with this type being the element type.
Cache struct {
ptr *Type // *T, or nil
slice *Type // []T, or nil
}
Sym *Sym // symbol containing name, for named types
Vargen int32 // unique name for OTYPE/ONAME
@ -488,7 +491,7 @@ func NewArray(elem *Type, bound int64) *Type {
// NewSlice returns the slice Type with element type elem.
func NewSlice(elem *Type) *Type {
if t := elem.SliceOf; t != nil {
if t := elem.Cache.slice; t != nil {
if t.Elem() != elem {
Fatalf("elem mismatch")
}
@ -497,7 +500,7 @@ func NewSlice(elem *Type) *Type {
t := New(TSLICE)
t.Extra = Slice{Elem: elem}
elem.SliceOf = t
elem.Cache.slice = t
return t
}
@ -551,7 +554,7 @@ func NewPtr(elem *Type) *Type {
Fatalf("NewPtr: pointer to elem Type is nil")
}
if t := elem.PtrBase; t != nil {
if t := elem.Cache.ptr; t != nil {
if t.Elem() != elem {
Fatalf("NewPtr: elem mismatch")
}
@ -563,7 +566,7 @@ func NewPtr(elem *Type) *Type {
t.Width = int64(Widthptr)
t.Align = uint8(Widthptr)
if NewPtrCacheEnabled {
elem.PtrBase = t
elem.Cache.ptr = t
}
return t
}
@ -662,23 +665,18 @@ func SubstAny(t *Type, types *[]*Type) *Type {
}
case TSTRUCT:
// Make a copy of all fields, including ones whose type does not change.
// This prevents aliasing across functions, which can lead to later
// fields getting their Offset incorrectly overwritten.
fields := t.FieldSlice()
var nfs []*Field
nfs := make([]*Field, len(fields))
for i, f := range fields {
nft := SubstAny(f.Type, types)
if nft == f.Type {
continue
}
if nfs == nil {
nfs = append([]*Field(nil), fields...)
}
nfs[i] = f.Copy()
nfs[i].Type = nft
}
if nfs != nil {
t = t.copy()
t.SetFields(nfs)
}
t = t.copy()
t.SetFields(nfs)
}
return t
@ -1258,6 +1256,11 @@ func (t *Type) IsPtr() bool {
return t.Etype == TPTR
}
// IsPtrElem reports whether t is the element of a pointer (to t).
func (t *Type) IsPtrElem() bool {
return t.Cache.ptr != nil
}
// IsUnsafePtr reports whether t is an unsafe pointer.
func (t *Type) IsUnsafePtr() bool {
return t.Etype == TUNSAFEPTR

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.
// It returns true if it makes any changes.
// It reports whether it makes any changes.
func renameTop(f *ast.File, old, new string) bool {
var fixed bool

View file

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

View file

@ -123,7 +123,7 @@ var hashFileCache struct {
m map[string][HashSize]byte
}
// HashFile returns the hash of the named file.
// FileHash returns the hash of the named file.
// It caches repeated lookups for a given file,
// and the cache entry for a file can be initialized
// using SetFileHash.

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

View file

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

View file

@ -154,7 +154,7 @@ func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (*File
return f, nil
}
var goVersionRE = regexp.MustCompile(`([1-9][0-9]*)\.(0|[1-9][0-9]*)`)
var GoVersionRE = regexp.MustCompile(`([1-9][0-9]*)\.(0|[1-9][0-9]*)`)
func (f *File) add(errs *bytes.Buffer, line *Line, verb string, args []string, fix VersionFixer, strict bool) {
// If strict is false, this module is a dependency.
@ -181,7 +181,7 @@ func (f *File) add(errs *bytes.Buffer, line *Line, verb string, args []string, f
fmt.Fprintf(errs, "%s:%d: repeated go statement\n", f.Syntax.Name, line.Start.Line)
return
}
if len(args) != 1 || !goVersionRE.MatchString(args[0]) {
if len(args) != 1 || !GoVersionRE.MatchString(args[0]) {
fmt.Fprintf(errs, "%s:%d: usage: go 1.23\n", f.Syntax.Name, line.Start.Line)
return
}
@ -477,6 +477,22 @@ func (f *File) Cleanup() {
f.Syntax.Cleanup()
}
func (f *File) AddGoStmt(version string) error {
if !GoVersionRE.MatchString(version) {
return fmt.Errorf("invalid language version string %q", version)
}
if f.Go == nil {
f.Go = &Go{
Version: version,
Syntax: f.Syntax.addLine(nil, "go", version),
}
} else {
f.Go.Version = version
f.Syntax.updateLine(f.Go.Syntax, "go", version)
}
return nil
}
func (f *File) AddRequire(path, vers string) error {
need := true
for _, r := range f.Require {

View file

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

View file

@ -19,6 +19,7 @@ import (
"cmd/go/internal/search"
"encoding/json"
"fmt"
"go/build"
"io/ioutil"
"os"
"path"
@ -335,6 +336,8 @@ func legacyModInit() {
modFile.AddModuleStmt(path)
}
addGoStmt()
for _, name := range altConfigs {
cfg := filepath.Join(ModRoot, name)
data, err := ioutil.ReadFile(cfg)
@ -357,6 +360,25 @@ func legacyModInit() {
}
}
// InitGoStmt adds a go statement, unless there already is one.
func InitGoStmt() {
if modFile.Go == nil {
addGoStmt()
}
}
// addGoStmt adds a go statement referring to the current version.
func addGoStmt() {
tags := build.Default.ReleaseTags
version := tags[len(tags)-1]
if !strings.HasPrefix(version, "go") || !modfile.GoVersionRE.MatchString(version[2:]) {
base.Fatalf("go: unrecognized default version %q", version)
}
if err := modFile.AddGoStmt(version[2:]); err != nil {
base.Fatalf("go: internal error: %v", err)
}
}
var altConfigs = []string{
"Gopkg.lock",

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
regardless of -timeout setting.
` + strings.TrimSpace(testFlag1) + ` See 'go help testflag' for details.
For more about build flags, see 'go help build'.
For more about specifying packages, see 'go help packages'.
See also: go build, go vet.
`,
}
const testFlag1 = `
In addition to the build flags, the flags handled by 'go test' itself are:
-args
@ -164,15 +154,13 @@ In addition to the build flags, the flags handled by 'go test' itself are:
The test still runs (unless -c or -i is specified).
The test binary also accepts flags that control execution of the test; these
flags are also accessible by 'go test'.
`
flags are also accessible by 'go test'. See 'go help testflag' for details.
// Usage prints the usage message for 'go test -h' and exits.
func Usage() {
os.Stderr.WriteString("usage: " + testUsage + "\n\n" +
strings.TrimSpace(testFlag1) + "\n\n\t" +
strings.TrimSpace(testFlag2) + "\n")
os.Exit(2)
For more about build flags, see 'go help build'.
For more about specifying packages, see 'go help packages'.
See also: go build, go vet.
`,
}
var HelpTestflag = &base.Command{
@ -190,11 +178,6 @@ options of pprof control how the information is presented.
The following flags are recognized by the 'go test' command and
control the execution of any test:
` + strings.TrimSpace(testFlag2) + `
`,
}
const testFlag2 = `
-bench regexp
Run only those benchmarks matching a regular expression.
By default, no benchmarks are run.
@ -414,7 +397,8 @@ In the first example, the -x and the second -v are passed through to the
test binary unchanged and with no effect on the go command itself.
In the second example, the argument math is passed through to the test
binary, instead of being interpreted as the package list.
`
`,
}
var HelpTestfunc = &base.Command{
UsageLine: "testfunc",
@ -532,7 +516,7 @@ var testVetFlags = []string{
func runTest(cmd *base.Command, args []string) {
modload.LoadTests = true
pkgArgs, testArgs = testFlags(args)
pkgArgs, testArgs = testFlags(cmd.Usage, args)
work.FindExecCmd() // initialize cached result

View file

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

View file

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

View file

@ -23,24 +23,43 @@ import (
// go vet flag processing
//
// We query the flags of the tool specified by GOVETTOOL (default:
// cmd/vet) and accept any of those flags plus any flag valid for 'go
// build'. The tool must support -flags, which prints a description of
// its flags in JSON to stdout.
// We query the flags of the tool specified by -vettool and accept any
// of those flags plus any flag valid for 'go build'. The tool must
// support -flags, which prints a description of its flags in JSON to
// stdout.
// GOVETTOOL specifies the vet command to run.
// This must be an environment variable because
// we need it before flag processing, as we execute
// $GOVETTOOL to discover the set of flags it supports.
// vetTool specifies the vet command to run.
// Any tool that supports the (still unpublished) vet
// command-line protocol may be supplied; see
// golang.org/x/tools/go/analysis/unitchecker for one
// implementation. It is also used by tests.
//
// Using an environment variable also makes it easy for users to opt in
// to (and later, opt out of) the new cmd/vet analysis driver during the
// transition. It is also used by tests.
var vetTool = os.Getenv("GOVETTOOL")
// The default behavior (vetTool=="") runs 'go tool vet'.
//
var vetTool string // -vettool
func init() {
// Extract -vettool by ad hoc flag processing:
// its value is needed even before we can declare
// the flags available during main flag processing.
for i, arg := range os.Args {
if arg == "-vettool" || arg == "--vettool" {
if i+1 >= len(os.Args) {
log.Fatalf("%s requires a filename", arg)
}
vetTool = os.Args[i+1]
break
} else if strings.HasPrefix(arg, "-vettool=") ||
strings.HasPrefix(arg, "--vettool=") {
vetTool = arg[strings.IndexByte(arg, '=')+1:]
break
}
}
}
// vetFlags processes the command line, splitting it at the first non-flag
// into the list of flags and list of packages.
func vetFlags(args []string) (passToVet, packageNames []string) {
func vetFlags(usage func(), args []string) (passToVet, packageNames []string) {
// Query the vet command for its flags.
tool := vetTool
if tool != "" {
@ -94,6 +113,9 @@ func vetFlags(args []string) (passToVet, packageNames []string) {
// Add build flags to vetFlagDefn.
var cmd base.Command
work.AddBuildFlags(&cmd)
// This flag declaration is a placeholder:
// -vettool is actually parsed by the init function above.
cmd.Flag.StringVar(new(string), "vettool", "", "path to vet tool binary")
cmd.Flag.VisitAll(func(f *flag.Flag) {
vetFlagDefn = append(vetFlagDefn, &cmdflag.Defn{
Name: f.Name,
@ -108,7 +130,7 @@ func vetFlags(args []string) (passToVet, packageNames []string) {
return args[:i], args[i:]
}
f, value, extraWord := cmdflag.Parse("vet", vetFlagDefn, args, i)
f, value, extraWord := cmdflag.Parse("vet", usage, vetFlagDefn, args, i)
if f == nil {
fmt.Fprintf(os.Stderr, "vet: flag %q not defined\n", args[i])
fmt.Fprintf(os.Stderr, "Run \"go help vet\" for more information\n")

View file

@ -178,7 +178,8 @@ func (b *Builder) toolID(name string) string {
path := base.Tool(name)
desc := "go tool " + name
// Special case: undocumented $GOVETTOOL overrides usual vet, for testing vet.
// Special case: undocumented -vettool overrides usual vet,
// for testing vet or supplying an alternative analysis tool.
if name == "vet" && VetTool != "" {
path = VetTool
desc = VetTool

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)
}
if p.Module != nil && !allowedVersion(p.Module.GoVersion) {
return fmt.Errorf("module requires Go %s", p.Module.GoVersion)
}
if err := b.Mkdir(a.Objdir); err != nil {
return err
}
@ -638,12 +634,19 @@ func (b *Builder) build(a *Action) (err error) {
objpkg := objdir + "_pkg_.a"
ofile, out, err := BuildToolchain.gc(b, a, objpkg, icfg.Bytes(), len(sfiles) > 0, gofiles)
if len(out) > 0 {
b.showOutput(a, a.Package.Dir, a.Package.Desc(), b.processOutput(out))
output := b.processOutput(out)
if p.Module != nil && !allowedVersion(p.Module.GoVersion) {
output += "note: module requires Go " + p.Module.GoVersion
}
b.showOutput(a, a.Package.Dir, a.Package.Desc(), output)
if err != nil {
return errPrintedOutput
}
}
if err != nil {
if p.Module != nil && !allowedVersion(p.Module.GoVersion) {
b.showOutput(a, a.Package.Dir, a.Package.Desc(), "note: module requires Go "+p.Module.GoVersion)
}
return err
}
if ofile != objpkg {

View file

@ -53,6 +53,9 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg []byte, a
pkgpath = "main"
}
gcargs := []string{"-p", pkgpath}
if p.Module != nil && p.Module.GoVersion != "" && allowedVersion(p.Module.GoVersion) {
gcargs = append(gcargs, "-lang=go"+p.Module.GoVersion)
}
if p.Standard {
gcargs = append(gcargs, "-std")
}

View file

@ -235,17 +235,6 @@ func init() {
}
func mainUsage() {
// special case "go test -h"
if len(os.Args) > 1 && os.Args[1] == "test" {
test.Usage()
}
// Since vet shares code with test in cmdflag, it doesn't show its
// command usage properly. For now, special case it too.
// TODO(mvdan): fix the cmdflag package instead; see
// golang.org/issue/26999
if len(os.Args) > 1 && os.Args[1] == "vet" {
vet.CmdVet.Usage()
}
help.PrintUsage(os.Stderr, base.Go)
os.Exit(2)
}

View file

@ -11,6 +11,7 @@ import (
"bytes"
"context"
"fmt"
"go/build"
"internal/testenv"
"io/ioutil"
"os"
@ -104,6 +105,7 @@ func (ts *testScript) setup() {
"GOROOT=" + testGOROOT,
tempEnvName() + "=" + filepath.Join(ts.workdir, "tmp"),
"devnull=" + os.DevNull,
"goversion=" + goVersion(ts),
":=" + string(os.PathListSeparator),
}
@ -130,6 +132,16 @@ func (ts *testScript) setup() {
}
}
// goVersion returns the current Go version.
func goVersion(ts *testScript) string {
tags := build.Default.ReleaseTags
version := tags[len(tags)-1]
if !regexp.MustCompile(`^go([1-9][0-9]*)\.(0|[1-9][0-9]*)$`).MatchString(version) {
ts.fatalf("invalid go version %q", version)
}
return version[2:]
}
var execCache par.Cache
// run runs the test script.
@ -331,6 +343,7 @@ var scriptCmds = map[string]func(*testScript, bool, []string){
"addcrlf": (*testScript).cmdAddcrlf,
"cd": (*testScript).cmdCd,
"cmp": (*testScript).cmdCmp,
"cmpenv": (*testScript).cmdCmpenv,
"cp": (*testScript).cmdCp,
"env": (*testScript).cmdEnv,
"exec": (*testScript).cmdExec,
@ -396,7 +409,21 @@ func (ts *testScript) cmdCmp(neg bool, args []string) {
if len(args) != 2 {
ts.fatalf("usage: cmp file1 file2")
}
ts.doCmdCmp(args, false)
}
// cmpenv compares two files with environment variable substitution.
func (ts *testScript) cmdCmpenv(neg bool, args []string) {
if neg {
ts.fatalf("unsupported: ! cmpenv")
}
if len(args) != 2 {
ts.fatalf("usage: cmpenv file1 file2")
}
ts.doCmdCmp(args, true)
}
func (ts *testScript) doCmdCmp(args []string, env bool) {
name1, name2 := args[0], args[1]
var text1, text2 string
if name1 == "stdout" {
@ -413,6 +440,11 @@ func (ts *testScript) cmdCmp(neg bool, args []string) {
ts.check(err)
text2 = string(data)
if env {
text1 = ts.expand(text1)
text2 = ts.expand(text2)
}
if text1 == text2 {
return
}

View file

@ -36,6 +36,7 @@ Scripts also have access to these other environment variables:
PATH=<actual PATH>
TMPDIR=$WORK/tmp
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.
@ -92,6 +93,10 @@ The commands are:
from the most recent exec or go command.
(If the files have differing content, the failure prints a diff.)
- cmpenv file1 file2
Like cmp, but environment variables are substituted in the file contents
before the comparison. For example, $GOOS is replaced by the target GOOS.
- cp src... dst
Copy the listed files to the target file or existing directory.

View file

@ -35,7 +35,13 @@ stderr 'Run ''go help mod'' for usage.'
stderr 'usage: go vet'
stderr 'Run ''go help vet'' for details'
# Earlier versions of Go printed a large document here, instead of these two
# lines.
! go test -h
stderr 'usage: go test'
stderr 'Run ''go help test'' for details'
# go help get shows usage for get
go help get
stdout 'usage: go get'
stdout 'get when using GOPATH'
stdout 'get when using GOPATH'

View file

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

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

View file

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

View file

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

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 {
return abbrevs[die.Abbrev].children != 0
}

View file

@ -414,6 +414,8 @@ const (
C_BITCON // bitfield and logical immediate masks
C_ADDCON2 // 24-bit constant
C_LCON // 32-bit constant
C_MOVCON2 // a constant that can be loaded with one MOVZ/MOVN and one MOVK
C_MOVCON3 // a constant that can be loaded with one MOVZ/MOVN and two MOVKs
C_VCON // 64-bit constant
C_FCON // floating-point constant
C_VCONADDR // 64-bit memory address

View file

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

View file

@ -198,9 +198,15 @@ var optab = []Optab{
{ACMP, C_BITCON, C_RSP, C_NONE, C_NONE, 62, 8, 0, 0, 0},
{AADD, C_ADDCON2, C_RSP, C_NONE, C_RSP, 48, 8, 0, 0, 0},
{AADD, C_ADDCON2, C_NONE, C_NONE, C_RSP, 48, 8, 0, 0, 0},
{AADD, C_VCON, C_RSP, C_NONE, C_RSP, 13, 8, 0, LFROM, 0},
{AADD, C_VCON, C_NONE, C_NONE, C_RSP, 13, 8, 0, LFROM, 0},
{ACMP, C_VCON, C_REG, C_NONE, C_NONE, 13, 8, 0, LFROM, 0},
{AADD, C_MOVCON2, C_RSP, C_NONE, C_RSP, 13, 12, 0, 0, 0},
{AADD, C_MOVCON2, C_NONE, C_NONE, C_RSP, 13, 12, 0, 0, 0},
{AADD, C_MOVCON3, C_RSP, C_NONE, C_RSP, 13, 16, 0, 0, 0},
{AADD, C_MOVCON3, C_NONE, C_NONE, C_RSP, 13, 16, 0, 0, 0},
{AADD, C_VCON, C_RSP, C_NONE, C_RSP, 13, 20, 0, 0, 0},
{AADD, C_VCON, C_NONE, C_NONE, C_RSP, 13, 20, 0, 0, 0},
{ACMP, C_MOVCON2, C_REG, C_NONE, C_NONE, 13, 12, 0, 0, 0},
{ACMP, C_MOVCON3, C_REG, C_NONE, C_NONE, 13, 16, 0, 0, 0},
{ACMP, C_VCON, C_REG, C_NONE, C_NONE, 13, 20, 0, 0, 0},
{AADD, C_SHIFT, C_REG, C_NONE, C_REG, 3, 4, 0, 0, 0},
{AADD, C_SHIFT, C_NONE, C_NONE, C_REG, 3, 4, 0, 0, 0},
{AMVN, C_SHIFT, C_NONE, C_NONE, C_REG, 3, 4, 0, 0, 0},
@ -255,11 +261,21 @@ var optab = []Optab{
{AANDS, C_MOVCON, C_REG, C_NONE, C_REG, 62, 8, 0, 0, 0},
{AANDS, C_MOVCON, C_NONE, C_NONE, C_REG, 62, 8, 0, 0, 0},
{ATST, C_MOVCON, C_REG, C_NONE, C_NONE, 62, 8, 0, 0, 0},
{AAND, C_VCON, C_REG, C_NONE, C_REG, 28, 8, 0, LFROM, 0},
{AAND, C_VCON, C_NONE, C_NONE, C_REG, 28, 8, 0, LFROM, 0},
{AANDS, C_VCON, C_REG, C_NONE, C_REG, 28, 8, 0, LFROM, 0},
{AANDS, C_VCON, C_NONE, C_NONE, C_REG, 28, 8, 0, LFROM, 0},
{ATST, C_VCON, C_REG, C_NONE, C_NONE, 28, 8, 0, LFROM, 0},
{AAND, C_MOVCON2, C_REG, C_NONE, C_REG, 28, 12, 0, 0, 0},
{AAND, C_MOVCON2, C_NONE, C_NONE, C_REG, 28, 12, 0, 0, 0},
{AAND, C_MOVCON3, C_REG, C_NONE, C_REG, 28, 16, 0, 0, 0},
{AAND, C_MOVCON3, C_NONE, C_NONE, C_REG, 28, 16, 0, 0, 0},
{AAND, C_VCON, C_REG, C_NONE, C_REG, 28, 20, 0, 0, 0},
{AAND, C_VCON, C_NONE, C_NONE, C_REG, 28, 20, 0, 0, 0},
{AANDS, C_MOVCON2, C_REG, C_NONE, C_REG, 28, 12, 0, 0, 0},
{AANDS, C_MOVCON2, C_NONE, C_NONE, C_REG, 28, 12, 0, 0, 0},
{AANDS, C_MOVCON3, C_REG, C_NONE, C_REG, 28, 16, 0, 0, 0},
{AANDS, C_MOVCON3, C_NONE, C_NONE, C_REG, 28, 16, 0, 0, 0},
{AANDS, C_VCON, C_REG, C_NONE, C_REG, 28, 20, 0, 0, 0},
{AANDS, C_VCON, C_NONE, C_NONE, C_REG, 28, 20, 0, 0, 0},
{ATST, C_MOVCON2, C_REG, C_NONE, C_NONE, 28, 12, 0, 0, 0},
{ATST, C_MOVCON3, C_REG, C_NONE, C_NONE, 28, 16, 0, 0, 0},
{ATST, C_VCON, C_REG, C_NONE, C_NONE, 28, 20, 0, 0, 0},
{AAND, C_SHIFT, C_REG, C_NONE, C_REG, 3, 4, 0, 0, 0},
{AAND, C_SHIFT, C_NONE, C_NONE, C_REG, 3, 4, 0, 0, 0},
{AANDS, C_SHIFT, C_REG, C_NONE, C_REG, 3, 4, 0, 0, 0},
@ -278,8 +294,10 @@ var optab = []Optab{
{AMOVD, C_MOVCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0},
{AMOVW, C_BITCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0},
{AMOVD, C_BITCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0},
{AMOVW, C_LCON, C_NONE, C_NONE, C_REG, 12, 4, 0, LFROM, 0},
{AMOVD, C_VCON, C_NONE, C_NONE, C_REG, 12, 4, 0, LFROM, 0},
{AMOVW, C_MOVCON2, C_NONE, C_NONE, C_REG, 12, 8, 0, 0, 0},
{AMOVD, C_MOVCON2, C_NONE, C_NONE, C_REG, 12, 8, 0, 0, 0},
{AMOVD, C_MOVCON3, C_NONE, C_NONE, C_REG, 12, 12, 0, 0, 0},
{AMOVD, C_VCON, C_NONE, C_NONE, C_REG, 12, 16, 0, 0, 0},
{AMOVK, C_VCON, C_NONE, C_NONE, C_REG, 33, 4, 0, 0, 0},
{AMOVD, C_AACON, C_NONE, C_NONE, C_REG, 4, 4, REGFROM, 0, 0},
@ -401,8 +419,8 @@ var optab = []Optab{
{AMOVH, C_REG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
{AMOVW, C_REG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
{AMOVW, C_REG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
{AMOVD, C_REG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
{AMOVD, C_REG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
{AMOVD, C_REG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
{AFMOVS, C_FREG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
{AFMOVS, C_FREG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
@ -411,15 +429,15 @@ var optab = []Optab{
/* scaled 12-bit unsigned displacement load */
{AMOVB, C_UAUTO4K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
{AMOVB, C_UOREG4K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
{AMOVB, C_UOREG4K, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
{AMOVBU, C_UAUTO4K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
{AMOVBU, C_UOREG4K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
{AMOVBU, C_UOREG4K, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
{AMOVH, C_UAUTO8K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
{AMOVH, C_UOREG8K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
{AMOVH, C_UOREG8K, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
{AMOVW, C_UAUTO16K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
{AMOVW, C_UOREG16K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
{AMOVW, C_UOREG16K, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
{AMOVD, C_UAUTO32K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
{AMOVD, C_UOREG32K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
{AMOVD, C_UOREG32K, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
{AFMOVS, C_UAUTO16K, C_NONE, C_NONE, C_FREG, 21, 4, REGSP, 0, 0},
{AFMOVS, C_UOREG16K, C_NONE, C_NONE, C_FREG, 21, 4, 0, 0, 0},
@ -428,15 +446,15 @@ var optab = []Optab{
/* unscaled 9-bit signed displacement load */
{AMOVB, C_NSAUTO, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
{AMOVB, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
{AMOVB, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
{AMOVBU, C_NSAUTO, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
{AMOVBU, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
{AMOVBU, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
{AMOVH, C_NSAUTO, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
{AMOVH, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
{AMOVH, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
{AMOVW, C_NSAUTO, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
{AMOVW, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
{AMOVW, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
{AMOVD, C_NSAUTO, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
{AMOVD, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
{AMOVD, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
{AFMOVS, C_NSAUTO, C_NONE, C_NONE, C_FREG, 21, 4, REGSP, 0, 0},
{AFMOVS, C_NSOREG, C_NONE, C_NONE, C_FREG, 21, 4, 0, 0, 0},
@ -1105,6 +1123,15 @@ func isSTXPop(op obj.As) bool {
return false
}
func isANDop(op obj.As) bool {
switch op {
case AAND, AORR, AEOR, AANDS, ATST,
ABIC, AEON, AORN, ABICS:
return true
}
return false
}
func isANDWop(op obj.As) bool {
switch op {
case AANDW, AORRW, AEORW, AANDSW, ATSTW,
@ -1114,6 +1141,14 @@ func isANDWop(op obj.As) bool {
return false
}
func isADDop(op obj.As) bool {
switch op {
case AADD, AADDS, ASUB, ASUBS, ACMN, ACMP:
return true
}
return false
}
func isADDWop(op obj.As) bool {
switch op {
case AADDW, AADDSW, ASUBW, ASUBSW, ACMNW, ACMPW:
@ -1445,6 +1480,12 @@ func (c *ctxt7) con32class(a *obj.Addr) int {
if isbitcon(uint64(v)) {
return C_ABCON
}
if movcon(int64(v)) >= 0 {
return C_AMCON
}
if movcon(int64(^v)) >= 0 {
return C_AMCON
}
return C_ADDCON
}
@ -1474,6 +1515,29 @@ func (c *ctxt7) con32class(a *obj.Addr) int {
return C_LCON
}
// con64class reclassifies the constant of C_VCON and C_LCON class.
func (c *ctxt7) con64class(a *obj.Addr) int {
zeroCount := 0
negCount := 0
for i := uint(0); i < 4; i++ {
immh := uint32(a.Offset >> (i * 16) & 0xffff)
if immh == 0 {
zeroCount++
} else if immh == 0xffff {
negCount++
}
}
if zeroCount >= 3 || negCount >= 3 {
return C_MOVCON
} else if zeroCount == 2 || negCount == 2 {
return C_MOVCON2
} else if zeroCount == 1 || negCount == 1 {
return C_MOVCON3
} else {
return C_VCON
}
}
func (c *ctxt7) aclass(a *obj.Addr) int {
switch a.Type {
case obj.TYPE_NONE:
@ -1689,21 +1753,18 @@ func (c *ctxt7) oplook(p *obj.Prog) *Optab {
a1 = ra0 + 1
p.From.Class = int8(a1)
}
if isANDWop(p.As) {
switch p.As {
case AANDW, AORRW, AEORW, AANDSW, ATSTW:
// For 32-bit logical instruction with constant,
// rewrite the high 32-bit to be a copy of the low
// 32-bit, so that the BITCON test can be shared
// for both 32-bit and 64-bit.
if a0 == C_BITCON {
break
}
fallthrough
default:
a1 = c.con32class(&p.From) + 1
p.From.Class = int8(a1)
}
if isANDWop(p.As) && a0 != C_BITCON {
// For 32-bit logical instruction with constant,
// the BITCON test is special in that it looks at
// the 64-bit which has the high 32-bit as a copy
// of the low 32-bit. We have handled that and
// don't pass it to con32class.
a1 = c.con32class(&p.From) + 1
p.From.Class = int8(a1)
}
if ((p.As == AMOVD) || isANDop(p.As) || isADDop(p.As)) && (a0 == C_LCON || a0 == C_VCON) {
a1 = c.con64class(&p.From) + 1
p.From.Class = int8(a1)
}
}
}
@ -1800,6 +1861,9 @@ func cmp(a int, b int) bool {
return true
}
case C_MOVCON2:
return cmp(C_LCON, b)
case C_VCON:
return cmp(C_LCON, b)
@ -2718,6 +2782,7 @@ func (c *ctxt7) checkShiftAmount(p *obj.Prog, a *obj.Addr) {
}
func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
var os [5]uint32
o1 := uint32(0)
o2 := uint32(0)
o3 := uint32(0)
@ -2907,13 +2972,29 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
}
case 12: /* movT $vcon, reg */
o1 = c.omovlit(p.As, p, &p.From, int(p.To.Reg))
num := c.omovlconst(p.As, p, &p.From, int(p.To.Reg), os[:])
if num == 0 {
c.ctxt.Diag("invalid constant: %v", p)
}
o1 = os[0]
o2 = os[1]
o3 = os[2]
o4 = os[3]
case 13: /* addop $vcon, [R], R (64 bit literal); cmp $lcon,R -> addop $lcon,R, ZR */
o1 = c.omovlit(AMOVD, p, &p.From, REGTMP)
if o1 == 0 {
break
o := uint32(0)
num := uint8(0)
cls := oclass(&p.From)
if isADDWop(p.As) {
if (cls != C_LCON) && (cls != C_ADDCON2) {
c.ctxt.Diag("illegal combination: %v", p)
}
num = c.omovlconst(AMOVW, p, &p.From, REGTMP, os[:])
} else {
num = c.omovlconst(AMOVD, p, &p.From, REGTMP, os[:])
}
if num == 0 {
c.ctxt.Diag("invalid constant: %v", p)
}
rt := int(p.To.Reg)
if p.To.Type == obj.TYPE_NONE {
@ -2924,16 +3005,23 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
r = rt
}
if p.To.Type != obj.TYPE_NONE && (p.To.Reg == REGSP || r == REGSP) {
o2 = c.opxrrr(p, p.As, false)
o2 |= REGTMP & 31 << 16
o2 |= LSL0_64
o = c.opxrrr(p, p.As, false)
o |= REGTMP & 31 << 16
o |= LSL0_64
} else {
o2 = c.oprrr(p, p.As)
o2 |= REGTMP & 31 << 16 /* shift is 0 */
o = c.oprrr(p, p.As)
o |= REGTMP & 31 << 16 /* shift is 0 */
}
o2 |= uint32(r&31) << 5
o2 |= uint32(rt & 31)
o |= uint32(r&31) << 5
o |= uint32(rt & 31)
os[num] = o
o1 = os[0]
o2 = os[1]
o3 = os[2]
o4 = os[3]
o5 = os[4]
case 14: /* word */
if c.aclass(&p.To) == C_ADDR {
@ -3179,10 +3267,20 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
o1 |= (uint32(r&31) << 5) | uint32(rt&31)
case 28: /* logop $vcon, [R], R (64 bit literal) */
o1 = c.omovlit(AMOVD, p, &p.From, REGTMP)
o := uint32(0)
num := uint8(0)
cls := oclass(&p.From)
if isANDWop(p.As) {
if (cls != C_LCON) && (cls != C_ADDCON) {
c.ctxt.Diag("illegal combination: %v", p)
}
num = c.omovlconst(AMOVW, p, &p.From, REGTMP, os[:])
} else {
num = c.omovlconst(AMOVD, p, &p.From, REGTMP, os[:])
}
if o1 == 0 {
break
if num == 0 {
c.ctxt.Diag("invalid constant: %v", p)
}
rt := int(p.To.Reg)
if p.To.Type == obj.TYPE_NONE {
@ -3192,10 +3290,17 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
if r == 0 {
r = rt
}
o2 = c.oprrr(p, p.As)
o2 |= REGTMP & 31 << 16 /* shift is 0 */
o2 |= uint32(r&31) << 5
o2 |= uint32(rt & 31)
o = c.oprrr(p, p.As)
o |= REGTMP & 31 << 16 /* shift is 0 */
o |= uint32(r&31) << 5
o |= uint32(rt & 31)
os[num] = o
o1 = os[0]
o2 = os[1]
o3 = os[2]
o4 = os[3]
o5 = os[4]
case 29: /* op Rn, Rd */
fc := c.aclass(&p.From)
@ -6326,10 +6431,155 @@ func (c *ctxt7) omovconst(as obj.As, p *obj.Prog, a *obj.Addr, rt int) (o1 uint3
}
o1 |= MOVCONST(d, s, rt)
}
return o1
}
// load a 32-bit/64-bit large constant (LCON or VCON) in a.Offset into rt
// put the instruction sequence in os and return the number of instructions.
func (c *ctxt7) omovlconst(as obj.As, p *obj.Prog, a *obj.Addr, rt int, os []uint32) (num uint8) {
switch as {
case AMOVW:
d := uint32(a.Offset)
// use MOVZW and MOVKW to load a constant to rt
os[0] = c.opirr(p, AMOVZW)
os[0] |= MOVCONST(int64(d), 0, rt)
os[1] = c.opirr(p, AMOVKW)
os[1] |= MOVCONST(int64(d), 1, rt)
return 2
case AMOVD:
d := a.Offset
dn := ^d
var immh [4]uint64
var i int
zeroCount := int(0)
negCount := int(0)
for i = 0; i < 4; i++ {
immh[i] = uint64((d >> uint(i*16)) & 0xffff)
if immh[i] == 0 {
zeroCount++
} else if immh[i] == 0xffff {
negCount++
}
}
if zeroCount == 4 || negCount == 4 {
c.ctxt.Diag("the immediate should be MOVCON: %v", p)
}
switch {
case zeroCount == 3:
// one MOVZ
for i = 0; i < 4; i++ {
if immh[i] != 0 {
os[0] = c.opirr(p, AMOVZ)
os[0] |= MOVCONST(d, i, rt)
break
}
}
return 1
case negCount == 3:
// one MOVN
for i = 0; i < 4; i++ {
if immh[i] != 0xffff {
os[0] = c.opirr(p, AMOVN)
os[0] |= MOVCONST(dn, i, rt)
break
}
}
return 1
case zeroCount == 2:
// one MOVZ and one MOVK
for i = 0; i < 4; i++ {
if immh[i] != 0 {
os[0] = c.opirr(p, AMOVZ)
os[0] |= MOVCONST(d, i, rt)
i++
break
}
}
for ; i < 4; i++ {
if immh[i] != 0 {
os[1] = c.opirr(p, AMOVK)
os[1] |= MOVCONST(d, i, rt)
}
}
return 2
case negCount == 2:
// one MOVN and one MOVK
for i = 0; i < 4; i++ {
if immh[i] != 0xffff {
os[0] = c.opirr(p, AMOVN)
os[0] |= MOVCONST(dn, i, rt)
i++
break
}
}
for ; i < 4; i++ {
if immh[i] != 0xffff {
os[1] = c.opirr(p, AMOVK)
os[1] |= MOVCONST(d, i, rt)
}
}
return 2
case zeroCount == 1:
// one MOVZ and two MOVKs
for i = 0; i < 4; i++ {
if immh[i] != 0 {
os[0] = c.opirr(p, AMOVZ)
os[0] |= MOVCONST(d, i, rt)
i++
break
}
}
for j := 1; i < 4; i++ {
if immh[i] != 0 {
os[j] = c.opirr(p, AMOVK)
os[j] |= MOVCONST(d, i, rt)
j++
}
}
return 3
case negCount == 1:
// one MOVN and two MOVKs
for i = 0; i < 4; i++ {
if immh[i] != 0xffff {
os[0] = c.opirr(p, AMOVN)
os[0] |= MOVCONST(dn, i, rt)
i++
break
}
}
for j := 1; i < 4; i++ {
if immh[i] != 0xffff {
os[j] = c.opirr(p, AMOVK)
os[j] |= MOVCONST(d, i, rt)
j++
}
}
return 3
default:
// one MOVZ and 3 MOVKs
os[0] = c.opirr(p, AMOVZ)
os[0] |= MOVCONST(d, 0, rt)
for i = 1; i < 4; i++ {
os[i] = c.opirr(p, AMOVK)
os[i] |= MOVCONST(d, i, rt)
}
return 4
}
default:
return 0
}
}
func (c *ctxt7) opbfm(p *obj.Prog, a obj.As, r int, s int, rf int, rt int) uint32 {
var b uint32
o := c.opirr(p, a)

View file

@ -89,7 +89,7 @@ such as str, stur, strb, sturb, strh, sturh stlr, stlrb. stlrh, st1.
Examples:
MOVD R29, 384(R19) <=> str x29, [x19,#384]
MOVB.P R30, 30(R4) <=> strb w30, [x4],#30
STLRH R21, (R18) <=> stlrh w21, [x18]
STLRH R21, (R19) <=> stlrh w21, [x19]
(2) MADD, MADDW, MSUB, MSUBW, SMADDL, SMSUBL, UMADDL, UMSUBL <Rm>, <Ra>, <Rn>, <Rd>
@ -127,7 +127,7 @@ such as str, stur, strb, sturb, strh, sturh stlr, stlrb. stlrh, st1.
Examples:
CCMN VS, R13, R22, $10 <=> ccmn x13, x22, #0xa, vs
CCMPW HS, R18, R14, $11 <=> ccmp w18, w14, #0xb, cs
CCMPW HS, R19, R14, $11 <=> ccmp w19, w14, #0xb, cs
(9) CSEL, CSELW, CSNEG, CSNEGW, CSINC, CSINCW <cond>, <Rn>, <Rm>, <Rd> ;
FCSELD, FCSELS <cond>, <Fn>, <Fm>, <Fd>
@ -144,12 +144,12 @@ FCSELD, FCSELS <cond>, <Fn>, <Fm>, <Fd>
Examples:
STLXR ZR, (R15), R16 <=> stlxr w16, xzr, [x15]
STXRB R9, (R21), R18 <=> stxrb w18, w9, [x21]
STXRB R9, (R21), R19 <=> stxrb w19, w9, [x21]
(12) STLXP, STLXPW, STXP, STXPW (<Rf1>, <Rf2>), (<Rn|RSP>), <Rs>
Examples:
STLXP (R17, R18), (R4), R5 <=> stlxp w5, x17, x18, [x4]
STLXP (R17, R19), (R4), R5 <=> stlxp w5, x17, x19, [x4]
STXPW (R30, R25), (R22), R13 <=> stxp w13, w30, w25, [x22]
2. Expressions for special arguments.
@ -173,7 +173,7 @@ Extended registers are written as <Rm>{.<extend>{<<<amount>}}.
<extend> can be UXTB, UXTH, UXTW, UXTX, SXTB, SXTH, SXTW or SXTX.
Examples:
ADDS R18.UXTB<<4, R9, R26 <=> adds x26, x9, w18, uxtb #4
ADDS R19.UXTB<<4, R9, R26 <=> adds x26, x9, w19, uxtb #4
ADDSW R14.SXTX, R14, R6 <=> adds w6, w14, w14, sxtx
Memory references: [<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
// will zero the high 32-bit of the destination
// register anyway.
switch p.As {
case AANDW, AORRW, AEORW, AANDSW, ATSTW:
if p.From.Type == obj.TYPE_CONST {
v := p.From.Offset & 0xffffffff
p.From.Offset = v | v<<32
}
if isANDWop(p.As) && p.From.Type == obj.TYPE_CONST {
v := p.From.Offset & 0xffffffff
p.From.Offset = v | v<<32
}
if c.ctxt.Flag_dynlink {

View file

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

View file

@ -25,12 +25,6 @@ type objWriter struct {
// Temporary buffer for zigzag int writing.
varintbuf [10]uint8
// Provide the index of a symbol reference by symbol name.
// One map for versioned symbols and one for unversioned symbols.
// Used for deduplicating the symbol reference list.
refIdx map[string]int
vrefIdx map[string]int
// Number of objects written of each type.
nRefs int
nData int
@ -79,10 +73,8 @@ func (w *objWriter) writeLengths() {
func newObjWriter(ctxt *Link, b *bufio.Writer) *objWriter {
return &objWriter{
ctxt: ctxt,
wr: b,
vrefIdx: make(map[string]int),
refIdx: make(map[string]int),
ctxt: ctxt,
wr: b,
}
}
@ -157,17 +149,6 @@ func (w *objWriter) writeRef(s *LSym, isPath bool) {
if s == nil || s.RefIdx != 0 {
return
}
var m map[string]int
if !s.Static() {
m = w.refIdx
} else {
m = w.vrefIdx
}
if idx := m[s.Name]; idx != 0 {
s.RefIdx = idx
return
}
w.wr.WriteByte(symPrefix)
if isPath {
w.writeString(filepath.ToSlash(s.Name))
@ -178,7 +159,6 @@ func (w *objWriter) writeRef(s *LSym, isPath bool) {
w.writeBool(s.Static())
w.nRefs++
s.RefIdx = w.nRefs
m[s.Name] = w.nRefs
}
func (w *objWriter) writeRefs(s *LSym) {

View file

@ -147,18 +147,6 @@ func (ctxt *Link) InitTextSym(s *LSym, flag int) {
isstmt.Type = objabi.SDWARFMISC
isstmt.Set(AttrDuplicateOK, s.DuplicateOK())
ctxt.Data = append(ctxt.Data, isstmt)
// Set up the function's gcargs and gclocals.
// They will be filled in later if needed.
gcargs := &s.Func.GCArgs
gcargs.Set(AttrDuplicateOK, true)
gcargs.Type = objabi.SRODATA
gclocals := &s.Func.GCLocals
gclocals.Set(AttrDuplicateOK, true)
gclocals.Type = objabi.SRODATA
gcregs := &s.Func.GCRegs
gcregs.Set(AttrDuplicateOK, true)
gcregs.Type = objabi.SRODATA
}
func (ctxt *Link) Globl(s *LSym, size int64, flag int) {

View file

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

View file

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

View file

@ -4704,7 +4704,9 @@ func (ab *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
r = obj.Addrel(cursym)
r.Off = int32(p.Pc + int64(ab.Len()))
r.Sym = p.To.Sym
r.Type = objabi.R_PCREL
// Note: R_CALL instead of R_PCREL. R_CALL is more permissive in that
// it can point to a trampoline instead of the destination itself.
r.Type = objabi.R_CALL
r.Siz = 4
ab.PutInt32(0)
break

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
// we convert the adrp; ld64 + R_ARM64_GOTPCREL into adrp;
// add + R_ADDRARM64.
if !(r.Sym.Version != 0 || r.Sym.Attr.VisibilityHidden() || r.Sym.Attr.Local()) && r.Sym.Type == sym.STEXT && ctxt.DynlinkingGo() {
if !(r.Sym.IsFileLocal() || r.Sym.Attr.VisibilityHidden() || r.Sym.Attr.Local()) && r.Sym.Type == sym.STEXT && ctxt.DynlinkingGo() {
if o2&0xffc00000 != 0xf9400000 {
ld.Errorf(s, "R_ARM64_GOTPCREL against unexpected instruction %x", o2)
}

View file

@ -342,6 +342,26 @@ func lookupOrDiag(ctxt *Link, n string) *sym.Symbol {
return s
}
// dwarfFuncSym looks up a DWARF metadata symbol for function symbol s.
// If the symbol does not exist, it creates it if create is true,
// or returns nil otherwise.
func dwarfFuncSym(ctxt *Link, s *sym.Symbol, meta string, create bool) *sym.Symbol {
// All function ABIs use symbol version 0 for the DWARF data.
//
// TODO(austin): It may be useful to have DWARF info for ABI
// wrappers, in which case we may want these versions to
// align. Better yet, replace these name lookups with a
// general way to attach metadata to a symbol.
ver := 0
if s.IsFileLocal() {
ver = int(s.Version)
}
if create {
return ctxt.Syms.Lookup(meta+s.Name, ver)
}
return ctxt.Syms.ROLookup(meta+s.Name, ver)
}
func dotypedef(ctxt *Link, parent *dwarf.DWDie, name string, def *dwarf.DWDie) *dwarf.DWDie {
// Only emit typedefs for real names.
if strings.HasPrefix(name, "map[") {
@ -843,7 +863,7 @@ func dwarfDefineGlobal(ctxt *Link, s *sym.Symbol, str string, v int64, gotype *s
}
dv := newdie(ctxt, ctxt.compUnitByPackage[lib].dwinfo, dwarf.DW_ABRV_VARIABLE, str, int(s.Version))
newabslocexprattr(dv, v, s)
if s.Version == 0 {
if !s.IsFileLocal() {
newattr(dv, dwarf.DW_AT_external, dwarf.DW_CLS_FLAG, 1, 0)
}
dt := defgotype(ctxt, gotype)
@ -1146,7 +1166,7 @@ func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) {
// indexes (created by numberfile) to CU-local indexes.
fileNums := make(map[int]int)
for _, s := range unit.lib.Textp { // textp has been dead-code-eliminated already.
dsym := ctxt.Syms.Lookup(dwarf.InfoPrefix+s.Name, int(s.Version))
dsym := dwarfFuncSym(ctxt, s, dwarf.InfoPrefix, true)
for _, f := range s.FuncInfo.File {
if _, ok := fileNums[int(f.Value)]; ok {
continue
@ -1756,12 +1776,12 @@ func dwarfGenerateDebugInfo(ctxt *Link) {
// referenced abstract functions.
// Collect all debug_range symbols in unit.rangeSyms
for _, s := range lib.Textp { // textp has been dead-code-eliminated already.
dsym := ctxt.Syms.ROLookup(dwarf.InfoPrefix+s.Name, int(s.Version))
dsym := dwarfFuncSym(ctxt, s, dwarf.InfoPrefix, false)
dsym.Attr |= sym.AttrNotInSymbolTable | sym.AttrReachable
dsym.Type = sym.SDWARFINFO
unit.funcDIEs = append(unit.funcDIEs, dsym)
rangeSym := ctxt.Syms.ROLookup(dwarf.RangePrefix+s.Name, int(s.Version))
rangeSym := dwarfFuncSym(ctxt, s, dwarf.RangePrefix, false)
if rangeSym != nil && rangeSym.Size > 0 {
rangeSym.Attr |= sym.AttrReachable | sym.AttrNotInSymbolTable
rangeSym.Type = sym.SDWARFRANGE

View file

@ -2130,7 +2130,7 @@ func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int6
if s.Attr.NotInSymbolTable() {
continue
}
if (s.Name == "" || s.Name[0] == '.') && s.Version == 0 && s.Name != ".rathole" && s.Name != ".TOC." {
if (s.Name == "" || s.Name[0] == '.') && !s.IsFileLocal() && s.Name != ".rathole" && s.Name != ".TOC." {
continue
}
switch s.Type {

View file

@ -704,7 +704,7 @@ func (f *peFile) writeSymbols(ctxt *Link) {
}
}
class := IMAGE_SYM_CLASS_EXTERNAL
if s.Version != 0 || s.Attr.VisibilityHidden() || s.Attr.Local() {
if s.IsFileLocal() || s.Attr.VisibilityHidden() || s.Attr.Local() {
class = IMAGE_SYM_CLASS_STATIC
}
f.writeSymbol(ctxt.Out, s, value, sect, typ, uint8(class))

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

View file

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

View file

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

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