Update to go1.25.0
This commit is contained in:
@@ -85,56 +85,92 @@ func SubMem(arr []int, b, c, d int) int {
|
||||
|
||||
func SubFromConst(a int) int {
|
||||
// ppc64x: `SUBC\tR[0-9]+,\s[$]40,\sR`
|
||||
// riscv64: "ADDI\t\\$-40","NEG"
|
||||
b := 40 - a
|
||||
return b
|
||||
}
|
||||
|
||||
func SubFromConstNeg(a int) int {
|
||||
// arm64: "ADD\t\\$40"
|
||||
// loong64: "ADDV[U]\t\\$40"
|
||||
// mips: "ADD[U]\t\\$40"
|
||||
// mips64: "ADDV[U]\t\\$40"
|
||||
// ppc64x: `ADD\t[$]40,\sR[0-9]+,\sR`
|
||||
// riscv64: "ADDI\t\\$40",-"NEG"
|
||||
c := 40 - (-a)
|
||||
return c
|
||||
}
|
||||
|
||||
func SubSubFromConst(a int) int {
|
||||
// arm64: "ADD\t\\$20"
|
||||
// loong64: "ADDV[U]\t\\$20"
|
||||
// mips: "ADD[U]\t\\$20"
|
||||
// mips64: "ADDV[U]\t\\$20"
|
||||
// ppc64x: `ADD\t[$]20,\sR[0-9]+,\sR`
|
||||
// riscv64: "ADDI\t\\$20",-"NEG"
|
||||
c := 40 - (20 - a)
|
||||
return c
|
||||
}
|
||||
|
||||
func AddSubFromConst(a int) int {
|
||||
// ppc64x: `SUBC\tR[0-9]+,\s[$]60,\sR`
|
||||
// riscv64: "ADDI\t\\$-60","NEG"
|
||||
c := 40 + (20 - a)
|
||||
return c
|
||||
}
|
||||
|
||||
func NegSubFromConst(a int) int {
|
||||
// arm64: "SUB\t\\$20"
|
||||
// loong64: "ADDV[U]\t\\$-20"
|
||||
// mips: "ADD[U]\t\\$-20"
|
||||
// mips64: "ADDV[U]\t\\$-20"
|
||||
// ppc64x: `ADD\t[$]-20,\sR[0-9]+,\sR`
|
||||
// riscv64: "ADDI\t\\$-20"
|
||||
c := -(20 - a)
|
||||
return c
|
||||
}
|
||||
|
||||
func NegAddFromConstNeg(a int) int {
|
||||
// arm64: "SUB\t\\$40","NEG"
|
||||
// loong64: "ADDV[U]\t\\$-40","SUBV"
|
||||
// mips: "ADD[U]\t\\$-40","SUB"
|
||||
// mips64: "ADDV[U]\t\\$-40","SUBV"
|
||||
// ppc64x: `SUBC\tR[0-9]+,\s[$]40,\sR`
|
||||
// riscv64: "ADDI\t\\$-40","NEG"
|
||||
c := -(-40 + a)
|
||||
return c
|
||||
}
|
||||
|
||||
func SubSubNegSimplify(a, b int) int {
|
||||
// amd64:"NEGQ"
|
||||
// arm64:"NEG"
|
||||
// loong64:"SUBV"
|
||||
// mips:"SUB"
|
||||
// mips64:"SUBV"
|
||||
// ppc64x:"NEG"
|
||||
// riscv64:"NEG",-"SUB"
|
||||
r := (a - b) - a
|
||||
return r
|
||||
}
|
||||
|
||||
func SubAddSimplify(a, b int) int {
|
||||
// amd64:-"SUBQ",-"ADDQ"
|
||||
// arm64:-"SUB",-"ADD"
|
||||
// loong64:-"SUBV",-"ADDV"
|
||||
// mips:-"SUB",-"ADD"
|
||||
// mips64:-"SUBV",-"ADDV"
|
||||
// ppc64x:-"SUB",-"ADD"
|
||||
// riscv64:-"SUB",-"ADD"
|
||||
r := a + (b - a)
|
||||
return r
|
||||
}
|
||||
|
||||
func SubAddSimplify2(a, b, c int) (int, int, int, int, int, int) {
|
||||
// amd64:-"ADDQ"
|
||||
// arm64:-"ADD"
|
||||
// mips:"SUB",-"ADD"
|
||||
// mips64:"SUBV",-"ADDV"
|
||||
// loong64:"SUBV",-"ADDV"
|
||||
r := (a + b) - (a + c)
|
||||
// amd64:-"ADDQ"
|
||||
r1 := (a + b) - (c + a)
|
||||
@@ -143,6 +179,10 @@ func SubAddSimplify2(a, b, c int) (int, int, int, int, int, int) {
|
||||
// amd64:-"ADDQ"
|
||||
r3 := (b + a) - (c + a)
|
||||
// amd64:-"SUBQ"
|
||||
// arm64:-"SUB"
|
||||
// mips:"ADD",-"SUB"
|
||||
// mips64:"ADDV",-"SUBV"
|
||||
// loong64:"ADDV",-"SUBV"
|
||||
r4 := (a - c) + (c + b)
|
||||
// amd64:-"SUBQ"
|
||||
r5 := (a - c) + (b + c)
|
||||
@@ -151,18 +191,34 @@ func SubAddSimplify2(a, b, c int) (int, int, int, int, int, int) {
|
||||
|
||||
func SubAddNegSimplify(a, b int) int {
|
||||
// amd64:"NEGQ",-"ADDQ",-"SUBQ"
|
||||
// arm64:"NEG",-"ADD",-"SUB"
|
||||
// loong64:"SUBV",-"ADDV"
|
||||
// mips:"SUB",-"ADD"
|
||||
// mips64:"SUBV",-"ADDV"
|
||||
// ppc64x:"NEG",-"ADD",-"SUB"
|
||||
// riscv64:"NEG",-"ADD",-"SUB"
|
||||
r := a - (b + a)
|
||||
return r
|
||||
}
|
||||
|
||||
func AddAddSubSimplify(a, b, c int) int {
|
||||
// amd64:-"SUBQ"
|
||||
// arm64:"ADD",-"SUB"
|
||||
// loong64:"ADDV",-"SUBV"
|
||||
// mips:"ADD",-"SUB"
|
||||
// mips64:"ADDV",-"SUBV"
|
||||
// ppc64x:-"SUB"
|
||||
// riscv64:"ADD","ADD",-"SUB"
|
||||
r := a + (b + (c - a))
|
||||
return r
|
||||
}
|
||||
|
||||
func NegToInt32(a int) int {
|
||||
// riscv64: "NEGW",-"MOVW"
|
||||
r := int(int32(-a))
|
||||
return r
|
||||
}
|
||||
|
||||
// -------------------- //
|
||||
// Multiplication //
|
||||
// -------------------- //
|
||||
@@ -185,6 +241,15 @@ func Pow2Muls(n1, n2 int) (int, int) {
|
||||
return a, b
|
||||
}
|
||||
|
||||
func Mul_2(n1 int32, n2 int64) (int32, int64) {
|
||||
// amd64:"ADDL", -"SHLL"
|
||||
a := n1 * 2
|
||||
// amd64:"ADDQ", -"SHLQ"
|
||||
b := n2 * 2
|
||||
|
||||
return a, b
|
||||
}
|
||||
|
||||
func Mul_96(n int) int {
|
||||
// amd64:`SHLQ\t[$]5`,`LEAQ\t\(.*\)\(.*\*2\),`,-`IMULQ`
|
||||
// 386:`SHLL\t[$]5`,`LEAL\t\(.*\)\(.*\*2\),`,-`IMULL`
|
||||
@@ -624,7 +689,7 @@ func constantFold2(i0, j0, i1, j1 int) (int, int) {
|
||||
}
|
||||
|
||||
func constantFold3(i, j int) int {
|
||||
// arm64: "MOVD\t[$]30","MUL",-"ADD",-"LSL"
|
||||
// arm64: "LSL\t[$]5,","SUB\tR[0-9]+<<1,",-"ADD"
|
||||
// ppc64x:"MULLD\t[$]30","MULLD"
|
||||
r := (5 * i) * (6 * j)
|
||||
return r
|
||||
@@ -638,7 +703,7 @@ func Int64Min(a, b int64) int64 {
|
||||
// amd64: "CMPQ","CMOVQLT"
|
||||
// arm64: "CMP","CSEL"
|
||||
// riscv64/rva20u64:"BLT\t"
|
||||
// riscv64/rva22u64:"MIN\t"
|
||||
// riscv64/rva22u64,riscv64/rva23u64:"MIN\t"
|
||||
return min(a, b)
|
||||
}
|
||||
|
||||
@@ -646,7 +711,7 @@ func Int64Max(a, b int64) int64 {
|
||||
// amd64: "CMPQ","CMOVQGT"
|
||||
// arm64: "CMP","CSEL"
|
||||
// riscv64/rva20u64:"BLT\t"
|
||||
// riscv64/rva22u64:"MAX\t"
|
||||
// riscv64/rva22u64,riscv64/rva23u64:"MAX\t"
|
||||
return max(a, b)
|
||||
}
|
||||
|
||||
@@ -654,7 +719,7 @@ func Uint64Min(a, b uint64) uint64 {
|
||||
// amd64: "CMPQ","CMOVQCS"
|
||||
// arm64: "CMP","CSEL"
|
||||
// riscv64/rva20u64:"BLTU"
|
||||
// riscv64/rva22u64:"MINU"
|
||||
// riscv64/rva22u64,riscv64/rva23u64:"MINU"
|
||||
return min(a, b)
|
||||
}
|
||||
|
||||
@@ -662,6 +727,6 @@ func Uint64Max(a, b uint64) uint64 {
|
||||
// amd64: "CMPQ","CMOVQHI"
|
||||
// arm64: "CMP","CSEL"
|
||||
// riscv64/rva20u64:"BLTU"
|
||||
// riscv64/rva22u64:"MAXU"
|
||||
// riscv64/rva22u64,riscv64/rva23u64:"MAXU"
|
||||
return max(a, b)
|
||||
}
|
||||
|
||||
@@ -120,6 +120,16 @@ func bitoff64(a, b uint64) (n uint64) {
|
||||
return n
|
||||
}
|
||||
|
||||
func clearLastBit(x int64, y int32) (int64, int32) {
|
||||
// amd64:"ANDQ\t[$]-2"
|
||||
a := (x >> 1) << 1
|
||||
|
||||
// amd64:"ANDL\t[$]-2"
|
||||
b := (y >> 1) << 1
|
||||
|
||||
return a, b
|
||||
}
|
||||
|
||||
func bitcompl64(a, b uint64) (n uint64) {
|
||||
// amd64:"BTCQ"
|
||||
n += b ^ (1 << (a & 63))
|
||||
@@ -322,9 +332,24 @@ func op_eon(x, y, z uint32, a []uint32, n, m uint64) uint64 {
|
||||
|
||||
func op_orn(x, y uint32) uint32 {
|
||||
// arm64:`ORN\t`,-`ORR`
|
||||
// loong64:"ORN"\t,-"OR\t"
|
||||
return x | ^y
|
||||
}
|
||||
|
||||
func op_nor(x int64, a []int64) {
|
||||
// loong64: "MOVV\t[$]0","NOR\tR"
|
||||
a[0] = ^(0x1234 | x)
|
||||
// loong64:"NOR",-"XOR"
|
||||
a[1] = (-1) ^ x
|
||||
// loong64: "MOVV\t[$]-55",-"OR",-"NOR"
|
||||
a[2] = ^(0x12 | 0x34)
|
||||
}
|
||||
|
||||
func op_andn(x, y uint32) uint32 {
|
||||
// loong64:"ANDN\t",-"AND\t"
|
||||
return x &^ y
|
||||
}
|
||||
|
||||
// check bitsets
|
||||
func bitSetPowerOf2Test(x int) bool {
|
||||
// amd64:"BTL\t[$]3"
|
||||
|
||||
@@ -47,6 +47,7 @@ func convertNeqBool32(x uint32) bool {
|
||||
|
||||
func convertEqBool32(x uint32) bool {
|
||||
// ppc64x:"RLDICL",-"CMPW","XOR",-"ISEL"
|
||||
// amd64:"ANDL","XORL",-"BTL",-"SETCC"
|
||||
return x&1 == 0
|
||||
}
|
||||
|
||||
@@ -57,9 +58,34 @@ func convertNeqBool64(x uint64) bool {
|
||||
|
||||
func convertEqBool64(x uint64) bool {
|
||||
// ppc64x:"RLDICL","XOR",-"CMP",-"ISEL"
|
||||
// amd64:"ANDL","XORL",-"BTL",-"SETCC"
|
||||
return x&1 == 0
|
||||
}
|
||||
|
||||
func phiAnd(a, b bool) bool {
|
||||
var x bool
|
||||
// amd64:-"TESTB"
|
||||
if a {
|
||||
x = b
|
||||
} else {
|
||||
x = a
|
||||
}
|
||||
// amd64:"ANDL"
|
||||
return x
|
||||
}
|
||||
|
||||
func phiOr(a, b bool) bool {
|
||||
var x bool
|
||||
// amd64:-"TESTB"
|
||||
if a {
|
||||
x = a
|
||||
} else {
|
||||
x = b
|
||||
}
|
||||
// amd64:"ORL"
|
||||
return x
|
||||
}
|
||||
|
||||
func TestSetEq64(x uint64, y uint64) bool {
|
||||
// ppc64x/power10:"SETBC\tCR0EQ",-"ISEL"
|
||||
// ppc64x/power9:"CMP","ISEL",-"SETBC\tCR0EQ"
|
||||
|
||||
@@ -241,4 +241,14 @@ func ui64x0(x chan uint64) {
|
||||
for <-x < 1 {
|
||||
dummy()
|
||||
}
|
||||
|
||||
// riscv64:"BNEZ"
|
||||
for 0 < <-x {
|
||||
dummy()
|
||||
}
|
||||
|
||||
// riscv64:"BEQZ"
|
||||
for 0 >= <-x {
|
||||
dummy()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -730,6 +730,54 @@ func cmpToCmnLessThan(a, b, c, d int) int {
|
||||
return c1 + c2 + c3 + c4
|
||||
}
|
||||
|
||||
func less128Signed32(x int32) bool {
|
||||
// amd64:`CMPL.*127`
|
||||
// amd64:`SETLE`
|
||||
return x < 128
|
||||
}
|
||||
|
||||
func less128Signed64(x int64) bool {
|
||||
// amd64:`CMPQ.*127`
|
||||
// amd64:`SETLE`
|
||||
return x < 128
|
||||
}
|
||||
|
||||
func less128Unsigned32(x uint32) bool {
|
||||
// amd64:`CMPL.*127`
|
||||
// amd64:`SETLS`
|
||||
return x < 128
|
||||
}
|
||||
|
||||
func less128Unsigned64(x uint64) bool {
|
||||
// amd64:`CMPQ.*127`
|
||||
// amd64:`SETLS`
|
||||
return x < 128
|
||||
}
|
||||
|
||||
func ge128Unsigned32(x uint32) bool {
|
||||
// amd64:`CMPL.*127`
|
||||
// amd64:`SETHI`
|
||||
return x >= 128
|
||||
}
|
||||
|
||||
func ge128Unsigned64(x uint64) bool {
|
||||
// amd64:`CMPQ.*127`
|
||||
// amd64:`SETHI`
|
||||
return x >= 128
|
||||
}
|
||||
|
||||
func ge128Signed32(x int32) bool {
|
||||
// amd64:`CMPL.*127`
|
||||
// amd64:`SETGT`
|
||||
return x >= 128
|
||||
}
|
||||
|
||||
func ge128Signed64(x int64) bool {
|
||||
// amd64:`CMPQ.*127`
|
||||
// amd64:`SETGT`
|
||||
return x >= 128
|
||||
}
|
||||
|
||||
func cmpToCmnGreaterThanEqual(a, b, c, d int) int {
|
||||
var c1, c2, c3, c4 int
|
||||
// arm64:`CMN`,`CSET\tPL`,-`CMP`
|
||||
|
||||
@@ -74,6 +74,7 @@ func FusedAdd32(x, y, z float32) float32 {
|
||||
// arm64:"FMADDS"
|
||||
// loong64:"FMADDF\t"
|
||||
// riscv64:"FMADDS\t"
|
||||
// amd64/v3:"VFMADD231SS\t"
|
||||
return x*y + z
|
||||
}
|
||||
|
||||
@@ -98,6 +99,7 @@ func FusedAdd64(x, y, z float64) float64 {
|
||||
// arm64:"FMADDD"
|
||||
// loong64:"FMADDD\t"
|
||||
// riscv64:"FMADDD\t"
|
||||
// amd64/v3:"VFMADD231SD\t"
|
||||
return x*y + z
|
||||
}
|
||||
|
||||
@@ -147,20 +149,14 @@ func CmpWithAdd(a float64, b float64) bool {
|
||||
// Non-floats //
|
||||
// ---------------- //
|
||||
|
||||
// We should make sure that the compiler doesn't generate floating point
|
||||
// instructions for non-float operations on Plan 9, because floating point
|
||||
// operations are not allowed in the note handler.
|
||||
|
||||
func ArrayZero() [16]byte {
|
||||
// amd64:"MOVUPS"
|
||||
// plan9/amd64/:-"MOVUPS"
|
||||
var a [16]byte
|
||||
return a
|
||||
}
|
||||
|
||||
func ArrayCopy(a [16]byte) (b [16]byte) {
|
||||
// amd64:"MOVUPS"
|
||||
// plan9/amd64/:-"MOVUPS"
|
||||
b = a
|
||||
return
|
||||
}
|
||||
|
||||
@@ -25,3 +25,39 @@ func ConvToM(x any) I {
|
||||
// arm64:`CALL\truntime.typeAssert`,`LDAR`,`MOVWU`,`MOVD\t\(R.*\)\(R.*\)`
|
||||
return x.(I)
|
||||
}
|
||||
|
||||
func e1(x any, y *int) bool {
|
||||
// amd64:-`.*faceeq`,`SETEQ`
|
||||
// arm64:-`.*faceeq`,`CSET\tEQ`
|
||||
return x == y
|
||||
}
|
||||
|
||||
func e2(x any, y *int) bool {
|
||||
// amd64:-`.*faceeq`,`SETEQ`
|
||||
// arm64:-`.*faceeq`,`CSET\tEQ`
|
||||
return y == x
|
||||
}
|
||||
|
||||
type E *int
|
||||
|
||||
func e3(x any, y E) bool {
|
||||
// amd64:-`.*faceeq`,`SETEQ`
|
||||
// arm64:-`.*faceeq`,`CSET\tEQ`
|
||||
return x == y
|
||||
}
|
||||
|
||||
type T int
|
||||
|
||||
func (t *T) M() {}
|
||||
|
||||
func i1(x I, y *T) bool {
|
||||
// amd64:-`.*faceeq`,`SETEQ`
|
||||
// arm64:-`.*faceeq`,`CSET\tEQ`
|
||||
return x == y
|
||||
}
|
||||
|
||||
func i2(x I, y *T) bool {
|
||||
// amd64:-`.*faceeq`,`SETEQ`
|
||||
// arm64:-`.*faceeq`,`CSET\tEQ`
|
||||
return y == x
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ package codegen
|
||||
type T struct {
|
||||
a *[10]int
|
||||
b [10]int
|
||||
s []int
|
||||
}
|
||||
|
||||
func (t *T) f() {
|
||||
@@ -38,4 +39,15 @@ func (t *T) f() {
|
||||
for i := range *t.a {
|
||||
(*t.a)[i] = 0
|
||||
}
|
||||
|
||||
// amd64:-".*runtime.memclrNoHeapPointers"
|
||||
// amd64:"DUFFZERO"
|
||||
for i := range t.b {
|
||||
t.b[i] = 0
|
||||
}
|
||||
|
||||
// amd64:".*runtime.memclrNoHeapPointers"
|
||||
for i := range t.s {
|
||||
t.s[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
// is constant. We check this by making sure that the constant length
|
||||
// is folded into a load offset.
|
||||
|
||||
package p
|
||||
package codegen
|
||||
|
||||
func f(x []int) int {
|
||||
s := make([]int, 3)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
package codegen
|
||||
|
||||
func dgemmSerialNotNot(m, n, k int, a []float64, lda int, b []float64, ldb int, c []float64, ldc int, alpha float64) {
|
||||
for i := 0; i < m; i++ {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
package codegen
|
||||
|
||||
var x = func() int {
|
||||
n := 0
|
||||
|
||||
20
test/codegen/issue70409.go
Normal file
20
test/codegen/issue70409.go
Normal file
@@ -0,0 +1,20 @@
|
||||
// asmcheck -gcflags=-d=ssa/check/on
|
||||
|
||||
// Copyright 2024 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 codegen
|
||||
|
||||
// amd64:-"MOVQ"
|
||||
func foo(v uint64) (b [8]byte) {
|
||||
b[0] = byte(v)
|
||||
b[1] = byte(v >> 8)
|
||||
b[2] = byte(v >> 16)
|
||||
b[3] = byte(v >> 24)
|
||||
b[4] = byte(v >> 32)
|
||||
b[5] = byte(v >> 40)
|
||||
b[6] = byte(v >> 48)
|
||||
b[7] = byte(v >> 56)
|
||||
return b
|
||||
}
|
||||
50
test/codegen/issue72832.go
Normal file
50
test/codegen/issue72832.go
Normal file
@@ -0,0 +1,50 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2025 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 codegen
|
||||
|
||||
type tile1 struct {
|
||||
a uint16
|
||||
b uint16
|
||||
c uint32
|
||||
}
|
||||
|
||||
func store_tile1(t *tile1) {
|
||||
// amd64:`MOVQ`
|
||||
t.a, t.b, t.c = 1, 1, 1
|
||||
}
|
||||
|
||||
type tile2 struct {
|
||||
a, b, c, d, e int8
|
||||
}
|
||||
|
||||
func store_tile2(t *tile2) {
|
||||
// amd64:`MOVW`
|
||||
t.a, t.b = 1, 1
|
||||
// amd64:`MOVW`
|
||||
t.d, t.e = 1, 1
|
||||
}
|
||||
|
||||
type tile3 struct {
|
||||
a, b uint8
|
||||
c uint16
|
||||
}
|
||||
|
||||
func store_shifted(t *tile3, x uint32) {
|
||||
// amd64:`MOVL`
|
||||
// ppc64:`MOVHBR`
|
||||
t.a = uint8(x)
|
||||
t.b = uint8(x >> 8)
|
||||
t.c = uint16(x >> 16)
|
||||
}
|
||||
|
||||
func store_const(t *tile3) {
|
||||
// 0x00030201
|
||||
// amd64:`MOVL\s\$197121`
|
||||
// 0x01020003
|
||||
// ppc64:`MOVD\s\$16908291`
|
||||
t.a, t.b, t.c = 1, 2, 3
|
||||
}
|
||||
24
test/codegen/load_type_from_itab.go
Normal file
24
test/codegen/load_type_from_itab.go
Normal file
@@ -0,0 +1,24 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2025 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.
|
||||
|
||||
// This test makes sure that we statically load a type from an itab, instead
|
||||
// of doing a indirect load from thet itab.
|
||||
|
||||
package codegen
|
||||
|
||||
type M interface{ M() }
|
||||
type A interface{ A() }
|
||||
|
||||
type Impl struct{}
|
||||
|
||||
func (*Impl) M() {}
|
||||
func (*Impl) A() {}
|
||||
|
||||
func main() {
|
||||
var a M = &Impl{}
|
||||
// amd64:`LEAQ\ttype:.*Impl`
|
||||
a.(A).A()
|
||||
}
|
||||
@@ -66,6 +66,28 @@ func LookupStringConversionKeyedArrayLit(m map[[2]string]int, bytes []byte) int
|
||||
return m[[2]string{0: string(bytes)}]
|
||||
}
|
||||
|
||||
func LookupStringConversion1(m map[string]int, bytes []byte) int {
|
||||
// amd64:-`.*runtime\.slicebytetostring\(`
|
||||
s := string(bytes)
|
||||
return m[s]
|
||||
}
|
||||
func LookupStringConversion2(m *map[string]int, bytes []byte) int {
|
||||
// amd64:-`.*runtime\.slicebytetostring\(`
|
||||
s := string(bytes)
|
||||
return (*m)[s]
|
||||
}
|
||||
func LookupStringConversion3(m map[string]int, bytes []byte) (int, bool) {
|
||||
// amd64:-`.*runtime\.slicebytetostring\(`
|
||||
s := string(bytes)
|
||||
r, ok := m[s]
|
||||
return r, ok
|
||||
}
|
||||
func DeleteStringConversion(m map[string]int, bytes []byte) {
|
||||
// amd64:-`.*runtime\.slicebytetostring\(`
|
||||
s := string(bytes)
|
||||
delete(m, s)
|
||||
}
|
||||
|
||||
// ------------------- //
|
||||
// Map Clear //
|
||||
// ------------------- //
|
||||
|
||||
@@ -240,10 +240,11 @@ func nanGenerate64() float64 {
|
||||
|
||||
// amd64:"DIVSD"
|
||||
z0 := zero / zero
|
||||
// amd64:"MULSD"
|
||||
// amd64/v1,amd64/v2:"MULSD"
|
||||
z1 := zero * inf
|
||||
// amd64:"SQRTSD"
|
||||
z2 := math.Sqrt(negone)
|
||||
// amd64/v3:"VFMADD231SD"
|
||||
return z0 + z1 + z2
|
||||
}
|
||||
|
||||
@@ -254,7 +255,8 @@ func nanGenerate32() float32 {
|
||||
|
||||
// amd64:"DIVSS"
|
||||
z0 := zero / zero
|
||||
// amd64:"MULSS"
|
||||
// amd64/v1,amd64/v2:"MULSS"
|
||||
z1 := zero * inf
|
||||
// amd64/v3:"VFMADD231SS"
|
||||
return z0 + z1
|
||||
}
|
||||
|
||||
@@ -6,7 +6,10 @@
|
||||
|
||||
package codegen
|
||||
|
||||
import "math/bits"
|
||||
import (
|
||||
"math/bits"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// ----------------------- //
|
||||
// bits.LeadingZeros //
|
||||
@@ -15,60 +18,70 @@ import "math/bits"
|
||||
func LeadingZeros(n uint) int {
|
||||
// amd64/v1,amd64/v2:"BSRQ"
|
||||
// amd64/v3:"LZCNTQ", -"BSRQ"
|
||||
// s390x:"FLOGR"
|
||||
// arm:"CLZ" arm64:"CLZ"
|
||||
// arm64:"CLZ"
|
||||
// arm:"CLZ"
|
||||
// loong64:"CLZV",-"SUB"
|
||||
// mips:"CLZ"
|
||||
// wasm:"I64Clz"
|
||||
// ppc64x:"CNTLZD"
|
||||
// riscv64/rva22u64,riscv64/rva23u64:"CLZ\t",-"SUB"
|
||||
// s390x:"FLOGR"
|
||||
// wasm:"I64Clz"
|
||||
return bits.LeadingZeros(n)
|
||||
}
|
||||
|
||||
func LeadingZeros64(n uint64) int {
|
||||
// amd64/v1,amd64/v2:"BSRQ"
|
||||
// amd64/v3:"LZCNTQ", -"BSRQ"
|
||||
// s390x:"FLOGR"
|
||||
// arm:"CLZ" arm64:"CLZ"
|
||||
// arm:"CLZ"
|
||||
// arm64:"CLZ"
|
||||
// loong64:"CLZV",-"SUB"
|
||||
// mips:"CLZ"
|
||||
// wasm:"I64Clz"
|
||||
// ppc64x:"CNTLZD"
|
||||
// riscv64/rva22u64,riscv64/rva23u64:"CLZ\t",-"ADDI"
|
||||
// s390x:"FLOGR"
|
||||
// wasm:"I64Clz"
|
||||
return bits.LeadingZeros64(n)
|
||||
}
|
||||
|
||||
func LeadingZeros32(n uint32) int {
|
||||
// amd64/v1,amd64/v2:"BSRQ","LEAQ",-"CMOVQEQ"
|
||||
// amd64/v3: "LZCNTL",- "BSRL"
|
||||
// s390x:"FLOGR"
|
||||
// arm:"CLZ" arm64:"CLZW"
|
||||
// arm:"CLZ"
|
||||
// arm64:"CLZW"
|
||||
// loong64:"CLZW",-"SUB"
|
||||
// mips:"CLZ"
|
||||
// wasm:"I64Clz"
|
||||
// ppc64x:"CNTLZW"
|
||||
// riscv64/rva22u64,riscv64/rva23u64:"CLZW",-"ADDI"
|
||||
// s390x:"FLOGR"
|
||||
// wasm:"I64Clz"
|
||||
return bits.LeadingZeros32(n)
|
||||
}
|
||||
|
||||
func LeadingZeros16(n uint16) int {
|
||||
// amd64/v1,amd64/v2:"BSRL","LEAL",-"CMOVQEQ"
|
||||
// amd64/v3: "LZCNTL",- "BSRL"
|
||||
// s390x:"FLOGR"
|
||||
// arm:"CLZ" arm64:"CLZ"
|
||||
// arm64:"CLZ"
|
||||
// arm:"CLZ"
|
||||
// loong64:"CLZV"
|
||||
// mips:"CLZ"
|
||||
// wasm:"I64Clz"
|
||||
// ppc64x:"CNTLZD"
|
||||
// riscv64/rva22u64,riscv64/rva23u64:"CLZ\t","ADDI\t\\$-48",-"NEG"
|
||||
// s390x:"FLOGR"
|
||||
// wasm:"I64Clz"
|
||||
return bits.LeadingZeros16(n)
|
||||
}
|
||||
|
||||
func LeadingZeros8(n uint8) int {
|
||||
// amd64/v1,amd64/v2:"BSRL","LEAL",-"CMOVQEQ"
|
||||
// amd64/v3: "LZCNTL",- "BSRL"
|
||||
// s390x:"FLOGR"
|
||||
// arm:"CLZ" arm64:"CLZ"
|
||||
// arm64:"CLZ"
|
||||
// arm:"CLZ"
|
||||
// loong64:"CLZV"
|
||||
// mips:"CLZ"
|
||||
// wasm:"I64Clz"
|
||||
// ppc64x:"CNTLZD"
|
||||
// riscv64/rva22u64,riscv64/rva23u64:"CLZ\t","ADDI\t\\$-56",-"NEG"
|
||||
// s390x:"FLOGR"
|
||||
// wasm:"I64Clz"
|
||||
return bits.LeadingZeros8(n)
|
||||
}
|
||||
|
||||
@@ -79,30 +92,35 @@ func LeadingZeros8(n uint8) int {
|
||||
func Len(n uint) int {
|
||||
// amd64/v1,amd64/v2:"BSRQ"
|
||||
// amd64/v3: "LZCNTQ"
|
||||
// s390x:"FLOGR"
|
||||
// arm:"CLZ" arm64:"CLZ"
|
||||
// arm64:"CLZ"
|
||||
// arm:"CLZ"
|
||||
// loong64:"CLZV"
|
||||
// mips:"CLZ"
|
||||
// wasm:"I64Clz"
|
||||
// ppc64x:"SUBC","CNTLZD"
|
||||
// riscv64/rva22u64,riscv64/rva23u64:"CLZ\t","ADDI\t\\$-64"
|
||||
// s390x:"FLOGR"
|
||||
// wasm:"I64Clz"
|
||||
return bits.Len(n)
|
||||
}
|
||||
|
||||
func Len64(n uint64) int {
|
||||
// amd64/v1,amd64/v2:"BSRQ"
|
||||
// amd64/v3: "LZCNTQ"
|
||||
// s390x:"FLOGR"
|
||||
// arm:"CLZ" arm64:"CLZ"
|
||||
// arm64:"CLZ"
|
||||
// arm:"CLZ"
|
||||
// loong64:"CLZV"
|
||||
// mips:"CLZ"
|
||||
// wasm:"I64Clz"
|
||||
// ppc64x:"SUBC","CNTLZD"
|
||||
// riscv64/rva22u64,riscv64/rva23u64:"CLZ\t","ADDI\t\\$-64"
|
||||
// s390x:"FLOGR"
|
||||
// wasm:"I64Clz"
|
||||
return bits.Len64(n)
|
||||
}
|
||||
|
||||
func SubFromLen64(n uint64) int {
|
||||
// loong64:"CLZV",-"ADD"
|
||||
// ppc64x:"CNTLZD",-"SUBC"
|
||||
// riscv64/rva22u64,riscv64/rva23u64:"CLZ\t",-"ADDI",-"NEG"
|
||||
return 64 - bits.Len64(n)
|
||||
}
|
||||
|
||||
@@ -114,36 +132,42 @@ func CompareWithLen64(n uint64) bool {
|
||||
func Len32(n uint32) int {
|
||||
// amd64/v1,amd64/v2:"BSRQ","LEAQ",-"CMOVQEQ"
|
||||
// amd64/v3: "LZCNTL"
|
||||
// s390x:"FLOGR"
|
||||
// arm:"CLZ" arm64:"CLZ"
|
||||
// arm64:"CLZ"
|
||||
// arm:"CLZ"
|
||||
// loong64:"CLZW"
|
||||
// mips:"CLZ"
|
||||
// wasm:"I64Clz"
|
||||
// ppc64x: "CNTLZW"
|
||||
// riscv64/rva22u64,riscv64/rva23u64:"CLZW","ADDI\t\\$-32"
|
||||
// s390x:"FLOGR"
|
||||
// wasm:"I64Clz"
|
||||
return bits.Len32(n)
|
||||
}
|
||||
|
||||
func Len16(n uint16) int {
|
||||
// amd64/v1,amd64/v2:"BSRL","LEAL",-"CMOVQEQ"
|
||||
// amd64/v3: "LZCNTL"
|
||||
// s390x:"FLOGR"
|
||||
// arm:"CLZ" arm64:"CLZ"
|
||||
// arm64:"CLZ"
|
||||
// arm:"CLZ"
|
||||
// loong64:"CLZV"
|
||||
// mips:"CLZ"
|
||||
// wasm:"I64Clz"
|
||||
// ppc64x:"SUBC","CNTLZD"
|
||||
// riscv64/rva22u64,riscv64/rva23u64:"CLZ\t","ADDI\t\\$-64"
|
||||
// s390x:"FLOGR"
|
||||
// wasm:"I64Clz"
|
||||
return bits.Len16(n)
|
||||
}
|
||||
|
||||
func Len8(n uint8) int {
|
||||
// amd64/v1,amd64/v2:"BSRL","LEAL",-"CMOVQEQ"
|
||||
// amd64/v3: "LZCNTL"
|
||||
// s390x:"FLOGR"
|
||||
// arm:"CLZ" arm64:"CLZ"
|
||||
// arm64:"CLZ"
|
||||
// arm:"CLZ"
|
||||
// loong64:"CLZV"
|
||||
// mips:"CLZ"
|
||||
// wasm:"I64Clz"
|
||||
// ppc64x:"SUBC","CNTLZD"
|
||||
// riscv64/rva22u64,riscv64/rva23u64:"CLZ\t","ADDI\t\\$-64"
|
||||
// s390x:"FLOGR"
|
||||
// wasm:"I64Clz"
|
||||
return bits.Len8(n)
|
||||
}
|
||||
|
||||
@@ -157,8 +181,9 @@ func OnesCount(n uint) int {
|
||||
// amd64:"POPCNTQ"
|
||||
// arm64:"VCNT","VUADDLV"
|
||||
// loong64:"VPCNTV"
|
||||
// s390x:"POPCNT"
|
||||
// ppc64x:"POPCNTD"
|
||||
// riscv64:"CPOP\t"
|
||||
// s390x:"POPCNT"
|
||||
// wasm:"I64Popcnt"
|
||||
return bits.OnesCount(n)
|
||||
}
|
||||
@@ -168,8 +193,9 @@ func OnesCount64(n uint64) int {
|
||||
// amd64:"POPCNTQ"
|
||||
// arm64:"VCNT","VUADDLV"
|
||||
// loong64:"VPCNTV"
|
||||
// s390x:"POPCNT"
|
||||
// ppc64x:"POPCNTD"
|
||||
// riscv64:"CPOP\t"
|
||||
// s390x:"POPCNT"
|
||||
// wasm:"I64Popcnt"
|
||||
return bits.OnesCount64(n)
|
||||
}
|
||||
@@ -179,8 +205,9 @@ func OnesCount32(n uint32) int {
|
||||
// amd64:"POPCNTL"
|
||||
// arm64:"VCNT","VUADDLV"
|
||||
// loong64:"VPCNTW"
|
||||
// s390x:"POPCNT"
|
||||
// ppc64x:"POPCNTW"
|
||||
// riscv64:"CPOPW"
|
||||
// s390x:"POPCNT"
|
||||
// wasm:"I64Popcnt"
|
||||
return bits.OnesCount32(n)
|
||||
}
|
||||
@@ -190,15 +217,17 @@ func OnesCount16(n uint16) int {
|
||||
// amd64:"POPCNTL"
|
||||
// arm64:"VCNT","VUADDLV"
|
||||
// loong64:"VPCNTH"
|
||||
// s390x:"POPCNT"
|
||||
// ppc64x:"POPCNTW"
|
||||
// riscv64:"CPOP\t"
|
||||
// s390x:"POPCNT"
|
||||
// wasm:"I64Popcnt"
|
||||
return bits.OnesCount16(n)
|
||||
}
|
||||
|
||||
func OnesCount8(n uint8) int {
|
||||
// s390x:"POPCNT"
|
||||
// ppc64x:"POPCNTB"
|
||||
// riscv64/rva22u64,riscv64/rva23u64:"CPOP\t"
|
||||
// s390x:"POPCNT"
|
||||
// wasm:"I64Popcnt"
|
||||
return bits.OnesCount8(n)
|
||||
}
|
||||
@@ -237,42 +266,46 @@ func Reverse8(n uint8) uint8 {
|
||||
// ----------------------- //
|
||||
|
||||
func ReverseBytes(n uint) uint {
|
||||
// amd64:"BSWAPQ"
|
||||
// 386:"BSWAPL"
|
||||
// s390x:"MOVDBR"
|
||||
// amd64:"BSWAPQ"
|
||||
// arm64:"REV"
|
||||
// loong64:"REVBV"
|
||||
// riscv64/rva22u64,riscv64/rva23u64:"REV8"
|
||||
// s390x:"MOVDBR"
|
||||
return bits.ReverseBytes(n)
|
||||
}
|
||||
|
||||
func ReverseBytes64(n uint64) uint64 {
|
||||
// amd64:"BSWAPQ"
|
||||
// 386:"BSWAPL"
|
||||
// s390x:"MOVDBR"
|
||||
// amd64:"BSWAPQ"
|
||||
// arm64:"REV"
|
||||
// ppc64x/power10: "BRD"
|
||||
// loong64:"REVBV"
|
||||
// ppc64x/power10: "BRD"
|
||||
// riscv64/rva22u64,riscv64/rva23u64:"REV8"
|
||||
// s390x:"MOVDBR"
|
||||
return bits.ReverseBytes64(n)
|
||||
}
|
||||
|
||||
func ReverseBytes32(n uint32) uint32 {
|
||||
// amd64:"BSWAPL"
|
||||
// 386:"BSWAPL"
|
||||
// s390x:"MOVWBR"
|
||||
// amd64:"BSWAPL"
|
||||
// arm64:"REVW"
|
||||
// loong64:"REVB2W"
|
||||
// ppc64x/power10: "BRW"
|
||||
// riscv64/rva22u64,riscv64/rva23u64:"REV8","SRLI\t\\$32"
|
||||
// s390x:"MOVWBR"
|
||||
return bits.ReverseBytes32(n)
|
||||
}
|
||||
|
||||
func ReverseBytes16(n uint16) uint16 {
|
||||
// amd64:"ROLW"
|
||||
// arm64:"REV16W",-"UBFX",-"ORR"
|
||||
// arm/5:"SLL","SRL","ORR"
|
||||
// arm/6:"REV16"
|
||||
// arm/7:"REV16"
|
||||
// arm64:"REV16W",-"UBFX",-"ORR"
|
||||
// loong64:"REVB2H"
|
||||
// ppc64x/power10: "BRH"
|
||||
// riscv64/rva22u64,riscv64/rva23u64:"REV8","SRLI\t\\$48"
|
||||
return bits.ReverseBytes16(n)
|
||||
}
|
||||
|
||||
@@ -356,28 +389,30 @@ func RotateLeftVariable32(n uint32, m int) uint32 {
|
||||
// ------------------------ //
|
||||
|
||||
func TrailingZeros(n uint) int {
|
||||
// 386:"BSFL"
|
||||
// amd64/v1,amd64/v2:"BSFQ","MOVL\t\\$64","CMOVQEQ"
|
||||
// amd64/v3:"TZCNTQ"
|
||||
// 386:"BSFL"
|
||||
// arm:"CLZ"
|
||||
// arm64:"RBIT","CLZ"
|
||||
// loong64:"CTZV"
|
||||
// s390x:"FLOGR"
|
||||
// ppc64x/power8:"ANDN","POPCNTD"
|
||||
// ppc64x/power9: "CNTTZD"
|
||||
// riscv64/rva22u64,riscv64/rva23u64: "CTZ\t"
|
||||
// s390x:"FLOGR"
|
||||
// wasm:"I64Ctz"
|
||||
return bits.TrailingZeros(n)
|
||||
}
|
||||
|
||||
func TrailingZeros64(n uint64) int {
|
||||
// 386:"BSFL","JNE"
|
||||
// amd64/v1,amd64/v2:"BSFQ","MOVL\t\\$64","CMOVQEQ"
|
||||
// amd64/v3:"TZCNTQ"
|
||||
// 386:"BSFL"
|
||||
// arm64:"RBIT","CLZ"
|
||||
// loong64:"CTZV"
|
||||
// s390x:"FLOGR"
|
||||
// ppc64x/power8:"ANDN","POPCNTD"
|
||||
// ppc64x/power9: "CNTTZD"
|
||||
// riscv64/rva22u64,riscv64/rva23u64: "CTZ\t"
|
||||
// s390x:"FLOGR"
|
||||
// wasm:"I64Ctz"
|
||||
return bits.TrailingZeros64(n)
|
||||
}
|
||||
@@ -389,38 +424,43 @@ func TrailingZeros64Subtract(n uint64) int {
|
||||
}
|
||||
|
||||
func TrailingZeros32(n uint32) int {
|
||||
// 386:"BSFL"
|
||||
// amd64/v1,amd64/v2:"BTSQ\\t\\$32","BSFQ"
|
||||
// amd64/v3:"TZCNTL"
|
||||
// 386:"BSFL"
|
||||
// arm:"CLZ"
|
||||
// arm64:"RBITW","CLZW"
|
||||
// loong64:"CTZW"
|
||||
// s390x:"FLOGR","MOVWZ"
|
||||
// ppc64x/power8:"ANDN","POPCNTW"
|
||||
// ppc64x/power9: "CNTTZW"
|
||||
// riscv64/rva22u64,riscv64/rva23u64: "CTZW"
|
||||
// s390x:"FLOGR","MOVWZ"
|
||||
// wasm:"I64Ctz"
|
||||
return bits.TrailingZeros32(n)
|
||||
}
|
||||
|
||||
func TrailingZeros16(n uint16) int {
|
||||
// amd64:"BSFL","ORL\\t\\$65536"
|
||||
// 386:"BSFL\t"
|
||||
// amd64:"BSFL","ORL\\t\\$65536"
|
||||
// arm:"ORR\t\\$65536","CLZ",-"MOVHU\tR"
|
||||
// arm64:"ORR\t\\$65536","RBITW","CLZW",-"MOVHU\tR",-"RBIT\t",-"CLZ\t"
|
||||
// loong64:"CTZV"
|
||||
// s390x:"FLOGR","OR\t\\$65536"
|
||||
// ppc64x/power8:"POPCNTD","ORIS\\t\\$1"
|
||||
// ppc64x/power8:"POPCNTW","ADD\t\\$-1"
|
||||
// ppc64x/power9:"CNTTZD","ORIS\\t\\$1"
|
||||
// riscv64/rva22u64,riscv64/rva23u64: "ORI\t\\$65536","CTZW"
|
||||
// s390x:"FLOGR","OR\t\\$65536"
|
||||
// wasm:"I64Ctz"
|
||||
return bits.TrailingZeros16(n)
|
||||
}
|
||||
|
||||
func TrailingZeros8(n uint8) int {
|
||||
// amd64:"BSFL","ORL\\t\\$256"
|
||||
// 386:"BSFL"
|
||||
// amd64:"BSFL","ORL\\t\\$256"
|
||||
// arm:"ORR\t\\$256","CLZ",-"MOVBU\tR"
|
||||
// arm64:"ORR\t\\$256","RBITW","CLZW",-"MOVBU\tR",-"RBIT\t",-"CLZ\t"
|
||||
// loong64:"CTZV"
|
||||
// ppc64x/power8:"POPCNTB","ADD\t\\$-1"
|
||||
// ppc64x/power9:"CNTTZD","OR\t\\$256"
|
||||
// riscv64/rva22u64,riscv64/rva23u64: "ORI\t\\$256","CTZW"
|
||||
// s390x:"FLOGR","OR\t\\$256"
|
||||
// wasm:"I64Ctz"
|
||||
return bits.TrailingZeros8(n)
|
||||
@@ -444,6 +484,7 @@ func IterateBits64(n uint64) int {
|
||||
for n != 0 {
|
||||
// amd64/v1,amd64/v2:"BSFQ",-"CMOVEQ"
|
||||
// amd64/v3:"TZCNTQ"
|
||||
// riscv64/rva22u64,riscv64/rva23u64: "CTZ\t"
|
||||
i += bits.TrailingZeros64(n)
|
||||
n &= n - 1
|
||||
}
|
||||
@@ -455,6 +496,7 @@ func IterateBits32(n uint32) int {
|
||||
for n != 0 {
|
||||
// amd64/v1,amd64/v2:"BSFL",-"BTSQ"
|
||||
// amd64/v3:"TZCNTL"
|
||||
// riscv64/rva22u64,riscv64/rva23u64: "CTZ\t"
|
||||
i += bits.TrailingZeros32(n)
|
||||
n &= n - 1
|
||||
}
|
||||
@@ -467,6 +509,7 @@ func IterateBits16(n uint16) int {
|
||||
// amd64/v1,amd64/v2:"BSFL",-"BTSL"
|
||||
// amd64/v3:"TZCNTL"
|
||||
// arm64:"RBITW","CLZW",-"ORR"
|
||||
// riscv64/rva22u64,riscv64/rva23u64: "CTZ\t",-"ORR"
|
||||
i += bits.TrailingZeros16(n)
|
||||
n &= n - 1
|
||||
}
|
||||
@@ -479,6 +522,7 @@ func IterateBits8(n uint8) int {
|
||||
// amd64/v1,amd64/v2:"BSFL",-"BTSL"
|
||||
// amd64/v3:"TZCNTL"
|
||||
// arm64:"RBITW","CLZW",-"ORR"
|
||||
// riscv64/rva22u64,riscv64/rva23u64: "CTZ\t",-"ORR"
|
||||
i += bits.TrailingZeros8(n)
|
||||
n &= n - 1
|
||||
}
|
||||
@@ -925,6 +969,17 @@ func Mul64LoOnly(x, y uint64) uint64 {
|
||||
return lo
|
||||
}
|
||||
|
||||
func Mul64Const() (uint64, uint64) {
|
||||
// 7133701809754865664 == 99<<56
|
||||
// arm64:"MOVD\t[$]7133701809754865664, R1", "MOVD\t[$]88, R0"
|
||||
return bits.Mul64(99+88<<8, 1<<56)
|
||||
}
|
||||
|
||||
func MulUintOverflow(p *uint64) []uint64 {
|
||||
// arm64:"CMP\t[$]72"
|
||||
return unsafe.Slice(p, 9)
|
||||
}
|
||||
|
||||
// --------------- //
|
||||
// bits.Div* //
|
||||
// --------------- //
|
||||
|
||||
@@ -19,7 +19,7 @@ func load_le64(b []byte) uint64 {
|
||||
// amd64:`MOVQ\s\(.*\),`,-`MOV[BWL]\t[^$]`,-`OR`
|
||||
// s390x:`MOVDBR\s\(.*\),`
|
||||
// arm64:`MOVD\s\(R[0-9]+\),`,-`MOV[BHW]`
|
||||
// loong64:`MOVBU\s\(R[0-9]+\),`
|
||||
// loong64:`MOVV\s\(R[0-9]+\),`
|
||||
// ppc64le:`MOVD\s`,-`MOV[BHW]Z`
|
||||
// ppc64:`MOVDBR\s`,-`MOV[BHW]Z`
|
||||
return binary.LittleEndian.Uint64(b)
|
||||
@@ -29,7 +29,7 @@ func load_le64_idx(b []byte, idx int) uint64 {
|
||||
// amd64:`MOVQ\s\(.*\)\(.*\*1\),`,-`MOV[BWL]\t[^$]`,-`OR`
|
||||
// s390x:`MOVDBR\s\(.*\)\(.*\*1\),`
|
||||
// arm64:`MOVD\s\(R[0-9]+\)\(R[0-9]+\),`,-`MOV[BHW]`
|
||||
// loong64:`MOVBU\s\(R[0-9]+\)\(R[0-9]+\),`
|
||||
// loong64:`MOVV\s\(R[0-9]+\)\(R[0-9]+\),`
|
||||
// ppc64le:`MOVD\s`,-`MOV[BHW]Z\s`
|
||||
// ppc64:`MOVDBR\s`,-`MOV[BHW]Z\s`
|
||||
return binary.LittleEndian.Uint64(b[idx:])
|
||||
@@ -40,7 +40,7 @@ func load_le32(b []byte) uint32 {
|
||||
// 386:`MOVL\s\(.*\),`,-`MOV[BW]`,-`OR`
|
||||
// s390x:`MOVWBR\s\(.*\),`
|
||||
// arm64:`MOVWU\s\(R[0-9]+\),`,-`MOV[BH]`
|
||||
// loong64:`MOVBU\s\(R[0-9]+\),`
|
||||
// loong64:`MOVWU\s\(R[0-9]+\),`
|
||||
// ppc64le:`MOVWZ\s`,-`MOV[BH]Z\s`
|
||||
// ppc64:`MOVWBR\s`,-`MOV[BH]Z\s`
|
||||
return binary.LittleEndian.Uint32(b)
|
||||
@@ -51,7 +51,7 @@ func load_le32_idx(b []byte, idx int) uint32 {
|
||||
// 386:`MOVL\s\(.*\)\(.*\*1\),`,-`MOV[BW]`,-`OR`
|
||||
// s390x:`MOVWBR\s\(.*\)\(.*\*1\),`
|
||||
// arm64:`MOVWU\s\(R[0-9]+\)\(R[0-9]+\),`,-`MOV[BH]`
|
||||
// loong64:`MOVBU\s\(R[0-9]+\)\(R[0-9]+\),`
|
||||
// loong64:`MOVWU\s\(R[0-9]+\)\(R[0-9]+\),`
|
||||
// ppc64le:`MOVWZ\s`,-`MOV[BH]Z\s`
|
||||
// ppc64:`MOVWBR\s`,-`MOV[BH]Z\s'
|
||||
return binary.LittleEndian.Uint32(b[idx:])
|
||||
@@ -61,7 +61,7 @@ func load_le16(b []byte) uint16 {
|
||||
// amd64:`MOVWLZX\s\(.*\),`,-`MOVB`,-`OR`
|
||||
// ppc64le:`MOVHZ\s`,-`MOVBZ`
|
||||
// arm64:`MOVHU\s\(R[0-9]+\),`,-`MOVB`
|
||||
// loong64:`MOVBU\s\(R[0-9]+\),`
|
||||
// loong64:`MOVHU\s\(R[0-9]+\),`
|
||||
// s390x:`MOVHBR\s\(.*\),`
|
||||
// ppc64:`MOVHBR\s`,-`MOVBZ`
|
||||
return binary.LittleEndian.Uint16(b)
|
||||
@@ -72,7 +72,7 @@ func load_le16_idx(b []byte, idx int) uint16 {
|
||||
// ppc64le:`MOVHZ\s`,-`MOVBZ`
|
||||
// ppc64:`MOVHBR\s`,-`MOVBZ`
|
||||
// arm64:`MOVHU\s\(R[0-9]+\)\(R[0-9]+\),`,-`MOVB`
|
||||
// loong64:`MOVBU\s\(R[0-9]+\)\(R[0-9]+\),`
|
||||
// loong64:`MOVHU\s\(R[0-9]+\)\(R[0-9]+\),`
|
||||
// s390x:`MOVHBR\s\(.*\)\(.*\*1\),`
|
||||
return binary.LittleEndian.Uint16(b[idx:])
|
||||
}
|
||||
@@ -396,6 +396,15 @@ func load_op_no_merge(p, q *int) {
|
||||
}
|
||||
}
|
||||
|
||||
func load_op_in_loop(a []int) int {
|
||||
r := 0
|
||||
for _, x := range a {
|
||||
// amd64:`ADDQ\t\([A-Z]+\)\([A-Z]+\*8\), [A-Z]+`
|
||||
r += x
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// Make sure offsets are folded into loads and stores.
|
||||
func offsets_fold(_, a [20]byte) (b [20]byte) {
|
||||
// arm64:`MOVD\tcommand-line-arguments\.a\+[0-9]+\(FP\), R[0-9]+`,`MOVD\tR[0-9]+, command-line-arguments\.b\+[0-9]+\(FP\)`
|
||||
@@ -899,9 +908,11 @@ func store32le(p *struct{ a, b uint32 }, x uint64) {
|
||||
p.b = uint32(x >> 32)
|
||||
}
|
||||
func store32be(p *struct{ a, b uint32 }, x uint64) {
|
||||
// arm64:"STPW"
|
||||
// ppc64:"MOVD",-"MOVW",-"SRD"
|
||||
// s390x:"MOVD",-"MOVW",-"SRD"
|
||||
p.a = uint32(x >> 32)
|
||||
// arm64:-"STPW"
|
||||
// ppc64:-"MOVW",-"SRD"
|
||||
// s390x:-"MOVW",-"SRD"
|
||||
p.b = uint32(x)
|
||||
@@ -970,3 +981,109 @@ func issue70300Reverse(v uint64) (b [8]byte) {
|
||||
b[0] = byte(v)
|
||||
return b
|
||||
}
|
||||
|
||||
// --------------------------------- //
|
||||
// Arm64 double-register loads //
|
||||
// --------------------------------- //
|
||||
|
||||
func dwloadI64(p *struct{ a, b int64 }) int64 {
|
||||
// arm64:"LDP\t"
|
||||
return p.a + p.b
|
||||
}
|
||||
func dwloadI32(p *struct{ a, b int32 }) int32 {
|
||||
// arm64:"LDPSW\t"
|
||||
return p.a + p.b
|
||||
}
|
||||
func dwloadU32(p *struct{ a, b uint32 }) uint32 {
|
||||
// arm64:"LDPW\t"
|
||||
return p.a + p.b
|
||||
}
|
||||
func dwloadF64(p *struct{ a, b float64 }) float64 {
|
||||
// arm64:"FLDPD\t"
|
||||
return p.a + p.b
|
||||
}
|
||||
func dwloadF32(p *struct{ a, b float32 }) float32 {
|
||||
// arm64:"FLDPS\t"
|
||||
return p.a + p.b
|
||||
}
|
||||
|
||||
func dwloadBig(p *struct{ a, b, c, d, e, f int64 }) int64 {
|
||||
// arm64:"LDP\t\\(", "LDP\t16", "LDP\t32"
|
||||
return p.c + p.f + p.a + p.e + p.d + p.b
|
||||
}
|
||||
|
||||
func dwloadArg(a [2]int64) int64 {
|
||||
// arm64:"LDP\t"
|
||||
return a[0] + a[1]
|
||||
}
|
||||
|
||||
func dwloadResult1(p *string) string {
|
||||
// arm64:"LDP\t\\(R0\\), \\(R0, R1\\)"
|
||||
return *p
|
||||
}
|
||||
|
||||
func dwloadResult2(p *[2]int64) (int64, int64) {
|
||||
// arm64:"LDP\t\\(R0\\), \\(R1, R0\\)"
|
||||
return p[1], p[0]
|
||||
}
|
||||
|
||||
// ---------------------------------- //
|
||||
// Arm64 double-register stores //
|
||||
// ---------------------------------- //
|
||||
|
||||
func dwstoreI64(p *struct{ a, b int64 }, x, y int64) {
|
||||
// arm64:"STP\t"
|
||||
p.a = x
|
||||
p.b = y
|
||||
}
|
||||
func dwstoreI32(p *struct{ a, b int32 }, x, y int32) {
|
||||
// arm64:"STPW\t"
|
||||
p.a = x
|
||||
p.b = y
|
||||
}
|
||||
func dwstoreF64(p *struct{ a, b float64 }, x, y float64) {
|
||||
// arm64:"FSTPD\t"
|
||||
p.a = x
|
||||
p.b = y
|
||||
}
|
||||
func dwstoreF32(p *struct{ a, b float32 }, x, y float32) {
|
||||
// arm64:"FSTPS\t"
|
||||
p.a = x
|
||||
p.b = y
|
||||
}
|
||||
|
||||
func dwstoreBig(p *struct{ a, b, c, d, e, f int64 }, a, b, c, d, e, f int64) {
|
||||
// This is not perfect. We merge b+a, then d+e, then c and f have no pair.
|
||||
p.c = c
|
||||
p.f = f
|
||||
// arm64:`STP\s\(R[0-9]+, R[0-9]+\), \(R[0-9]+\)`
|
||||
p.a = a
|
||||
// arm64:`STP\s\(R[0-9]+, R[0-9]+\), 24\(R[0-9]+\)`
|
||||
p.e = e
|
||||
p.d = d
|
||||
p.b = b
|
||||
}
|
||||
|
||||
func dwstoreRet() [2]int {
|
||||
// arm64:"STP\t"
|
||||
return [2]int{5, 6}
|
||||
}
|
||||
|
||||
func dwstoreLocal(i int) int64 {
|
||||
var a [2]int64
|
||||
a[0] = 5
|
||||
// arm64:"STP\t"
|
||||
a[1] = 6
|
||||
return a[i]
|
||||
}
|
||||
|
||||
func dwstoreOrder(p *struct {
|
||||
a, b int64
|
||||
c, d, e, f bool
|
||||
}, a, b int64) {
|
||||
// arm64:"STP\t"
|
||||
p.a = a
|
||||
p.c = true
|
||||
p.e = true
|
||||
p.b = b
|
||||
}
|
||||
|
||||
312
test/codegen/multiply.go
Normal file
312
test/codegen/multiply.go
Normal file
@@ -0,0 +1,312 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2024 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 codegen
|
||||
|
||||
// This file contains codegen tests related to strength
|
||||
// reduction of integer multiply.
|
||||
|
||||
func m0(x int64) int64 {
|
||||
// amd64: "XORL"
|
||||
// arm64: "MOVD\tZR"
|
||||
return x * 0
|
||||
}
|
||||
func m2(x int64) int64 {
|
||||
// amd64: "ADDQ"
|
||||
// arm64: "ADD"
|
||||
return x * 2
|
||||
}
|
||||
func m3(x int64) int64 {
|
||||
// amd64: "LEAQ\t.*[*]2"
|
||||
// arm64: "ADD\tR[0-9]+<<1,"
|
||||
return x * 3
|
||||
}
|
||||
func m4(x int64) int64 {
|
||||
// amd64: "SHLQ\t[$]2,"
|
||||
// arm64: "LSL\t[$]2,"
|
||||
return x * 4
|
||||
}
|
||||
func m5(x int64) int64 {
|
||||
// amd64: "LEAQ\t.*[*]4"
|
||||
// arm64: "ADD\tR[0-9]+<<2,"
|
||||
return x * 5
|
||||
}
|
||||
func m6(x int64) int64 {
|
||||
// amd64: "LEAQ\t.*[*]1", "LEAQ\t.*[*]2"
|
||||
// arm64: "ADD\tR[0-9]+,", "ADD\tR[0-9]+<<1,"
|
||||
return x * 6
|
||||
}
|
||||
func m7(x int64) int64 {
|
||||
// amd64: "LEAQ\t.*[*]2"
|
||||
// arm64: "LSL\t[$]3,", "SUB\tR[0-9]+,"
|
||||
return x * 7
|
||||
}
|
||||
func m8(x int64) int64 {
|
||||
// amd64: "SHLQ\t[$]3,"
|
||||
// arm64: "LSL\t[$]3,"
|
||||
return x * 8
|
||||
}
|
||||
func m9(x int64) int64 {
|
||||
// amd64: "LEAQ\t.*[*]8"
|
||||
// arm64: "ADD\tR[0-9]+<<3,"
|
||||
return x * 9
|
||||
}
|
||||
func m10(x int64) int64 {
|
||||
// amd64: "LEAQ\t.*[*]1", "LEAQ\t.*[*]4"
|
||||
// arm64: "ADD\tR[0-9]+,", "ADD\tR[0-9]+<<2,"
|
||||
return x * 10
|
||||
}
|
||||
func m11(x int64) int64 {
|
||||
// amd64: "LEAQ\t.*[*]4", "LEAQ\t.*[*]2"
|
||||
// arm64: "MOVD\t[$]11,", "MUL"
|
||||
return x * 11
|
||||
}
|
||||
func m12(x int64) int64 {
|
||||
// amd64: "LEAQ\t.*[*]2", "SHLQ\t[$]2,"
|
||||
// arm64: "LSL\t[$]2,", "ADD\tR[0-9]+<<1,"
|
||||
return x * 12
|
||||
}
|
||||
func m13(x int64) int64 {
|
||||
// amd64: "LEAQ\t.*[*]2", "LEAQ\t.*[*]4"
|
||||
// arm64: "MOVD\t[$]13,", "MUL"
|
||||
return x * 13
|
||||
}
|
||||
func m14(x int64) int64 {
|
||||
// amd64: "IMUL3Q\t[$]14,"
|
||||
// arm64: "LSL\t[$]4,", "SUB\tR[0-9]+<<1,"
|
||||
return x * 14
|
||||
}
|
||||
func m15(x int64) int64 {
|
||||
// amd64: "LEAQ\t.*[*]2", "LEAQ\t.*[*]4"
|
||||
// arm64: "LSL\t[$]4,", "SUB\tR[0-9]+,"
|
||||
return x * 15
|
||||
}
|
||||
func m16(x int64) int64 {
|
||||
// amd64: "SHLQ\t[$]4,"
|
||||
// arm64: "LSL\t[$]4,"
|
||||
return x * 16
|
||||
}
|
||||
func m17(x int64) int64 {
|
||||
// amd64: "LEAQ\t.*[*]1", "LEAQ\t.*[*]8"
|
||||
// arm64: "ADD\tR[0-9]+<<4,"
|
||||
return x * 17
|
||||
}
|
||||
func m18(x int64) int64 {
|
||||
// amd64: "LEAQ\t.*[*]1", "LEAQ\t.*[*]8"
|
||||
// arm64: "ADD\tR[0-9]+,", "ADD\tR[0-9]+<<3,"
|
||||
return x * 18
|
||||
}
|
||||
func m19(x int64) int64 {
|
||||
// amd64: "LEAQ\t.*[*]8", "LEAQ\t.*[*]2"
|
||||
// arm64: "MOVD\t[$]19,", "MUL"
|
||||
return x * 19
|
||||
}
|
||||
func m20(x int64) int64 {
|
||||
// amd64: "LEAQ\t.*[*]4", "SHLQ\t[$]2,"
|
||||
// arm64: "LSL\t[$]2,", "ADD\tR[0-9]+<<2,"
|
||||
return x * 20
|
||||
}
|
||||
func m21(x int64) int64 {
|
||||
// amd64: "LEAQ\t.*[*]4", "LEAQ\t.*[*]4"
|
||||
// arm64: "MOVD\t[$]21,", "MUL"
|
||||
return x * 21
|
||||
}
|
||||
func m22(x int64) int64 {
|
||||
// amd64: "IMUL3Q\t[$]22,"
|
||||
// arm64: "MOVD\t[$]22,", "MUL"
|
||||
return x * 22
|
||||
}
|
||||
func m23(x int64) int64 {
|
||||
// amd64: "IMUL3Q\t[$]23,"
|
||||
// arm64: "MOVD\t[$]23,", "MUL"
|
||||
return x * 23
|
||||
}
|
||||
func m24(x int64) int64 {
|
||||
// amd64: "LEAQ\t.*[*]2", "SHLQ\t[$]3,"
|
||||
// arm64: "LSL\t[$]3,", "ADD\tR[0-9]+<<1,"
|
||||
return x * 24
|
||||
}
|
||||
func m25(x int64) int64 {
|
||||
// amd64: "LEAQ\t.*[*]4", "LEAQ\t.*[*]4"
|
||||
// arm64: "MOVD\t[$]25,", "MUL"
|
||||
return x * 25
|
||||
}
|
||||
func m26(x int64) int64 {
|
||||
// amd64: "IMUL3Q\t[$]26,"
|
||||
// arm64: "MOVD\t[$]26,", "MUL"
|
||||
return x * 26
|
||||
}
|
||||
func m27(x int64) int64 {
|
||||
// amd64: "LEAQ\t.*[*]2", "LEAQ\t.*[*]8"
|
||||
// arm64: "MOVD\t[$]27,", "MUL"
|
||||
return x * 27
|
||||
}
|
||||
func m28(x int64) int64 {
|
||||
// amd64: "IMUL3Q\t[$]28,"
|
||||
// arm64: "LSL\t[$]5, "SUB\tR[0-9]+<<2,"
|
||||
return x * 28
|
||||
}
|
||||
func m29(x int64) int64 {
|
||||
// amd64: "IMUL3Q\t[$]29,"
|
||||
// arm64: "MOVD\t[$]29,", "MUL"
|
||||
return x * 29
|
||||
}
|
||||
func m30(x int64) int64 {
|
||||
// amd64: "IMUL3Q\t[$]30,"
|
||||
// arm64: "LSL\t[$]5,", "SUB\tR[0-9]+<<1,"
|
||||
return x * 30
|
||||
}
|
||||
func m31(x int64) int64 {
|
||||
// amd64: "SHLQ\t[$]5,", "SUBQ"
|
||||
// arm64: "LSL\t[$]5,", "SUB\tR[0-9]+,"
|
||||
return x * 31
|
||||
}
|
||||
func m32(x int64) int64 {
|
||||
// amd64: "SHLQ\t[$]5,"
|
||||
// arm64: "LSL\t[$]5,"
|
||||
return x * 32
|
||||
}
|
||||
func m33(x int64) int64 {
|
||||
// amd64: "SHLQ\t[$]2,", "LEAQ\t.*[*]8"
|
||||
// arm64: "ADD\tR[0-9]+<<5,"
|
||||
return x * 33
|
||||
}
|
||||
func m34(x int64) int64 {
|
||||
// amd64: "SHLQ\t[$]5,", "LEAQ\t.*[*]2"
|
||||
// arm64: "ADD\tR[0-9]+,", "ADD\tR[0-9]+<<4,"
|
||||
return x * 34
|
||||
}
|
||||
func m35(x int64) int64 {
|
||||
// amd64: "IMUL3Q\t[$]35,"
|
||||
// arm64: "MOVD\t[$]35,", "MUL"
|
||||
return x * 35
|
||||
}
|
||||
func m36(x int64) int64 {
|
||||
// amd64: "LEAQ\t.*[*]8", "SHLQ\t[$]2,"
|
||||
// arm64: "LSL\t[$]2,", "ADD\tR[0-9]+<<3,"
|
||||
return x * 36
|
||||
}
|
||||
func m37(x int64) int64 {
|
||||
// amd64: "LEAQ\t.*[*]8", "LEAQ\t.*[*]4"
|
||||
// arm64: "MOVD\t[$]37,", "MUL"
|
||||
return x * 37
|
||||
}
|
||||
func m38(x int64) int64 {
|
||||
// amd64: "IMUL3Q\t[$]38,"
|
||||
// arm64: "MOVD\t[$]38,", "MUL"
|
||||
return x * 38
|
||||
}
|
||||
func m39(x int64) int64 {
|
||||
// amd64: "IMUL3Q\t[$]39,"
|
||||
// arm64: "MOVD\t[$]39,", "MUL"
|
||||
return x * 39
|
||||
}
|
||||
func m40(x int64) int64 {
|
||||
// amd64: "LEAQ\t.*[*]4", "SHLQ\t[$]3,"
|
||||
// arm64: "LSL\t[$]3,", "ADD\tR[0-9]+<<2,"
|
||||
return x * 40
|
||||
}
|
||||
|
||||
func mn1(x int64) int64 {
|
||||
// amd64: "NEGQ\t"
|
||||
// arm64: "NEG\tR[0-9]+,"
|
||||
return x * -1
|
||||
}
|
||||
func mn2(x int64) int64 {
|
||||
// amd64: "NEGQ", "ADDQ"
|
||||
// arm64: "NEG\tR[0-9]+<<1,"
|
||||
return x * -2
|
||||
}
|
||||
func mn3(x int64) int64 {
|
||||
// amd64: "NEGQ", "LEAQ\t.*[*]2"
|
||||
// arm64: "SUB\tR[0-9]+<<2,"
|
||||
return x * -3
|
||||
}
|
||||
func mn4(x int64) int64 {
|
||||
// amd64: "NEGQ", "SHLQ\t[$]2,"
|
||||
// arm64: "NEG\tR[0-9]+<<2,"
|
||||
return x * -4
|
||||
}
|
||||
func mn5(x int64) int64 {
|
||||
// amd64: "NEGQ", "LEAQ\t.*[*]4"
|
||||
// arm64: "NEG\tR[0-9]+,", "ADD\tR[0-9]+<<2,"
|
||||
return x * -5
|
||||
}
|
||||
func mn6(x int64) int64 {
|
||||
// amd64: "IMUL3Q\t[$]-6,"
|
||||
// arm64: "ADD\tR[0-9]+,", "SUB\tR[0-9]+<<2,"
|
||||
return x * -6
|
||||
}
|
||||
func mn7(x int64) int64 {
|
||||
// amd64: "NEGQ", "LEAQ\t.*[*]8"
|
||||
// arm64: "SUB\tR[0-9]+<<3,"
|
||||
return x * -7
|
||||
}
|
||||
func mn8(x int64) int64 {
|
||||
// amd64: "NEGQ", "SHLQ\t[$]3,"
|
||||
// arm64: "NEG\tR[0-9]+<<3,"
|
||||
return x * -8
|
||||
}
|
||||
func mn9(x int64) int64 {
|
||||
// amd64: "NEGQ", "LEAQ\t.*[*]8"
|
||||
// arm64: "NEG\tR[0-9]+,", "ADD\tR[0-9]+<<3,"
|
||||
return x * -9
|
||||
}
|
||||
func mn10(x int64) int64 {
|
||||
// amd64: "IMUL3Q\t[$]-10,"
|
||||
// arm64: "MOVD\t[$]-10,", "MUL"
|
||||
return x * -10
|
||||
}
|
||||
func mn11(x int64) int64 {
|
||||
// amd64: "IMUL3Q\t[$]-11,"
|
||||
// arm64: "MOVD\t[$]-11,", "MUL"
|
||||
return x * -11
|
||||
}
|
||||
func mn12(x int64) int64 {
|
||||
// amd64: "IMUL3Q\t[$]-12,"
|
||||
// arm64: "LSL\t[$]2,", "SUB\tR[0-9]+<<2,"
|
||||
return x * -12
|
||||
}
|
||||
func mn13(x int64) int64 {
|
||||
// amd64: "IMUL3Q\t[$]-13,"
|
||||
// arm64: "MOVD\t[$]-13,", "MUL"
|
||||
return x * -13
|
||||
}
|
||||
func mn14(x int64) int64 {
|
||||
// amd64: "IMUL3Q\t[$]-14,"
|
||||
// arm64: "ADD\tR[0-9]+,", "SUB\tR[0-9]+<<3,"
|
||||
return x * -14
|
||||
}
|
||||
func mn15(x int64) int64 {
|
||||
// amd64: "SHLQ\t[$]4,", "SUBQ"
|
||||
// arm64: "SUB\tR[0-9]+<<4,"
|
||||
return x * -15
|
||||
}
|
||||
func mn16(x int64) int64 {
|
||||
// amd64: "NEGQ", "SHLQ\t[$]4,"
|
||||
// arm64: "NEG\tR[0-9]+<<4,"
|
||||
return x * -16
|
||||
}
|
||||
func mn17(x int64) int64 {
|
||||
// amd64: "IMUL3Q\t[$]-17,"
|
||||
// arm64: "NEG\tR[0-9]+,", "ADD\tR[0-9]+<<4,"
|
||||
return x * -17
|
||||
}
|
||||
func mn18(x int64) int64 {
|
||||
// amd64: "IMUL3Q\t[$]-18,"
|
||||
// arm64: "MOVD\t[$]-18,", "MUL"
|
||||
return x * -18
|
||||
}
|
||||
func mn19(x int64) int64 {
|
||||
// amd64: "IMUL3Q\t[$]-19,"
|
||||
// arm64: "MOVD\t[$]-19,", "MUL"
|
||||
return x * -19
|
||||
}
|
||||
func mn20(x int64) int64 {
|
||||
// amd64: "IMUL3Q\t[$]-20,"
|
||||
// arm64: "MOVD\t[$]-20,", "MUL"
|
||||
return x * -20
|
||||
}
|
||||
17
test/codegen/schedule.go
Normal file
17
test/codegen/schedule.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2025 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 codegen
|
||||
|
||||
func f(n int) int {
|
||||
r := 0
|
||||
// arm64:-"MOVD\t R"
|
||||
// amd64:-"LEAQ","INCQ"
|
||||
for i := range n {
|
||||
r += i
|
||||
}
|
||||
return r
|
||||
}
|
||||
@@ -11,95 +11,141 @@ package codegen
|
||||
// ------------------ //
|
||||
|
||||
func lshConst64x64(v int64) int64 {
|
||||
// loong64:"SLLV"
|
||||
// ppc64x:"SLD"
|
||||
// riscv64:"SLLI",-"AND",-"SLTIU"
|
||||
return v << uint64(33)
|
||||
}
|
||||
|
||||
func rshConst64Ux64(v uint64) uint64 {
|
||||
// loong64:"SRLV"
|
||||
// ppc64x:"SRD"
|
||||
// riscv64:"SRLI\t",-"AND",-"SLTIU"
|
||||
return v >> uint64(33)
|
||||
}
|
||||
|
||||
func rshConst64Ux64Overflow32(v uint32) uint64 {
|
||||
// loong64:"MOVV\t\\$0,",-"SRL\t"
|
||||
// riscv64:"MOV\t\\$0,",-"SRL"
|
||||
return uint64(v) >> 32
|
||||
}
|
||||
|
||||
func rshConst64Ux64Overflow16(v uint16) uint64 {
|
||||
// loong64:"MOVV\t\\$0,",-"SRLV"
|
||||
// riscv64:"MOV\t\\$0,",-"SRL"
|
||||
return uint64(v) >> 16
|
||||
}
|
||||
|
||||
func rshConst64Ux64Overflow8(v uint8) uint64 {
|
||||
// loong64:"MOVV\t\\$0,",-"SRLV"
|
||||
// riscv64:"MOV\t\\$0,",-"SRL"
|
||||
return uint64(v) >> 8
|
||||
}
|
||||
|
||||
func rshConst64x64(v int64) int64 {
|
||||
// loong64:"SRAV"
|
||||
// ppc64x:"SRAD"
|
||||
// riscv64:"SRAI\t",-"OR",-"SLTIU"
|
||||
return v >> uint64(33)
|
||||
}
|
||||
|
||||
func rshConst64x64Overflow32(v int32) int64 {
|
||||
// loong64:"SRA\t\\$31"
|
||||
// riscv64:"SRAIW",-"SLLI",-"SRAI\t"
|
||||
return int64(v) >> 32
|
||||
}
|
||||
|
||||
func rshConst64x64Overflow16(v int16) int64 {
|
||||
// loong64:"SLLV\t\\$48","SRAV\t\\$63"
|
||||
// riscv64:"SLLI","SRAI",-"SRAIW"
|
||||
return int64(v) >> 16
|
||||
}
|
||||
|
||||
func rshConst64x64Overflow8(v int8) int64 {
|
||||
// loong64:"SLLV\t\\$56","SRAV\t\\$63"
|
||||
// riscv64:"SLLI","SRAI",-"SRAIW"
|
||||
return int64(v) >> 8
|
||||
}
|
||||
|
||||
func lshConst32x1(v int32) int32 {
|
||||
// amd64:"ADDL", -"SHLL"
|
||||
return v << 1
|
||||
}
|
||||
|
||||
func lshConst64x1(v int64) int64 {
|
||||
// amd64:"ADDQ", -"SHLQ"
|
||||
return v << 1
|
||||
}
|
||||
|
||||
func lshConst32x64(v int32) int32 {
|
||||
// loong64:"SLL\t"
|
||||
// ppc64x:"SLW"
|
||||
// riscv64:"SLLI",-"AND",-"SLTIU", -"MOVW"
|
||||
return v << uint64(29)
|
||||
}
|
||||
|
||||
func rshConst32Ux64(v uint32) uint32 {
|
||||
// loong64:"SRL\t"
|
||||
// ppc64x:"SRW"
|
||||
// riscv64:"SRLIW",-"AND",-"SLTIU", -"MOVW"
|
||||
return v >> uint64(29)
|
||||
}
|
||||
|
||||
func rshConst32x64(v int32) int32 {
|
||||
// loong64:"SRA\t"
|
||||
// ppc64x:"SRAW"
|
||||
// riscv64:"SRAIW",-"OR",-"SLTIU", -"MOVW"
|
||||
return v >> uint64(29)
|
||||
}
|
||||
|
||||
func lshConst64x32(v int64) int64 {
|
||||
// loong64:"SLLV"
|
||||
// ppc64x:"SLD"
|
||||
// riscv64:"SLLI",-"AND",-"SLTIU"
|
||||
return v << uint32(33)
|
||||
}
|
||||
|
||||
func rshConst64Ux32(v uint64) uint64 {
|
||||
// loong64:"SRLV"
|
||||
// ppc64x:"SRD"
|
||||
// riscv64:"SRLI\t",-"AND",-"SLTIU"
|
||||
return v >> uint32(33)
|
||||
}
|
||||
|
||||
func rshConst64x32(v int64) int64 {
|
||||
// loong64:"SRAV"
|
||||
// ppc64x:"SRAD"
|
||||
// riscv64:"SRAI\t",-"OR",-"SLTIU"
|
||||
return v >> uint32(33)
|
||||
}
|
||||
|
||||
func lshConst32x1Add(x int32) int32 {
|
||||
// amd64:"SHLL\t[$]2"
|
||||
return (x + x) << 1
|
||||
}
|
||||
|
||||
func lshConst64x1Add(x int64) int64 {
|
||||
// amd64:"SHLQ\t[$]2"
|
||||
return (x + x) << 1
|
||||
}
|
||||
|
||||
func lshConst32x2Add(x int32) int32 {
|
||||
// amd64:"SHLL\t[$]3"
|
||||
return (x + x) << 2
|
||||
}
|
||||
|
||||
func lshConst64x2Add(x int64) int64 {
|
||||
// amd64:"SHLQ\t[$]3"
|
||||
return (x + x) << 2
|
||||
}
|
||||
|
||||
// ------------------ //
|
||||
// masked shifts //
|
||||
// ------------------ //
|
||||
|
||||
func lshMask64x64(v int64, s uint64) int64 {
|
||||
// arm64:"LSL",-"AND"
|
||||
// loong64:"SLLV",-"AND"
|
||||
// ppc64x:"RLDICL",-"ORN",-"ISEL"
|
||||
// riscv64:"SLL",-"AND\t",-"SLTIU"
|
||||
// s390x:-"RISBGZ",-"AND",-"LOCGR"
|
||||
@@ -108,6 +154,7 @@ func lshMask64x64(v int64, s uint64) int64 {
|
||||
|
||||
func rshMask64Ux64(v uint64, s uint64) uint64 {
|
||||
// arm64:"LSR",-"AND",-"CSEL"
|
||||
// loong64:"SRLV",-"AND"
|
||||
// ppc64x:"RLDICL",-"ORN",-"ISEL"
|
||||
// riscv64:"SRL\t",-"AND\t",-"SLTIU"
|
||||
// s390x:-"RISBGZ",-"AND",-"LOCGR"
|
||||
@@ -116,6 +163,7 @@ func rshMask64Ux64(v uint64, s uint64) uint64 {
|
||||
|
||||
func rshMask64x64(v int64, s uint64) int64 {
|
||||
// arm64:"ASR",-"AND",-"CSEL"
|
||||
// loong64:"SRAV",-"AND"
|
||||
// ppc64x:"RLDICL",-"ORN",-"ISEL"
|
||||
// riscv64:"SRA\t",-"OR",-"SLTIU"
|
||||
// s390x:-"RISBGZ",-"AND",-"LOCGR"
|
||||
@@ -124,14 +172,21 @@ func rshMask64x64(v int64, s uint64) int64 {
|
||||
|
||||
func lshMask32x64(v int32, s uint64) int32 {
|
||||
// arm64:"LSL",-"AND"
|
||||
// loong64:"SLL\t","AND","SGTU","MASKEQZ"
|
||||
// ppc64x:"ISEL",-"ORN"
|
||||
// riscv64:"SLL",-"AND\t",-"SLTIU"
|
||||
// s390x:-"RISBGZ",-"AND",-"LOCGR"
|
||||
return v << (s & 63)
|
||||
}
|
||||
|
||||
func lsh5Mask32x64(v int32, s uint64) int32 {
|
||||
// loong64:"SLL\t",-"AND"
|
||||
return v << (s & 31)
|
||||
}
|
||||
|
||||
func rshMask32Ux64(v uint32, s uint64) uint32 {
|
||||
// arm64:"LSR",-"AND"
|
||||
// loong64:"SRL\t","AND","SGTU","MASKEQZ"
|
||||
// ppc64x:"ISEL",-"ORN"
|
||||
// riscv64:"SRLW","SLTIU","NEG","AND\t",-"SRL\t"
|
||||
// s390x:-"RISBGZ",-"AND",-"LOCGR"
|
||||
@@ -139,12 +194,14 @@ func rshMask32Ux64(v uint32, s uint64) uint32 {
|
||||
}
|
||||
|
||||
func rsh5Mask32Ux64(v uint32, s uint64) uint32 {
|
||||
// loong64:"SRL\t",-"AND"
|
||||
// riscv64:"SRLW",-"AND\t",-"SLTIU",-"SRL\t"
|
||||
return v >> (s & 31)
|
||||
}
|
||||
|
||||
func rshMask32x64(v int32, s uint64) int32 {
|
||||
// arm64:"ASR",-"AND"
|
||||
// loong64:"SRA\t","AND","SGTU","SUBVU","OR"
|
||||
// ppc64x:"ISEL",-"ORN"
|
||||
// riscv64:"SRAW","OR","SLTIU"
|
||||
// s390x:-"RISBGZ",-"AND",-"LOCGR"
|
||||
@@ -152,12 +209,14 @@ func rshMask32x64(v int32, s uint64) int32 {
|
||||
}
|
||||
|
||||
func rsh5Mask32x64(v int32, s uint64) int32 {
|
||||
// loong64:"SRA\t",-"AND"
|
||||
// riscv64:"SRAW",-"OR",-"SLTIU"
|
||||
return v >> (s & 31)
|
||||
}
|
||||
|
||||
func lshMask64x32(v int64, s uint32) int64 {
|
||||
// arm64:"LSL",-"AND"
|
||||
// loong64:"SLLV",-"AND"
|
||||
// ppc64x:"RLDICL",-"ORN"
|
||||
// riscv64:"SLL",-"AND\t",-"SLTIU"
|
||||
// s390x:-"RISBGZ",-"AND",-"LOCGR"
|
||||
@@ -166,6 +225,7 @@ func lshMask64x32(v int64, s uint32) int64 {
|
||||
|
||||
func rshMask64Ux32(v uint64, s uint32) uint64 {
|
||||
// arm64:"LSR",-"AND",-"CSEL"
|
||||
// loong64:"SRLV",-"AND"
|
||||
// ppc64x:"RLDICL",-"ORN"
|
||||
// riscv64:"SRL\t",-"AND\t",-"SLTIU"
|
||||
// s390x:-"RISBGZ",-"AND",-"LOCGR"
|
||||
@@ -174,6 +234,7 @@ func rshMask64Ux32(v uint64, s uint32) uint64 {
|
||||
|
||||
func rshMask64x32(v int64, s uint32) int64 {
|
||||
// arm64:"ASR",-"AND",-"CSEL"
|
||||
// loong64:"SRAV",-"AND"
|
||||
// ppc64x:"RLDICL",-"ORN",-"ISEL"
|
||||
// riscv64:"SRA\t",-"OR",-"SLTIU"
|
||||
// s390x:-"RISBGZ",-"AND",-"LOCGR"
|
||||
@@ -531,13 +592,86 @@ func checkShiftToMask(u []uint64, s []int64) {
|
||||
|
||||
func checkLeftShiftWithAddition(a int64, b int64) int64 {
|
||||
// riscv64/rva20u64: "SLLI","ADD"
|
||||
// riscv64/rva22u64: "SH1ADD"
|
||||
// riscv64/rva22u64,riscv64/rva23u64: "SH1ADD"
|
||||
a = a + b<<1
|
||||
// riscv64/rva20u64: "SLLI","ADD"
|
||||
// riscv64/rva22u64: "SH2ADD"
|
||||
// riscv64/rva22u64,riscv64/rva23u64: "SH2ADD"
|
||||
a = a + b<<2
|
||||
// riscv64/rva20u64: "SLLI","ADD"
|
||||
// riscv64/rva22u64: "SH3ADD"
|
||||
// riscv64/rva22u64,riscv64/rva23u64: "SH3ADD"
|
||||
a = a + b<<3
|
||||
return a
|
||||
}
|
||||
|
||||
//
|
||||
// Convert and shift.
|
||||
//
|
||||
|
||||
func rsh64Uto32U(v uint64) uint32 {
|
||||
x := uint32(v)
|
||||
// riscv64:"MOVWU"
|
||||
if x > 8 {
|
||||
// riscv64:"SRLIW",-"MOVWU",-"SLLI"
|
||||
x >>= 2
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func rsh64Uto16U(v uint64) uint16 {
|
||||
x := uint16(v)
|
||||
// riscv64:"MOVHU"
|
||||
if x > 8 {
|
||||
// riscv64:"SLLI","SRLI"
|
||||
x >>= 2
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func rsh64Uto8U(v uint64) uint8 {
|
||||
x := uint8(v)
|
||||
// riscv64:"MOVBU"
|
||||
if x > 8 {
|
||||
// riscv64:"SLLI","SRLI"
|
||||
x >>= 2
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func rsh64to32(v int64) int32 {
|
||||
x := int32(v)
|
||||
// riscv64:"MOVW"
|
||||
if x > 8 {
|
||||
// riscv64:"SRAIW",-"MOVW",-"SLLI"
|
||||
x >>= 2
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func rsh64to16(v int64) int16 {
|
||||
x := int16(v)
|
||||
// riscv64:"MOVH"
|
||||
if x > 8 {
|
||||
// riscv64:"SLLI","SRAI"
|
||||
x >>= 2
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func rsh64to8(v int64) int8 {
|
||||
x := int8(v)
|
||||
// riscv64:"MOVB"
|
||||
if x > 8 {
|
||||
// riscv64:"SLLI","SRAI"
|
||||
x >>= 2
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// We don't need to worry about shifting
|
||||
// more than the type size.
|
||||
// (There is still a negative shift test, but
|
||||
// no shift-too-big test.)
|
||||
func signedModShift(i int) int64 {
|
||||
// arm64:-"CMP",-"CSEL"
|
||||
return 1 << (i % 64)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,10 @@
|
||||
|
||||
package codegen
|
||||
|
||||
import "runtime"
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// This file contains code generation tests related to the use of the
|
||||
// stack.
|
||||
@@ -128,6 +131,29 @@ func spillSlotReuse() {
|
||||
getp2()[nopInt()] = 0
|
||||
}
|
||||
|
||||
// Check that no stack frame space is needed for simple slice initialization with underlying structure.
|
||||
type mySlice struct {
|
||||
array unsafe.Pointer
|
||||
len int
|
||||
cap int
|
||||
}
|
||||
|
||||
// amd64:"TEXT\t.*, [$]0-"
|
||||
func sliceInit(base uintptr) []uintptr {
|
||||
const ptrSize = 8
|
||||
size := uintptr(4096)
|
||||
bitmapSize := size / ptrSize / 8
|
||||
elements := int(bitmapSize / ptrSize)
|
||||
var sl mySlice
|
||||
sl = mySlice{
|
||||
unsafe.Pointer(base + size - bitmapSize),
|
||||
elements,
|
||||
elements,
|
||||
}
|
||||
// amd64:-"POPQ",-"SP"
|
||||
return *(*[]uintptr)(unsafe.Pointer(&sl))
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func nopInt() int {
|
||||
return 0
|
||||
|
||||
@@ -183,3 +183,17 @@ func interfaceConv(x IJ) I {
|
||||
// arm64:`CALL\truntime.typeAssert`,`LDAR`,`MOVWU\t16\(R0\)`,`MOVD\t\(R.*\)\(R.*\)`
|
||||
return x
|
||||
}
|
||||
|
||||
// Make sure we can constant fold after inlining. See issue 71699.
|
||||
func stringSwitchInlineable(s string) {
|
||||
switch s {
|
||||
case "foo", "bar", "baz", "goo":
|
||||
default:
|
||||
println("no")
|
||||
}
|
||||
}
|
||||
func stringSwitch() {
|
||||
// amd64:-"CMP",-"CALL"
|
||||
// arm64:-"CMP",-"CALL"
|
||||
stringSwitchInlineable("foo")
|
||||
}
|
||||
|
||||
24
test/codegen/unique.go
Normal file
24
test/codegen/unique.go
Normal file
@@ -0,0 +1,24 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package codegen
|
||||
|
||||
import "unique"
|
||||
|
||||
func BytesToHandle(b []byte) unique.Handle[string] {
|
||||
// amd64:-`.*runtime\.slicebytetostring\(`
|
||||
return unique.Make(string(b))
|
||||
}
|
||||
|
||||
type Pair struct {
|
||||
S1 string
|
||||
S2 string
|
||||
}
|
||||
|
||||
func BytesPairToHandle(b1, b2 []byte) unique.Handle[Pair] {
|
||||
// TODO: should not copy b1 and b2.
|
||||
return unique.Make(Pair{string(b1), string(b2)})
|
||||
}
|
||||
@@ -88,3 +88,16 @@ func issue71228(dst *S, ptr *int) {
|
||||
//amd64:`.*runtime[.]wbMove`
|
||||
*dst = *sp
|
||||
}
|
||||
|
||||
func writeDouble(p *[2]*int, x, y *int) {
|
||||
// arm64: `LDP\s`, `STP\s\(R[0-9]+, R[0-9]+\), \(`,
|
||||
p[0] = x
|
||||
// arm64: `STP\s\(R[0-9]+, R[0-9]+\), 16\(`,
|
||||
p[1] = y
|
||||
}
|
||||
|
||||
func writeDoubleNil(p *[2]*int) {
|
||||
// arm64: `LDP\s`, `STP\s\(R[0-9]+, R[0-9]+\),`, `STP\s\(ZR, ZR\),`
|
||||
p[0] = nil
|
||||
p[1] = nil
|
||||
}
|
||||
|
||||
@@ -18,8 +18,27 @@ func zeroSize() {
|
||||
g(&s, 1, 2, 3, 4, 5)
|
||||
|
||||
// amd64:`LEAQ\tcommand-line-arguments\..*\+55\(SP\)`
|
||||
c <- noliteral(struct{}{})
|
||||
}
|
||||
|
||||
// Like zeroSize, but without hiding the zero-sized struct.
|
||||
func zeroSize2() {
|
||||
c := make(chan struct{})
|
||||
// amd64:`MOVQ\t\$0, command-line-arguments\.s\+48\(SP\)`
|
||||
var s *int
|
||||
// force s to be a stack object, also use some (fixed) stack space
|
||||
g(&s, 1, 2, 3, 4, 5)
|
||||
|
||||
// amd64:`LEAQ\tcommand-line-arguments\..*stmp_\d+\(SB\)`
|
||||
c <- struct{}{}
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func g(**int, int, int, int, int, int) {}
|
||||
|
||||
// noliteral prevents the compiler from recognizing a literal value.
|
||||
//
|
||||
//go:noinline
|
||||
func noliteral[T any](t T) T {
|
||||
return t
|
||||
}
|
||||
|
||||
@@ -18,9 +18,9 @@ func fp() *[3]int
|
||||
var mp map[int]*[3]int
|
||||
|
||||
var (
|
||||
_ = [3]int{1, 2, 3}[:] // ERROR "slice of unaddressable value"
|
||||
_ = m[0][:] // ERROR "slice of unaddressable value"
|
||||
_ = f()[:] // ERROR "slice of unaddressable value"
|
||||
_ = [3]int{1, 2, 3}[:] // ERROR "cannot slice unaddressable value"
|
||||
_ = m[0][:] // ERROR "cannot slice unaddressable value"
|
||||
_ = f()[:] // ERROR "cannot slice unaddressable value"
|
||||
|
||||
_ = 301[:] // ERROR "cannot slice|attempt to slice object that is not"
|
||||
_ = 3.1[:] // ERROR "cannot slice|attempt to slice object that is not"
|
||||
|
||||
@@ -20,8 +20,8 @@ func main() {
|
||||
_ = copy(si, "hi") // ERROR "have different element types(.*int.*string| int and byte)"
|
||||
_ = copy(si, sf) // ERROR "have different element types.*int.*float64"
|
||||
|
||||
_ = copy(1, 2) // ERROR "must be slices; have int, int|expects slice arguments"
|
||||
_ = copy(1, si) // ERROR "first argument to copy should be|expects slice arguments"
|
||||
_ = copy(si, 2) // ERROR "second argument to copy should be|expects slice arguments"
|
||||
_ = copy(1, 2) // ERROR "must be slices; have int, int|argument must be a slice; have 1"
|
||||
_ = copy(1, si) // ERROR "first argument to copy should be|argument must be a slice; have 1"
|
||||
_ = copy(si, 2) // ERROR "second argument to copy should be|argument must be a slice; have 2"
|
||||
|
||||
}
|
||||
|
||||
@@ -494,13 +494,13 @@ func foo70(mv1 *MV, m M) { // ERROR "leaking param: m$" "leaking param: mv1$"
|
||||
|
||||
func foo71(x *int) []*int { // ERROR "leaking param: x$"
|
||||
var y []*int
|
||||
y = append(y, x)
|
||||
y = append(y, x) // ERROR "append escapes to heap"
|
||||
return y
|
||||
}
|
||||
|
||||
func foo71a(x int) []*int { // ERROR "moved to heap: x$"
|
||||
var y []*int
|
||||
y = append(y, &x)
|
||||
y = append(y, &x) // ERROR "append escapes to heap"
|
||||
return y
|
||||
}
|
||||
|
||||
@@ -860,12 +860,12 @@ func foo104(x []*int) { // ERROR "leaking param content: x"
|
||||
|
||||
// does not leak x but does leak content
|
||||
func foo105(x []*int) { // ERROR "leaking param content: x"
|
||||
_ = append(y, x...)
|
||||
_ = append(y, x...) // ERROR "append does not escape"
|
||||
}
|
||||
|
||||
// does leak x
|
||||
func foo106(x *int) { // ERROR "leaking param: x$"
|
||||
_ = append(y, x)
|
||||
_ = append(y, x) // ERROR "append does not escape"
|
||||
}
|
||||
|
||||
func foo107(x *int) map[*int]*int { // ERROR "leaking param: x$"
|
||||
|
||||
@@ -494,13 +494,13 @@ func foo70(mv1 *MV, m M) { // ERROR "leaking param: m$" "leaking param: mv1$"
|
||||
|
||||
func foo71(x *int) []*int { // ERROR "leaking param: x$"
|
||||
var y []*int
|
||||
y = append(y, x)
|
||||
y = append(y, x) // ERROR "append escapes to heap"
|
||||
return y
|
||||
}
|
||||
|
||||
func foo71a(x int) []*int { // ERROR "moved to heap: x$"
|
||||
var y []*int
|
||||
y = append(y, &x)
|
||||
y = append(y, &x) // ERROR "append escapes to heap"
|
||||
return y
|
||||
}
|
||||
|
||||
@@ -860,12 +860,12 @@ func foo104(x []*int) { // ERROR "leaking param content: x"
|
||||
|
||||
// does not leak x but does leak content
|
||||
func foo105(x []*int) { // ERROR "leaking param content: x"
|
||||
_ = append(y, x...)
|
||||
_ = append(y, x...) // ERROR "append does not escape"
|
||||
}
|
||||
|
||||
// does leak x
|
||||
func foo106(x *int) { // ERROR "leaking param: x$"
|
||||
_ = append(y, x)
|
||||
_ = append(y, x) // ERROR "append does not escape"
|
||||
}
|
||||
|
||||
func foo107(x *int) map[*int]*int { // ERROR "leaking param: x$"
|
||||
|
||||
@@ -252,7 +252,7 @@ func f29000(_ int, x interface{}) { // ERROR "leaking param: x"
|
||||
|
||||
func g29000() {
|
||||
x := 1
|
||||
f29000(2, x) // ERROR "x escapes to heap"
|
||||
f29000(2, x) // ERROR "1 escapes to heap"
|
||||
}
|
||||
|
||||
// Issue 28369: taking an address of a parameter and converting it into a uintptr causes an
|
||||
|
||||
59
test/escape6.go
Normal file
59
test/escape6.go
Normal file
@@ -0,0 +1,59 @@
|
||||
// errorcheck -0 -m -l
|
||||
|
||||
// Copyright 2025 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.
|
||||
|
||||
// Tests for escaping variable-sized allocations.
|
||||
// In particular, we need to make sure things assigned into
|
||||
// variable-sized allocations escape even when the variable-sized
|
||||
// allocations themselves don't escape.
|
||||
|
||||
package foo
|
||||
|
||||
type T string
|
||||
|
||||
func f1(n int, v T) { // ERROR "leaking param: v"
|
||||
s := make([]T, n) // ERROR "make\(\[\]T, n\) does not escape"
|
||||
s[0] = v
|
||||
g(s)
|
||||
}
|
||||
|
||||
func f2(n int, v T) { // ERROR "leaking param: v"
|
||||
s := make([]T, n) // ERROR "make\(\[\]T, n\) does not escape"
|
||||
p := &s[0]
|
||||
*p = v
|
||||
g(s)
|
||||
}
|
||||
|
||||
func f3(n int, v T) { // ERROR "leaking param: v"
|
||||
s := make([]T, n) // ERROR "make\(\[\]T, n\) does not escape"
|
||||
t := (*[4]T)(s)
|
||||
t[0] = v
|
||||
g(s)
|
||||
}
|
||||
|
||||
// TODO: imprecise: this does not need to leak v.
|
||||
func f4(v T) { // ERROR "leaking param: v"
|
||||
s := make([]T, 4) // ERROR "make\(\[\]T, 4\) does not escape"
|
||||
s[0] = v
|
||||
g(s)
|
||||
}
|
||||
|
||||
// TODO: imprecise: this does not need to leak v.
|
||||
func f5(v T) { // ERROR "leaking param: v"
|
||||
var b [4]T
|
||||
s := b[:]
|
||||
s[0] = v
|
||||
g(s)
|
||||
}
|
||||
|
||||
func f6(v T) { // ERROR "v does not escape"
|
||||
var b [4]T
|
||||
s := b[:]
|
||||
b[0] = v
|
||||
g(s)
|
||||
}
|
||||
|
||||
func g(s []T) { // ERROR "s does not escape"
|
||||
}
|
||||
@@ -123,7 +123,7 @@ func doesMakeSlice(x *string, y *string) { // ERROR "leaking param: x" "leaking
|
||||
|
||||
func nonconstArray() {
|
||||
n := 32
|
||||
s1 := make([]int, n) // ERROR "make\(\[\]int, n\) escapes to heap"
|
||||
s2 := make([]int, 0, n) // ERROR "make\(\[\]int, 0, n\) escapes to heap"
|
||||
s1 := make([]int, n) // ERROR "make\(\[\]int, 32\) does not escape"
|
||||
s2 := make([]int, 0, n) // ERROR "make\(\[\]int, 0, 32\) does not escape"
|
||||
_, _ = s1, s2
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ func prototype(xyz []string) {} // ERROR "xyz does not escape"
|
||||
func bar() {
|
||||
var got [][]string
|
||||
f := prototype
|
||||
f = func(ss []string) { got = append(got, ss) } // ERROR "leaking param: ss" "func literal does not escape"
|
||||
f = func(ss []string) { got = append(got, ss) } // ERROR "leaking param: ss" "func literal does not escape" "append escapes to heap"
|
||||
s := "string"
|
||||
f([]string{s}) // ERROR "\[\]string{...} escapes to heap"
|
||||
}
|
||||
|
||||
@@ -228,8 +228,8 @@ func dotTypeEscape2() { // #13805, #15796
|
||||
j := 0
|
||||
var v int
|
||||
var ok bool
|
||||
var x interface{} = i // ERROR "i does not escape"
|
||||
var y interface{} = j // ERROR "j does not escape"
|
||||
var x interface{} = i // ERROR "0 does not escape"
|
||||
var y interface{} = j // ERROR "0 does not escape"
|
||||
|
||||
*(&v) = x.(int)
|
||||
*(&v), *(&ok) = y.(int)
|
||||
@@ -238,8 +238,8 @@ func dotTypeEscape2() { // #13805, #15796
|
||||
i := 0
|
||||
j := 0
|
||||
var ok bool
|
||||
var x interface{} = i // ERROR "i does not escape"
|
||||
var y interface{} = j // ERROR "j does not escape"
|
||||
var x interface{} = i // ERROR "0 does not escape"
|
||||
var y interface{} = j // ERROR "0 does not escape"
|
||||
|
||||
sink = x.(int) // ERROR "x.\(int\) escapes to heap"
|
||||
sink, *(&ok) = y.(int) // ERROR "autotmp_.* escapes to heap"
|
||||
|
||||
297
test/escape_iface_data.go
Normal file
297
test/escape_iface_data.go
Normal file
@@ -0,0 +1,297 @@
|
||||
// errorcheck -0 -d=escapedebug=1
|
||||
|
||||
// Copyright 2024 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.
|
||||
|
||||
// Test the data word used for interface conversions
|
||||
// that might otherwise allocate.
|
||||
|
||||
package dataword
|
||||
|
||||
var sink interface{}
|
||||
|
||||
func string1() {
|
||||
sink = "abc" // ERROR "using global for interface value"
|
||||
}
|
||||
|
||||
func string2() {
|
||||
v := "abc"
|
||||
sink = v // ERROR "using global for interface value"
|
||||
}
|
||||
|
||||
func string3() {
|
||||
sink = "" // ERROR "using global for interface value"
|
||||
}
|
||||
|
||||
func string4() {
|
||||
v := ""
|
||||
sink = v // ERROR "using global for interface value"
|
||||
}
|
||||
|
||||
func string5() {
|
||||
var a any = "abc" // ERROR "using global for interface value"
|
||||
_ = a
|
||||
}
|
||||
|
||||
func string6() {
|
||||
var a any
|
||||
v := "abc"
|
||||
a = v // ERROR "using global for interface value"
|
||||
_ = a
|
||||
}
|
||||
|
||||
// string7 can be inlined.
|
||||
func string7(v string) {
|
||||
sink = v
|
||||
}
|
||||
|
||||
func string8() {
|
||||
v0 := "abc"
|
||||
v := v0
|
||||
string7(v) // ERROR "using global for interface value"
|
||||
}
|
||||
|
||||
func string9() {
|
||||
v0 := "abc"
|
||||
v := v0
|
||||
f := func() {
|
||||
string7(v)
|
||||
}
|
||||
f() // ERROR "using global for interface value"
|
||||
}
|
||||
|
||||
func string10() {
|
||||
v0 := "abc"
|
||||
v := v0
|
||||
f := func() {
|
||||
f2 := func() {
|
||||
string7(v)
|
||||
}
|
||||
f2()
|
||||
}
|
||||
f() // ERROR "using global for interface value"
|
||||
}
|
||||
|
||||
func string11() {
|
||||
v0 := "abc"
|
||||
v := v0
|
||||
defer func() {
|
||||
string7(v) // ERROR "using global for interface value"
|
||||
}()
|
||||
}
|
||||
|
||||
func integer1() {
|
||||
sink = 42 // ERROR "using global for interface value"
|
||||
}
|
||||
|
||||
func integer2() {
|
||||
v := 42
|
||||
sink = v // ERROR "using global for interface value"
|
||||
}
|
||||
|
||||
func integer3() {
|
||||
sink = 0 // ERROR "using global for interface value"
|
||||
}
|
||||
|
||||
func integer4a() {
|
||||
v := 0
|
||||
sink = v // ERROR "using global for interface value"
|
||||
}
|
||||
|
||||
func integer4b() {
|
||||
v := uint8(0)
|
||||
sink = v // ERROR "using global for single-byte interface value"
|
||||
}
|
||||
|
||||
func integer5() {
|
||||
var a any = 42 // ERROR "using global for interface value"
|
||||
_ = a
|
||||
}
|
||||
|
||||
func integer6() {
|
||||
var a any
|
||||
v := 42
|
||||
a = v // ERROR "using global for interface value"
|
||||
_ = a
|
||||
}
|
||||
|
||||
func integer7(v int) {
|
||||
sink = v
|
||||
}
|
||||
|
||||
type M interface{ M() }
|
||||
|
||||
type MyInt int
|
||||
|
||||
func (m MyInt) M() {}
|
||||
|
||||
func escapes(m M) {
|
||||
sink = m
|
||||
}
|
||||
|
||||
func named1a() {
|
||||
sink = MyInt(42) // ERROR "using global for interface value"
|
||||
}
|
||||
|
||||
func named1b() {
|
||||
escapes(MyInt(42)) // ERROR "using global for interface value"
|
||||
}
|
||||
|
||||
func named2a() {
|
||||
v := MyInt(0)
|
||||
sink = v // ERROR "using global for interface value"
|
||||
}
|
||||
|
||||
func named2b() {
|
||||
v := MyInt(42)
|
||||
escapes(v) // ERROR "using global for interface value"
|
||||
}
|
||||
|
||||
func named2c() {
|
||||
v := 42
|
||||
sink = MyInt(v) // ERROR "using global for interface value"
|
||||
}
|
||||
|
||||
func named2d() {
|
||||
v := 42
|
||||
escapes(MyInt(v)) // ERROR "using global for interface value"
|
||||
}
|
||||
func named3a() {
|
||||
sink = MyInt(42) // ERROR "using global for interface value"
|
||||
}
|
||||
|
||||
func named3b() {
|
||||
escapes(MyInt(0)) // ERROR "using global for interface value"
|
||||
}
|
||||
|
||||
func named4a() {
|
||||
v := MyInt(0)
|
||||
sink = v // ERROR "using global for interface value"
|
||||
}
|
||||
|
||||
func named4b() {
|
||||
v := MyInt(0)
|
||||
escapes(v) // ERROR "using global for interface value"
|
||||
}
|
||||
|
||||
func named4c() {
|
||||
v := 0
|
||||
sink = MyInt(v) // ERROR "using global for interface value"
|
||||
}
|
||||
|
||||
func named4d() {
|
||||
v := 0
|
||||
escapes(MyInt(v)) // ERROR "using global for interface value"
|
||||
}
|
||||
|
||||
func named5() {
|
||||
var a any = MyInt(42) // ERROR "using global for interface value"
|
||||
_ = a
|
||||
}
|
||||
|
||||
func named6() {
|
||||
var a any
|
||||
v := MyInt(42)
|
||||
a = v // ERROR "using global for interface value"
|
||||
_ = a
|
||||
}
|
||||
|
||||
func named7a(v MyInt) {
|
||||
sink = v
|
||||
}
|
||||
|
||||
func named7b(v MyInt) {
|
||||
escapes(v)
|
||||
}
|
||||
|
||||
type S struct{ a, b int64 }
|
||||
|
||||
func struct1() {
|
||||
sink = S{1, 1} // ERROR "using global for interface value"
|
||||
}
|
||||
|
||||
func struct2() {
|
||||
v := S{1, 1}
|
||||
sink = v // ERROR "using global for interface value"
|
||||
}
|
||||
|
||||
func struct3() {
|
||||
sink = S{} // ERROR "using global for zero value interface value"
|
||||
}
|
||||
|
||||
func struct4() {
|
||||
v := S{}
|
||||
sink = v // ERROR "using global for zero value interface value"
|
||||
}
|
||||
|
||||
func struct5() {
|
||||
var a any = S{1, 1} // ERROR "using global for interface value"
|
||||
_ = a
|
||||
}
|
||||
|
||||
func struct6() {
|
||||
var a any
|
||||
v := S{1, 1}
|
||||
a = v // ERROR "using global for interface value"
|
||||
_ = a
|
||||
}
|
||||
|
||||
func struct7(v S) {
|
||||
sink = v
|
||||
}
|
||||
|
||||
func emptyStruct1() {
|
||||
sink = struct{}{} // ERROR "using global for zero-sized interface value"
|
||||
}
|
||||
|
||||
func emptyStruct2() {
|
||||
v := struct{}{}
|
||||
sink = v // ERROR "using global for zero-sized interface value"
|
||||
}
|
||||
|
||||
func emptyStruct3(v struct{}) { // ERROR "using global for zero-sized interface value"
|
||||
sink = v
|
||||
}
|
||||
|
||||
// Some light emulation of conditional debug printing (such as in #53465).
|
||||
|
||||
func Printf(format string, args ...any) {
|
||||
for _, arg := range args {
|
||||
sink = arg
|
||||
}
|
||||
}
|
||||
|
||||
var enabled = true
|
||||
|
||||
func debugf(format string, args ...interface{}) {
|
||||
if enabled {
|
||||
Printf(format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func debugf2(format string, args ...interface{}) {
|
||||
if enabled {
|
||||
Printf(format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func f1() {
|
||||
v := 1000
|
||||
debugf("hello %d", v) // ERROR "using global for interface value"
|
||||
}
|
||||
|
||||
func f2() {
|
||||
v := 1000
|
||||
debugf2("hello %d", v) // ERROR "using global for interface value"
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func f3(i int) {
|
||||
debugf("hello %d", i)
|
||||
}
|
||||
|
||||
func f4() {
|
||||
f3(1000)
|
||||
}
|
||||
108
test/escape_make_non_const.go
Normal file
108
test/escape_make_non_const.go
Normal file
@@ -0,0 +1,108 @@
|
||||
// errorcheck -0 -m
|
||||
|
||||
// Copyright 2025 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 escape
|
||||
|
||||
const globalConstSize = 128
|
||||
|
||||
var globalVarSize = 128
|
||||
|
||||
//go:noinline
|
||||
func testSlices() {
|
||||
{
|
||||
size := 128
|
||||
_ = make([]byte, size) // ERROR "make\(\[\]byte, 128\) does not escape"
|
||||
}
|
||||
|
||||
{
|
||||
s := 128
|
||||
size := s
|
||||
_ = make([]byte, size) // ERROR "make\(\[\]byte, 128\) does not escape"
|
||||
}
|
||||
|
||||
{
|
||||
size := 128
|
||||
_ = make([]byte, size) // ERROR "make\(\[\]byte, 128\) does not escape"
|
||||
}
|
||||
|
||||
{
|
||||
s := 128
|
||||
size := s
|
||||
_ = make([]byte, size) // ERROR "make\(\[\]byte, 128\) does not escape"
|
||||
}
|
||||
|
||||
{
|
||||
s1 := 128
|
||||
s2 := 256
|
||||
_ = make([]byte, s2, s1) // ERROR "make\(\[\]byte, s2, 128\) does not escape"
|
||||
}
|
||||
|
||||
allocLen(256) // ERROR "make\(\[\]byte, 256\) does not escape" "inlining call"
|
||||
allocCap(256) // ERROR "make\(\[\]byte, 0, 256\) does not escape" "inlining call"
|
||||
_ = newT(256) // ERROR "make\(\[\]byte, 256\) does not escape" "inlining call"
|
||||
|
||||
{
|
||||
size := globalConstSize
|
||||
_ = make([]byte, size) // ERROR "make\(\[\]byte, 128\) does not escape"
|
||||
}
|
||||
|
||||
allocLen(globalConstSize) // ERROR "make\(\[\]byte, 128\) does not escape" "inlining call"
|
||||
allocCap(globalConstSize) // ERROR "make\(\[\]byte, 0, 128\) does not escape" "inlining call"
|
||||
_ = newT(globalConstSize) // ERROR "make\(\[\]byte, 128\) does not escape" "inlining call"
|
||||
|
||||
{
|
||||
c := 128
|
||||
s := 256
|
||||
_ = make([]byte, s, c) // ERROR "make\(\[\]byte, s, 128\) does not escape"
|
||||
}
|
||||
|
||||
{
|
||||
s := 256
|
||||
_ = make([]byte, s, globalConstSize) // ERROR "make\(\[\]byte, s, 128\) does not escape"
|
||||
}
|
||||
|
||||
{
|
||||
_ = make([]byte, globalVarSize) // ERROR "make\(\[\]byte, globalVarSize\) does not escape"
|
||||
_ = make([]byte, globalVarSize, globalConstSize) // ERROR "make\(\[\]byte, globalVarSize, 128\) does not escape"
|
||||
}
|
||||
}
|
||||
|
||||
func allocLen(l int) []byte { // ERROR "can inline"
|
||||
return make([]byte, l) // ERROR "escapes to heap"
|
||||
}
|
||||
|
||||
func allocCap(l int) []byte { // ERROR "can inline"
|
||||
return make([]byte, 0, l) // ERROR "escapes to heap"
|
||||
}
|
||||
|
||||
type t struct {
|
||||
s []byte
|
||||
}
|
||||
|
||||
func newT(l int) t { // ERROR "can inline"
|
||||
return t{make([]byte, l)} // ERROR "make.*escapes to heap"
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func testMaps() {
|
||||
size := 128
|
||||
_ = make(map[string]int, size) // ERROR "does not escape"
|
||||
|
||||
_ = allocMapLen(128) // ERROR "does not escape" "inlining call"
|
||||
_ = newM(128) // ERROR "does not escape" "inlining call"
|
||||
}
|
||||
|
||||
func allocMapLen(l int) map[string]int { // ERROR "can inline"
|
||||
return make(map[string]int, l) // ERROR "escapes to heap"
|
||||
}
|
||||
|
||||
type m struct {
|
||||
m map[string]int
|
||||
}
|
||||
|
||||
func newM(l int) m { // ERROR "can inline"
|
||||
return m{make(map[string]int, l)} // ERROR "make.*escapes to heap"
|
||||
}
|
||||
@@ -45,7 +45,7 @@ func map3() []*int {
|
||||
m[&i] = &j
|
||||
var r []*int
|
||||
for k := range m {
|
||||
r = append(r, k)
|
||||
r = append(r, k) // ERROR "append escapes to heap"
|
||||
}
|
||||
return r
|
||||
}
|
||||
@@ -61,7 +61,7 @@ func map4() []*int {
|
||||
// We want to test exactly "for k, v := range m" rather than "for _, v := range m".
|
||||
// The following if is merely to use (but not leak) k.
|
||||
if k != nil {
|
||||
r = append(r, v)
|
||||
r = append(r, v) // ERROR "append escapes to heap"
|
||||
}
|
||||
}
|
||||
return r
|
||||
|
||||
@@ -18,29 +18,29 @@ var sink interface{}
|
||||
func slice0() {
|
||||
var s []*int
|
||||
// BAD: i should not escape
|
||||
i := 0 // ERROR "moved to heap: i"
|
||||
s = append(s, &i)
|
||||
i := 0 // ERROR "moved to heap: i"
|
||||
s = append(s, &i) // ERROR "append does not escape"
|
||||
_ = s
|
||||
}
|
||||
|
||||
func slice1() *int {
|
||||
var s []*int
|
||||
i := 0 // ERROR "moved to heap: i"
|
||||
s = append(s, &i)
|
||||
i := 0 // ERROR "moved to heap: i"
|
||||
s = append(s, &i) // ERROR "append does not escape"
|
||||
return s[0]
|
||||
}
|
||||
|
||||
func slice2() []*int {
|
||||
var s []*int
|
||||
i := 0 // ERROR "moved to heap: i"
|
||||
s = append(s, &i)
|
||||
i := 0 // ERROR "moved to heap: i"
|
||||
s = append(s, &i) // ERROR "append escapes to heap"
|
||||
return s
|
||||
}
|
||||
|
||||
func slice3() *int {
|
||||
var s []*int
|
||||
i := 0 // ERROR "moved to heap: i"
|
||||
s = append(s, &i)
|
||||
i := 0 // ERROR "moved to heap: i"
|
||||
s = append(s, &i) // ERROR "append does not escape"
|
||||
for _, p := range s {
|
||||
return p
|
||||
}
|
||||
@@ -124,7 +124,7 @@ NextVar:
|
||||
continue NextVar
|
||||
}
|
||||
}
|
||||
out = append(out, inkv)
|
||||
out = append(out, inkv) // ERROR "append escapes to heap"
|
||||
}
|
||||
return out
|
||||
}
|
||||
@@ -167,7 +167,7 @@ var resolveIPAddrTests = []resolveIPAddrTest{
|
||||
}
|
||||
|
||||
func setupTestData() {
|
||||
resolveIPAddrTests = append(resolveIPAddrTests,
|
||||
resolveIPAddrTests = append(resolveIPAddrTests, // ERROR "append escapes to heap"
|
||||
[]resolveIPAddrTest{ // ERROR "\[\]resolveIPAddrTest{...} does not escape"
|
||||
{"ip",
|
||||
"localhost",
|
||||
|
||||
62
test/escape_unique.go
Normal file
62
test/escape_unique.go
Normal file
@@ -0,0 +1,62 @@
|
||||
// errorcheck -0 -m -l
|
||||
|
||||
// Copyright 2025 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.
|
||||
|
||||
// Test escape analysis for unique.
|
||||
|
||||
package escape
|
||||
|
||||
import "unique"
|
||||
|
||||
type T string
|
||||
|
||||
func f1(s string) unique.Handle[string] { // ERROR "s does not escape$"
|
||||
return unique.Make(s)
|
||||
}
|
||||
|
||||
func f1a(s []byte) unique.Handle[string] { // ERROR "s does not escape$"
|
||||
return unique.Make(string(s)) // ERROR "string\(s\) does not escape$"
|
||||
}
|
||||
|
||||
func gen[S ~string](s S) unique.Handle[S] {
|
||||
return unique.Make(s)
|
||||
}
|
||||
|
||||
func f2(s T) unique.Handle[T] { // ERROR "s does not escape$"
|
||||
return unique.Make(s)
|
||||
}
|
||||
|
||||
func f3(s T) unique.Handle[T] { // ERROR "s does not escape$"
|
||||
return gen(s)
|
||||
}
|
||||
|
||||
type pair struct {
|
||||
s1 string
|
||||
s2 string
|
||||
}
|
||||
|
||||
func f4(s1 string, s2 string) unique.Handle[pair] { // ERROR "s1 does not escape$" "s2 does not escape$"
|
||||
return unique.Make(pair{s1, s2})
|
||||
}
|
||||
|
||||
type viaInterface struct {
|
||||
s any
|
||||
}
|
||||
|
||||
func f5(s string) unique.Handle[viaInterface] { // ERROR "leaking param: s$"
|
||||
return unique.Make(viaInterface{s}) // ERROR "s escapes to heap$"
|
||||
}
|
||||
|
||||
var sink any
|
||||
|
||||
func f6(s string) unique.Handle[string] { // ERROR "leaking param: s$"
|
||||
sink = s // ERROR "s escapes to heap$"
|
||||
return unique.Make(s)
|
||||
}
|
||||
|
||||
func f6a(s []byte) unique.Handle[string] { // ERROR "leaking param: s$"
|
||||
sink = s // ERROR "s escapes to heap$"
|
||||
return unique.Make(string(s)) // ERROR "string\(s\) does not escape$"
|
||||
}
|
||||
@@ -9,7 +9,7 @@ package main
|
||||
func putint(digits *string) {
|
||||
var i byte;
|
||||
i = (*digits)[7]; // compiles
|
||||
i = digits[7]; // ERROR "illegal|is not|invalid"
|
||||
i = digits[7]; // ERROR "illegal|is not|cannot index"
|
||||
_ = i;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,14 +17,14 @@ func FooN(vals ...*int) (s int) { // ERROR "vals does not escape"
|
||||
|
||||
// Append forces heap allocation and copies entries in vals to heap, therefore they escape to heap.
|
||||
func FooNx(x *int, vals ...*int) (s int) { // ERROR "leaking param: x" "leaking param content: vals"
|
||||
vals = append(vals, x)
|
||||
vals = append(vals, x) // ERROR "append does not escape"
|
||||
return FooN(vals...)
|
||||
}
|
||||
|
||||
var sink []*int
|
||||
|
||||
func FooNy(x *int, vals ...*int) (s int) { // ERROR "leaking param: x" "leaking param: vals"
|
||||
vals = append(vals, x)
|
||||
vals = append(vals, x) // ERROR "append escapes to heap"
|
||||
sink = vals
|
||||
return FooN(vals...)
|
||||
}
|
||||
@@ -84,7 +84,7 @@ func TFooI() {
|
||||
a := int32(1) // ERROR "moved to heap: a"
|
||||
b := "cat"
|
||||
c := &a
|
||||
FooI(a, b, c) // ERROR "a escapes to heap" "b escapes to heap" "... argument does not escape"
|
||||
FooI(a, b, c) // ERROR "a escapes to heap" ".cat. escapes to heap" "... argument does not escape"
|
||||
}
|
||||
|
||||
func FooJ(args ...interface{}) *int32 { // ERROR "leaking param: args to result ~r0 level=1"
|
||||
@@ -108,14 +108,14 @@ func TFooJ1() {
|
||||
a := int32(1)
|
||||
b := "cat"
|
||||
c := &a
|
||||
FooJ(a, b, c) // ERROR "a does not escape" "b does not escape" "... argument does not escape"
|
||||
FooJ(a, b, c) // ERROR "a does not escape" ".cat. does not escape" "... argument does not escape"
|
||||
}
|
||||
|
||||
func TFooJ2() {
|
||||
a := int32(1) // ERROR "moved to heap: a"
|
||||
b := "cat"
|
||||
c := &a
|
||||
isink = FooJ(a, b, c) // ERROR "a escapes to heap" "b escapes to heap" "... argument does not escape"
|
||||
isink = FooJ(a, b, c) // ERROR "a escapes to heap" ".cat. escapes to heap" "... argument does not escape"
|
||||
}
|
||||
|
||||
type fakeSlice struct {
|
||||
@@ -144,7 +144,7 @@ func TFooK2() {
|
||||
a := int32(1) // ERROR "moved to heap: a"
|
||||
b := "cat"
|
||||
c := &a
|
||||
fs := fakeSlice{3, &[4]interface{}{a, b, c, nil}} // ERROR "a escapes to heap" "b escapes to heap" "&\[4\]interface {}{...} does not escape"
|
||||
fs := fakeSlice{3, &[4]interface{}{a, b, c, nil}} // ERROR "a escapes to heap" ".cat. escapes to heap" "&\[4\]interface {}{...} does not escape"
|
||||
isink = FooK(fs)
|
||||
}
|
||||
|
||||
@@ -169,6 +169,6 @@ func TFooL2() {
|
||||
a := int32(1) // ERROR "moved to heap: a"
|
||||
b := "cat"
|
||||
c := &a
|
||||
s := []interface{}{a, b, c} // ERROR "a escapes to heap" "b escapes to heap" "\[\]interface {}{...} does not escape"
|
||||
s := []interface{}{a, b, c} // ERROR "a escapes to heap" ".cat. escapes to heap" "\[\]interface {}{...} does not escape"
|
||||
isink = FooL(s)
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ func test1(iter int) {
|
||||
// var fn func() // this makes it work, because fn stays off heap
|
||||
j := 0 // ERROR "moved to heap: j$"
|
||||
fn = func() { // ERROR "func literal escapes to heap$"
|
||||
m[i] = append(m[i], 0)
|
||||
m[i] = append(m[i], 0) // ERROR "append escapes to heap"
|
||||
if j < 25 {
|
||||
j++
|
||||
fn()
|
||||
@@ -75,7 +75,7 @@ func test2(iter int) {
|
||||
var fn func() // this makes it work, because fn stays off heap
|
||||
j := 0
|
||||
fn = func() { // ERROR "func literal does not escape$"
|
||||
m[i] = append(m[i], 0)
|
||||
m[i] = append(m[i], 0) // ERROR "append escapes to heap"
|
||||
if j < 25 {
|
||||
j++
|
||||
fn()
|
||||
|
||||
@@ -6,4 +6,4 @@
|
||||
|
||||
package main
|
||||
|
||||
const A = complex(0()) // ERROR "cannot call non-function"
|
||||
const A = complex(0()) // ERROR "cannot call .* not a function"
|
||||
|
||||
@@ -13,7 +13,7 @@ func F() {
|
||||
slice := []int{1, 2, 3}
|
||||
_ = slice
|
||||
len := int(2)
|
||||
println(len(slice)) // ERROR "cannot call non-function len .type int., declared at LINE-1|expected function|cannot call non-function len"
|
||||
println(len(slice)) // ERROR "cannot call non-function len .type int., declared at LINE-1|expected function|cannot call len"
|
||||
const iota = 1
|
||||
println(iota(slice)) // ERROR "cannot call non-function iota .type int., declared at LINE-1|expected function|cannot call non-function iota"
|
||||
println(iota(slice)) // ERROR "cannot call non-function iota .type int., declared at LINE-1|expected function|cannot call iota"
|
||||
}
|
||||
|
||||
@@ -11,9 +11,9 @@ package p
|
||||
var a = []int{1,2,3}
|
||||
|
||||
func _(len int) {
|
||||
_ = len(a) // ERROR "cannot call non-function|expected function"
|
||||
_ = len(a) // ERROR "cannot call|expected function"
|
||||
}
|
||||
|
||||
var cap = false
|
||||
var _ = cap(a) // ERROR "cannot call non-function|expected function"
|
||||
var _ = cap(a) // ERROR "cannot call|expected function"
|
||||
|
||||
|
||||
@@ -15,5 +15,5 @@ func debugf(format string, args ...interface{}) { // ERROR "can inline debugf" "
|
||||
|
||||
func bar() { // ERROR "can inline bar"
|
||||
value := 10
|
||||
debugf("value is %d", value) // ERROR "inlining call to debugf" "value does not escape" "\.\.\. argument does not escape"
|
||||
debugf("value is %d", value) // ERROR "inlining call to debugf" "10 does not escape" "\.\.\. argument does not escape"
|
||||
}
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !nacl && !js
|
||||
//go:build !nacl && !js && !wasip1
|
||||
|
||||
package ignored
|
||||
|
||||
@@ -6,4 +6,4 @@
|
||||
|
||||
package p
|
||||
|
||||
func init() // ERROR "missing function body|cannot declare init"
|
||||
func init() // ERROR "func init must have a body|cannot declare init"
|
||||
|
||||
@@ -12,6 +12,6 @@ func f() { // ERROR ""
|
||||
_ = make([]byte, 100, 1<<17) // ERROR "too large for stack" ""
|
||||
_ = make([]byte, n, 1<<17) // ERROR "too large for stack" ""
|
||||
|
||||
_ = make([]byte, n) // ERROR "non-constant size" ""
|
||||
_ = make([]byte, 100, m) // ERROR "non-constant size" ""
|
||||
_ = make([]byte, n) // ERROR "does not escape"
|
||||
_ = make([]byte, 100, m) // ERROR "does not escape"
|
||||
}
|
||||
|
||||
17
test/fixedbugs/issue71184.go
Normal file
17
test/fixedbugs/issue71184.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// compile
|
||||
|
||||
// Copyright 2024 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 x
|
||||
|
||||
func F[T int32]() {
|
||||
_ = G[*[0]T]()[:]
|
||||
}
|
||||
|
||||
func G[T any]() (v T) {
|
||||
return
|
||||
}
|
||||
|
||||
var _ = F[int32]
|
||||
19
test/fixedbugs/issue71225.go
Normal file
19
test/fixedbugs/issue71225.go
Normal file
@@ -0,0 +1,19 @@
|
||||
// build
|
||||
|
||||
//go:build cgo
|
||||
|
||||
// Copyright 2025 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
// #cgo CFLAGS: -Werror -Wunused-parameter
|
||||
import "C"
|
||||
|
||||
func main() {
|
||||
}
|
||||
|
||||
//export Fn
|
||||
func Fn() {
|
||||
}
|
||||
29
test/fixedbugs/issue71226.go
Normal file
29
test/fixedbugs/issue71226.go
Normal file
@@ -0,0 +1,29 @@
|
||||
// build
|
||||
|
||||
//go:build cgo
|
||||
|
||||
// Copyright 2025 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -Werror -Wimplicit-function-declaration
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static void CFn(_GoString_ gostr) {
|
||||
printf("%.*s\n", (int)(_GoStringLen(gostr)), _GoStringPtr(gostr));
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func main() {
|
||||
C.CFn("hello, world")
|
||||
}
|
||||
|
||||
// The bug only occurs if there is an exported function.
|
||||
//export Fn
|
||||
func Fn() {
|
||||
}
|
||||
20
test/fixedbugs/issue71759.go
Normal file
20
test/fixedbugs/issue71759.go
Normal file
@@ -0,0 +1,20 @@
|
||||
// run
|
||||
|
||||
// Copyright 2025 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
//go:noinline
|
||||
func f(p *[2]int32) (int64, int64) {
|
||||
return int64(p[0]), int64(p[1])
|
||||
}
|
||||
|
||||
func main() {
|
||||
p := [2]int32{-1, -1}
|
||||
x, y := f(&p)
|
||||
if x != -1 || y != -1 {
|
||||
println(x, y)
|
||||
}
|
||||
}
|
||||
70
test/fixedbugs/issue72844.go
Normal file
70
test/fixedbugs/issue72844.go
Normal file
@@ -0,0 +1,70 @@
|
||||
// run
|
||||
|
||||
// Copyright 2025 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
//go:noinline
|
||||
func nilPtrFunc() *[4]int {
|
||||
return nil
|
||||
}
|
||||
|
||||
var nilPtrVar *[4]int
|
||||
|
||||
func testLen1() {
|
||||
_ = len(*nilPtrFunc())
|
||||
}
|
||||
|
||||
func testLen2() {
|
||||
_ = len(nilPtrFunc())
|
||||
}
|
||||
|
||||
func testLen3() {
|
||||
_ = len(*nilPtrVar)
|
||||
}
|
||||
|
||||
func testLen4() {
|
||||
_ = len(nilPtrVar)
|
||||
}
|
||||
|
||||
func testRange1() {
|
||||
for range *nilPtrFunc() {
|
||||
}
|
||||
}
|
||||
func testRange2() {
|
||||
for range nilPtrFunc() {
|
||||
}
|
||||
}
|
||||
func testRange3() {
|
||||
for range *nilPtrVar {
|
||||
}
|
||||
}
|
||||
func testRange4() {
|
||||
for range nilPtrVar {
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
shouldPanic(testLen1)
|
||||
shouldNotPanic(testLen2)
|
||||
shouldNotPanic(testLen3)
|
||||
shouldNotPanic(testLen4)
|
||||
shouldPanic(testRange1)
|
||||
shouldNotPanic(testRange2)
|
||||
shouldNotPanic(testRange3)
|
||||
shouldNotPanic(testRange4)
|
||||
}
|
||||
|
||||
func shouldPanic(f func()) {
|
||||
defer func() {
|
||||
if e := recover(); e == nil {
|
||||
panic("should have panicked")
|
||||
}
|
||||
}()
|
||||
f()
|
||||
}
|
||||
func shouldNotPanic(f func()) {
|
||||
f()
|
||||
}
|
||||
24
test/fixedbugs/issue72860.go
Normal file
24
test/fixedbugs/issue72860.go
Normal file
@@ -0,0 +1,24 @@
|
||||
// run
|
||||
|
||||
// Copyright 2025 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
//go:noinline
|
||||
func f(p *int, b bool) int {
|
||||
valid := *p >= 0
|
||||
if !b || !valid {
|
||||
return 5
|
||||
}
|
||||
return 6
|
||||
}
|
||||
func main() {
|
||||
defer func() {
|
||||
if e := recover(); e == nil {
|
||||
println("should have panicked")
|
||||
}
|
||||
}()
|
||||
f(nil, false)
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
_ = copy(nil, []int{}) // ERROR "use of untyped nil|left argument must be a slice|expects slice arguments"
|
||||
_ = copy([]int{}, nil) // ERROR "use of untyped nil|second argument must be slice or string|expects slice arguments"
|
||||
_ = copy(nil, []int{}) // ERROR "use of untyped nil|left argument must be a slice|argument must be a slice; have untyped nil"
|
||||
_ = copy([]int{}, nil) // ERROR "use of untyped nil|second argument must be slice or string|argument must be a slice; have untyped nil"
|
||||
_ = 1 + true // ERROR "mismatched types untyped int and untyped bool|incompatible types|cannot convert"
|
||||
}
|
||||
|
||||
15
test/fixedbugs/issue73180.go
Normal file
15
test/fixedbugs/issue73180.go
Normal file
@@ -0,0 +1,15 @@
|
||||
// build
|
||||
|
||||
// Copyright 2025 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 p
|
||||
|
||||
func F(a, b map[float32]int) int {
|
||||
var st *struct {
|
||||
n int
|
||||
f float32
|
||||
}
|
||||
return a[0] + b[st.f]
|
||||
}
|
||||
36
test/fixedbugs/issue73200.go
Normal file
36
test/fixedbugs/issue73200.go
Normal file
@@ -0,0 +1,36 @@
|
||||
// build
|
||||
|
||||
// Copyright 2025 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
var g bool
|
||||
|
||||
func main() {
|
||||
l_4 := uint32(0x6E54EE87)
|
||||
v4 := int8(-Int64FromInt64(1))
|
||||
g = int32(v4) >= safe_mod_func_int32_t_s_s(BoolInt32(l_4 >= 1), 7)
|
||||
}
|
||||
|
||||
func safe_mod_func_int32_t_s_s(si1 int32, si2 int32) (r int32) {
|
||||
var v1 int32
|
||||
if si2 == 0 {
|
||||
v1 = si1
|
||||
} else {
|
||||
v1 = si1 % si2
|
||||
}
|
||||
return v1
|
||||
}
|
||||
|
||||
func Int64FromInt64(n int64) int64 {
|
||||
return n
|
||||
}
|
||||
|
||||
func BoolInt32(b bool) int32 {
|
||||
if b {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
18
test/fixedbugs/issue73309.go
Normal file
18
test/fixedbugs/issue73309.go
Normal file
@@ -0,0 +1,18 @@
|
||||
// compile
|
||||
|
||||
// Copyright 2025 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
type B[T any] struct {
|
||||
a A[T]
|
||||
}
|
||||
|
||||
type A[T any] = func(B[T]) bool
|
||||
|
||||
func main() {
|
||||
var s A[int]
|
||||
println(s)
|
||||
}
|
||||
88
test/fixedbugs/issue73309b.go
Normal file
88
test/fixedbugs/issue73309b.go
Normal file
@@ -0,0 +1,88 @@
|
||||
// compile
|
||||
|
||||
// Copyright 2025 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
type Unsigned interface {
|
||||
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
|
||||
}
|
||||
|
||||
// a Validator instance
|
||||
type Validator []Validable
|
||||
|
||||
type Numeric interface {
|
||||
~int | ~int8 | ~int16 | ~int32 | ~int64 | ~float32 | ~float64
|
||||
}
|
||||
|
||||
func (v Validator) Valid() bool {
|
||||
for _, field := range v {
|
||||
if !field.Validate() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
type Validable interface {
|
||||
Validate() bool
|
||||
}
|
||||
|
||||
type FieldDef[T any] struct {
|
||||
value T
|
||||
rules []Rule[T]
|
||||
}
|
||||
|
||||
func (f FieldDef[T]) Validate() bool {
|
||||
for _, rule := range f.rules {
|
||||
if !rule(f) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
type Rule[T any] = func(FieldDef[T]) bool
|
||||
|
||||
func Field[T any](value T, rules ...Rule[T]) *FieldDef[T] {
|
||||
return &FieldDef[T]{value: value, rules: rules}
|
||||
}
|
||||
|
||||
type StringRule = Rule[string]
|
||||
|
||||
type NumericRule[T Numeric] = Rule[T]
|
||||
|
||||
type UnsignedRule[T Unsigned] = Rule[T]
|
||||
|
||||
func MinS(n int) StringRule {
|
||||
return func(fd FieldDef[string]) bool {
|
||||
return len(fd.value) < n
|
||||
}
|
||||
}
|
||||
|
||||
func MinD[T Numeric](n T) NumericRule[T] {
|
||||
return func(fd FieldDef[T]) bool {
|
||||
return fd.value < n
|
||||
}
|
||||
}
|
||||
|
||||
func MinU[T Unsigned](n T) UnsignedRule[T] {
|
||||
return func(fd FieldDef[T]) bool {
|
||||
return fd.value < n
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
v := Validator{
|
||||
Field("test", MinS(5)),
|
||||
}
|
||||
|
||||
if !v.Valid() {
|
||||
println("invalid")
|
||||
return
|
||||
}
|
||||
|
||||
println("valid")
|
||||
}
|
||||
17
test/fixedbugs/issue73476.go
Normal file
17
test/fixedbugs/issue73476.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// run
|
||||
|
||||
// Copyright 2025 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
//go:noinline
|
||||
func f(p *[4]int) {
|
||||
for i := range (*p) { // Note the parentheses! gofmt wants to remove them - don't let it!
|
||||
println(i)
|
||||
}
|
||||
}
|
||||
func main() {
|
||||
f(nil)
|
||||
}
|
||||
4
test/fixedbugs/issue73476.out
Normal file
4
test/fixedbugs/issue73476.out
Normal file
@@ -0,0 +1,4 @@
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
20
test/fixedbugs/issue73483.go
Normal file
20
test/fixedbugs/issue73483.go
Normal file
@@ -0,0 +1,20 @@
|
||||
// run -race
|
||||
|
||||
//go:build race && cgo
|
||||
|
||||
// Copyright 2025 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
/*
|
||||
int v[8192];
|
||||
*/
|
||||
import "C"
|
||||
|
||||
var x [8192]C.int
|
||||
|
||||
func main() {
|
||||
copy(C.v[:], x[:])
|
||||
}
|
||||
25
test/fixedbugs/issue73491.go
Normal file
25
test/fixedbugs/issue73491.go
Normal file
@@ -0,0 +1,25 @@
|
||||
// build
|
||||
|
||||
// Copyright 2025 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
type T int
|
||||
|
||||
const K T = 5
|
||||
|
||||
type P struct {
|
||||
a [K]*byte
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func f(p *P) {
|
||||
for i := range K {
|
||||
p.a[i] = nil
|
||||
}
|
||||
}
|
||||
func main() {
|
||||
f(nil)
|
||||
}
|
||||
37
test/fixedbugs/issue73716.go
Normal file
37
test/fixedbugs/issue73716.go
Normal file
@@ -0,0 +1,37 @@
|
||||
// build
|
||||
|
||||
// Copyright 2025 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.
|
||||
|
||||
// Issue 73716: cmd/compile: unnamed functions missing FuncInfo
|
||||
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type EP func()
|
||||
type F func(EP) EP
|
||||
|
||||
func main() {
|
||||
eps := []EP{ep1, ep2}
|
||||
var h EP
|
||||
|
||||
for _, ep := range eps {
|
||||
h = F(func(e EP) EP {
|
||||
return func() {
|
||||
ep()
|
||||
e()
|
||||
}
|
||||
})(h)
|
||||
}
|
||||
h()
|
||||
}
|
||||
|
||||
func ep1() {
|
||||
fmt.Printf("ep1\n")
|
||||
}
|
||||
|
||||
func ep2() {
|
||||
fmt.Printf("ep2\n")
|
||||
}
|
||||
58
test/fixedbugs/issue73823.go
Normal file
58
test/fixedbugs/issue73823.go
Normal file
@@ -0,0 +1,58 @@
|
||||
// compile
|
||||
|
||||
// Copyright 2025 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 p
|
||||
|
||||
type Backend interface {
|
||||
Hash(ignores func(bucketName, keyName []byte) bool) (uint32, error)
|
||||
}
|
||||
|
||||
type backend struct {
|
||||
}
|
||||
|
||||
func first() (key []byte, value []byte) {
|
||||
return
|
||||
}
|
||||
|
||||
func (b *backend) View(fn func() error) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *backend) Hash(ignores func(bucketName, keyName []byte) bool) (uint32, error) {
|
||||
err := b.View(func() error {
|
||||
for next, _ := first(); next != nil; next, _ = first() {
|
||||
_ = next
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return 0, err
|
||||
}
|
||||
|
||||
func defragdb() error {
|
||||
for next, _ := first(); next != nil; next, _ = first() {
|
||||
_ = f(next)
|
||||
ForEach(func(k, v []byte) error {
|
||||
_ = next
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ForEach(fn func(k, v []byte) error) error {
|
||||
for k, v := first(); k != nil; k, v = first() {
|
||||
if err := fn(k, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func f(any) string {
|
||||
return ""
|
||||
}
|
||||
34
test/fixedbugs/issue73888.go
Normal file
34
test/fixedbugs/issue73888.go
Normal file
@@ -0,0 +1,34 @@
|
||||
// run
|
||||
|
||||
// Copyright 2025 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
type SourceRange struct {
|
||||
x, y int
|
||||
}
|
||||
|
||||
func (r *SourceRange) String() string {
|
||||
return "hello"
|
||||
}
|
||||
|
||||
type SourceNode interface {
|
||||
SourceRange()
|
||||
}
|
||||
|
||||
type testNode SourceRange
|
||||
|
||||
func (tn testNode) SourceRange() {
|
||||
}
|
||||
|
||||
func main() {
|
||||
n := testNode(SourceRange{}) // zero value
|
||||
Errorf(n)
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func Errorf(n SourceNode) {
|
||||
n.SourceRange()
|
||||
}
|
||||
34
test/fixedbugs/issue73888b.go
Normal file
34
test/fixedbugs/issue73888b.go
Normal file
@@ -0,0 +1,34 @@
|
||||
// run
|
||||
|
||||
// Copyright 2025 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
type SourceRange struct {
|
||||
x, y int
|
||||
}
|
||||
|
||||
func (r *SourceRange) String() string {
|
||||
return "hello"
|
||||
}
|
||||
|
||||
type SourceNode interface {
|
||||
SourceRange()
|
||||
}
|
||||
|
||||
type testNode SourceRange
|
||||
|
||||
func (tn testNode) SourceRange() {
|
||||
}
|
||||
|
||||
func main() {
|
||||
n := testNode(SourceRange{1, 1}) // not zero value
|
||||
Errorf(n)
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func Errorf(n SourceNode) {
|
||||
n.SourceRange()
|
||||
}
|
||||
30
test/fixedbugs/issue74379.go
Normal file
30
test/fixedbugs/issue74379.go
Normal file
@@ -0,0 +1,30 @@
|
||||
// run
|
||||
|
||||
// Copyright 2025 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func crashOnErr(err error) bool {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func main() {
|
||||
defer func() {
|
||||
if recover() == nil {
|
||||
fmt.Println("failed to have expected panic")
|
||||
os.Exit(1)
|
||||
}
|
||||
}()
|
||||
fmt.Println(crashOnErr(errors.New("test error")))
|
||||
}
|
||||
32
test/fixedbugs/issue74379b.go
Normal file
32
test/fixedbugs/issue74379b.go
Normal file
@@ -0,0 +1,32 @@
|
||||
// run
|
||||
|
||||
// Copyright 2025 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func crashOnErr(err error) int {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return 10
|
||||
}
|
||||
|
||||
func main() {
|
||||
defer func() {
|
||||
if recover() == nil {
|
||||
fmt.Println("failed to have expected panic")
|
||||
os.Exit(1)
|
||||
}
|
||||
}()
|
||||
|
||||
s := make([]int, crashOnErr(errors.New("test error")))
|
||||
println("unreachable: len(s) =", len(s))
|
||||
}
|
||||
54
test/fixedbugs/issue74379c.go
Normal file
54
test/fixedbugs/issue74379c.go
Normal file
@@ -0,0 +1,54 @@
|
||||
// run
|
||||
|
||||
// Copyright 2025 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
type S struct{ a, b int }
|
||||
|
||||
func crashOnErr1(err error) S {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return S{} // zero value struct
|
||||
}
|
||||
|
||||
func f1() {
|
||||
defer func() {
|
||||
if recover() == nil {
|
||||
fmt.Println("failed to have expected panic")
|
||||
os.Exit(1)
|
||||
}
|
||||
}()
|
||||
fmt.Println(crashOnErr1(errors.New("test error")))
|
||||
}
|
||||
|
||||
func crashOnErr2(err error) S {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return S{1, 2} // not zero value struct
|
||||
}
|
||||
|
||||
func f2() {
|
||||
defer func() {
|
||||
if recover() == nil {
|
||||
fmt.Println("failed to have expected panic")
|
||||
os.Exit(1)
|
||||
}
|
||||
}()
|
||||
fmt.Println(crashOnErr2(errors.New("test error")))
|
||||
}
|
||||
|
||||
func main() {
|
||||
f1()
|
||||
f2()
|
||||
}
|
||||
@@ -21,15 +21,15 @@ func endian(b []byte) uint64 { // ERROR "can inline endian" "b does not escape"
|
||||
}
|
||||
|
||||
func appendLittleEndian(b []byte) []byte { // ERROR "can inline appendLittleEndian" "leaking param: b to result ~r0 level=0"
|
||||
b = binary.LittleEndian.AppendUint64(b, 64) // ERROR "inlining call to binary.littleEndian.AppendUint64"
|
||||
b = binary.LittleEndian.AppendUint32(b, 32) // ERROR "inlining call to binary.littleEndian.AppendUint32"
|
||||
b = binary.LittleEndian.AppendUint16(b, 16) // ERROR "inlining call to binary.littleEndian.AppendUint16"
|
||||
b = binary.LittleEndian.AppendUint64(b, 64) // ERROR "inlining call to binary.littleEndian.AppendUint64" "append escapes to heap"
|
||||
b = binary.LittleEndian.AppendUint32(b, 32) // ERROR "inlining call to binary.littleEndian.AppendUint32" "append escapes to heap"
|
||||
b = binary.LittleEndian.AppendUint16(b, 16) // ERROR "inlining call to binary.littleEndian.AppendUint16" "append escapes to heap"
|
||||
return b
|
||||
}
|
||||
|
||||
func appendBigEndian(b []byte) []byte { // ERROR "can inline appendBigEndian" "leaking param: b to result ~r0 level=0"
|
||||
b = binary.BigEndian.AppendUint64(b, 64) // ERROR "inlining call to binary.bigEndian.AppendUint64"
|
||||
b = binary.BigEndian.AppendUint32(b, 32) // ERROR "inlining call to binary.bigEndian.AppendUint32"
|
||||
b = binary.BigEndian.AppendUint16(b, 16) // ERROR "inlining call to binary.bigEndian.AppendUint16"
|
||||
b = binary.BigEndian.AppendUint64(b, 64) // ERROR "inlining call to binary.bigEndian.AppendUint64" "append escapes to heap"
|
||||
b = binary.BigEndian.AppendUint32(b, 32) // ERROR "inlining call to binary.bigEndian.AppendUint32" "append escapes to heap"
|
||||
b = binary.BigEndian.AppendUint16(b, 16) // ERROR "inlining call to binary.bigEndian.AppendUint16" "append escapes to heap"
|
||||
return b
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ var once *sync.Once
|
||||
|
||||
func small7() { // ERROR "can inline small7"
|
||||
// the Do fast path should be inlined
|
||||
once.Do(small5) // ERROR "inlining call to sync\.\(\*Once\)\.Do" "inlining call to atomic\.\(\*Uint32\)\.Load"
|
||||
once.Do(small5) // ERROR "inlining call to sync\.\(\*Once\)\.Do" "inlining call to atomic\.\(\*Bool\)\.Load"
|
||||
}
|
||||
|
||||
var rwmutex *sync.RWMutex
|
||||
|
||||
46
test/live.go
46
test/live.go
@@ -337,23 +337,34 @@ func f20() {
|
||||
ch <- byteptr()
|
||||
}
|
||||
|
||||
func f21() {
|
||||
func f21(x, y string) { // ERROR "live at entry to f21: x y"
|
||||
// key temporary for mapaccess using array literal key.
|
||||
var z *byte
|
||||
if b {
|
||||
z = m2[[2]string{"x", "y"}] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
|
||||
z = m2[[2]string{x, y}] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
|
||||
}
|
||||
z = m2[[2]string{"x", "y"}]
|
||||
z = m2[[2]string{"x", "y"}]
|
||||
printbytepointer(z)
|
||||
}
|
||||
|
||||
func f23() {
|
||||
func f21b() {
|
||||
// key temporary for mapaccess using array literal key.
|
||||
var z *byte
|
||||
if b {
|
||||
z = m2[[2]string{"x", "y"}]
|
||||
}
|
||||
z = m2[[2]string{"x", "y"}]
|
||||
z = m2[[2]string{"x", "y"}]
|
||||
printbytepointer(z)
|
||||
}
|
||||
|
||||
func f23(x, y string) { // ERROR "live at entry to f23: x y"
|
||||
// key temporary for two-result map access using array literal key.
|
||||
var z *byte
|
||||
var ok bool
|
||||
if b {
|
||||
z, ok = m2[[2]string{"x", "y"}] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
|
||||
z, ok = m2[[2]string{x, y}] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
|
||||
}
|
||||
z, ok = m2[[2]string{"x", "y"}]
|
||||
z, ok = m2[[2]string{"x", "y"}]
|
||||
@@ -361,11 +372,34 @@ func f23() {
|
||||
print(ok)
|
||||
}
|
||||
|
||||
func f24() {
|
||||
func f23b() {
|
||||
// key temporary for two-result map access using array literal key.
|
||||
var z *byte
|
||||
var ok bool
|
||||
if b {
|
||||
z, ok = m2[[2]string{"x", "y"}]
|
||||
}
|
||||
z, ok = m2[[2]string{"x", "y"}]
|
||||
z, ok = m2[[2]string{"x", "y"}]
|
||||
printbytepointer(z)
|
||||
print(ok)
|
||||
}
|
||||
|
||||
func f24(x, y string) { // ERROR "live at entry to f24: x y"
|
||||
// key temporary for map access using array literal key.
|
||||
// value temporary too.
|
||||
if b {
|
||||
m2[[2]string{"x", "y"}] = nil // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
|
||||
m2[[2]string{x, y}] = nil // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
|
||||
}
|
||||
m2[[2]string{"x", "y"}] = nil
|
||||
m2[[2]string{"x", "y"}] = nil
|
||||
}
|
||||
|
||||
func f24b() {
|
||||
// key temporary for map access using array literal key.
|
||||
// value temporary too.
|
||||
if b {
|
||||
m2[[2]string{"x", "y"}] = nil
|
||||
}
|
||||
m2[[2]string{"x", "y"}] = nil
|
||||
m2[[2]string{"x", "y"}] = nil
|
||||
|
||||
@@ -335,23 +335,34 @@ func f20() {
|
||||
ch <- byteptr()
|
||||
}
|
||||
|
||||
func f21() {
|
||||
func f21(x, y string) { // ERROR "live at entry to f21: x y"
|
||||
// key temporary for mapaccess using array literal key.
|
||||
var z *byte
|
||||
if b {
|
||||
z = m2[[2]string{"x", "y"}] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
|
||||
z = m2[[2]string{x, y}] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
|
||||
}
|
||||
z = m2[[2]string{"x", "y"}]
|
||||
z = m2[[2]string{"x", "y"}]
|
||||
printbytepointer(z)
|
||||
}
|
||||
|
||||
func f23() {
|
||||
func f21b() {
|
||||
// key temporary for mapaccess using array literal key.
|
||||
var z *byte
|
||||
if b {
|
||||
z = m2[[2]string{"x", "y"}]
|
||||
}
|
||||
z = m2[[2]string{"x", "y"}]
|
||||
z = m2[[2]string{"x", "y"}]
|
||||
printbytepointer(z)
|
||||
}
|
||||
|
||||
func f23(x, y string) { // ERROR "live at entry to f23: x y"
|
||||
// key temporary for two-result map access using array literal key.
|
||||
var z *byte
|
||||
var ok bool
|
||||
if b {
|
||||
z, ok = m2[[2]string{"x", "y"}] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
|
||||
z, ok = m2[[2]string{x, y}] // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
|
||||
}
|
||||
z, ok = m2[[2]string{"x", "y"}]
|
||||
z, ok = m2[[2]string{"x", "y"}]
|
||||
@@ -359,11 +370,34 @@ func f23() {
|
||||
print(ok)
|
||||
}
|
||||
|
||||
func f24() {
|
||||
func f23b() {
|
||||
// key temporary for two-result map access using array literal key.
|
||||
var z *byte
|
||||
var ok bool
|
||||
if b {
|
||||
z, ok = m2[[2]string{"x", "y"}]
|
||||
}
|
||||
z, ok = m2[[2]string{"x", "y"}]
|
||||
z, ok = m2[[2]string{"x", "y"}]
|
||||
printbytepointer(z)
|
||||
print(ok)
|
||||
}
|
||||
|
||||
func f24(x, y string) { // ERROR "live at entry to f24: x y"
|
||||
// key temporary for map access using array lit3ral key.
|
||||
// value temporary too.
|
||||
if b {
|
||||
m2[[2]string{x, y}] = nil // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
|
||||
}
|
||||
m2[[2]string{"x", "y"}] = nil
|
||||
m2[[2]string{"x", "y"}] = nil
|
||||
}
|
||||
|
||||
func f24b() {
|
||||
// key temporary for map access using array literal key.
|
||||
// value temporary too.
|
||||
if b {
|
||||
m2[[2]string{"x", "y"}] = nil // ERROR "stack object .autotmp_[0-9]+ \[2\]string$"
|
||||
m2[[2]string{"x", "y"}] = nil
|
||||
}
|
||||
m2[[2]string{"x", "y"}] = nil
|
||||
m2[[2]string{"x", "y"}] = nil
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
// Test that the implementation catches nil ptr indirection
|
||||
// in a large address space.
|
||||
|
||||
// Address space starts at 1<<32 on AIX and on darwin/arm64 and on windows/arm64, so dummy is too far.
|
||||
//go:build !aix && (!darwin || !arm64) && (!windows || !arm64)
|
||||
// Address space starts at 1<<32 on AIX and on darwin/arm64 and on windows/[amd64/arm64], so dummy is too far.
|
||||
//go:build !aix && (!darwin || !arm64) && (!windows || (!amd64 && !arm64))
|
||||
|
||||
package main
|
||||
|
||||
|
||||
@@ -129,5 +129,27 @@ func f9(a, b int) bool {
|
||||
return c
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func f10and(a bool, b bool) bool {
|
||||
var x bool
|
||||
if a {
|
||||
x = b
|
||||
} else {
|
||||
x = a
|
||||
}
|
||||
return x // ERROR "converted OpPhi to AndB$"
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func f11or(a bool, b bool) bool {
|
||||
var x bool
|
||||
if a {
|
||||
x = a
|
||||
} else {
|
||||
x = b
|
||||
}
|
||||
return x // ERROR "converted OpPhi to OrB$"
|
||||
}
|
||||
|
||||
func main() {
|
||||
}
|
||||
|
||||
393
test/prove.go
393
test/prove.go
@@ -1391,8 +1391,8 @@ func bitLen8(x uint8, ensureBothBranchesCouldHappen bool) int {
|
||||
}
|
||||
|
||||
func xor64(a, b uint64, ensureBothBranchesCouldHappen bool) int {
|
||||
a &= 0xff
|
||||
b &= 0xfff
|
||||
a = min(a, 0xff)
|
||||
b = min(b, 0xfff)
|
||||
|
||||
z := a ^ b
|
||||
|
||||
@@ -1409,8 +1409,8 @@ func xor64(a, b uint64, ensureBothBranchesCouldHappen bool) int {
|
||||
}
|
||||
|
||||
func or64(a, b uint64, ensureBothBranchesCouldHappen bool) int {
|
||||
a &= 0xff
|
||||
b &= 0xfff
|
||||
a = min(a, 0xff)
|
||||
b = min(b, 0xfff)
|
||||
|
||||
z := a | b
|
||||
|
||||
@@ -1427,8 +1427,8 @@ func or64(a, b uint64, ensureBothBranchesCouldHappen bool) int {
|
||||
}
|
||||
|
||||
func mod64uWithSmallerDividendMax(a, b uint64, ensureBothBranchesCouldHappen bool) int {
|
||||
a &= 0xff
|
||||
b &= 0xfff
|
||||
a = min(a, 0xff)
|
||||
b = min(b, 0xfff)
|
||||
|
||||
z := bits.Len64(a % b) // see go.dev/issue/68857 for bits.Len64
|
||||
|
||||
@@ -1444,8 +1444,8 @@ func mod64uWithSmallerDividendMax(a, b uint64, ensureBothBranchesCouldHappen boo
|
||||
return z
|
||||
}
|
||||
func mod64uWithSmallerDivisorMax(a, b uint64, ensureBothBranchesCouldHappen bool) int {
|
||||
a &= 0xfff
|
||||
b &= 0x10 // we need bits.Len64(b.umax) != bits.Len64(b.umax-1)
|
||||
a = min(a, 0xfff)
|
||||
b = min(b, 0x10) // we need bits.Len64(b.umax) != bits.Len64(b.umax-1)
|
||||
|
||||
z := bits.Len64(a % b) // see go.dev/issue/68857 for bits.Len64
|
||||
|
||||
@@ -1461,8 +1461,8 @@ func mod64uWithSmallerDivisorMax(a, b uint64, ensureBothBranchesCouldHappen bool
|
||||
return z
|
||||
}
|
||||
func mod64uWithIdenticalMax(a, b uint64, ensureBothBranchesCouldHappen bool) int {
|
||||
a &= 0x10
|
||||
b &= 0x10 // we need bits.Len64(b.umax) != bits.Len64(b.umax-1)
|
||||
a = min(a, 0x10)
|
||||
b = min(b, 0x10) // we need bits.Len64(b.umax) != bits.Len64(b.umax-1)
|
||||
|
||||
z := bits.Len64(a % b) // see go.dev/issue/68857 for bits.Len64
|
||||
|
||||
@@ -1481,8 +1481,8 @@ func mod64sPositiveWithSmallerDividendMax(a, b int64, ensureBothBranchesCouldHap
|
||||
if a < 0 || b < 0 {
|
||||
return 42
|
||||
}
|
||||
a &= 0xff
|
||||
b &= 0xfff
|
||||
a = min(a, 0xff)
|
||||
b = min(b, 0xfff)
|
||||
|
||||
z := a % b // ERROR "Proved Mod64 does not need fix-up$"
|
||||
|
||||
@@ -1501,8 +1501,8 @@ func mod64sPositiveWithSmallerDivisorMax(a, b int64, ensureBothBranchesCouldHapp
|
||||
if a < 0 || b < 0 {
|
||||
return 42
|
||||
}
|
||||
a &= 0xfff
|
||||
b &= 0xff
|
||||
a = min(a, 0xfff)
|
||||
b = min(b, 0xff)
|
||||
|
||||
z := a % b // ERROR "Proved Mod64 does not need fix-up$"
|
||||
|
||||
@@ -1521,8 +1521,8 @@ func mod64sPositiveWithIdenticalMax(a, b int64, ensureBothBranchesCouldHappen bo
|
||||
if a < 0 || b < 0 {
|
||||
return 42
|
||||
}
|
||||
a &= 0xfff
|
||||
b &= 0xfff
|
||||
a = min(a, 0xfff)
|
||||
b = min(b, 0xfff)
|
||||
|
||||
z := a % b // ERROR "Proved Mod64 does not need fix-up$"
|
||||
|
||||
@@ -1539,10 +1539,10 @@ func mod64sPositiveWithIdenticalMax(a, b int64, ensureBothBranchesCouldHappen bo
|
||||
}
|
||||
|
||||
func div64u(a, b uint64, ensureAllBranchesCouldHappen func() bool) uint64 {
|
||||
a &= 0xffff
|
||||
a |= 0xfff
|
||||
b &= 0xff
|
||||
b |= 0xf
|
||||
a = min(a, 0xffff)
|
||||
a = max(a, 0xfff)
|
||||
b = min(b, 0xff)
|
||||
b = max(b, 0xf)
|
||||
|
||||
z := a / b // ERROR "Proved Neq64$"
|
||||
|
||||
@@ -1564,10 +1564,10 @@ func div64s(a, b int64, ensureAllBranchesCouldHappen func() bool) int64 {
|
||||
if a < 0 || b < 0 {
|
||||
return 42
|
||||
}
|
||||
a &= 0xffff
|
||||
a |= 0xfff
|
||||
b &= 0xff
|
||||
b |= 0xf
|
||||
a = min(a, 0xffff)
|
||||
a = max(a, 0xfff)
|
||||
b = min(b, 0xff)
|
||||
b = max(b, 0xf)
|
||||
|
||||
z := a / b // ERROR "(Proved Div64 does not need fix-up|Proved Neq64)$"
|
||||
|
||||
@@ -1587,8 +1587,8 @@ func div64s(a, b int64, ensureAllBranchesCouldHappen func() bool) int64 {
|
||||
}
|
||||
|
||||
func trunc64to16(a uint64, ensureAllBranchesCouldHappen func() bool) uint16 {
|
||||
a &= 0xfff
|
||||
a |= 0xff
|
||||
a = min(a, 0xfff)
|
||||
a = max(a, 0xff)
|
||||
|
||||
z := uint16(a)
|
||||
if ensureAllBranchesCouldHappen() && z > 0xfff { // ERROR "Disproved Less16U$"
|
||||
@@ -1607,8 +1607,8 @@ func trunc64to16(a uint64, ensureAllBranchesCouldHappen func() bool) uint16 {
|
||||
}
|
||||
|
||||
func com64(a uint64, ensureAllBranchesCouldHappen func() bool) uint64 {
|
||||
a &= 0xffff
|
||||
a |= 0xff
|
||||
a = min(a, 0xffff)
|
||||
a = max(a, 0xff)
|
||||
|
||||
z := ^a
|
||||
|
||||
@@ -1629,8 +1629,8 @@ func com64(a uint64, ensureAllBranchesCouldHappen func() bool) uint64 {
|
||||
|
||||
func neg64(a uint64, ensureAllBranchesCouldHappen func() bool) uint64 {
|
||||
var lo, hi uint64 = 0xff, 0xfff
|
||||
a &= hi
|
||||
a |= lo
|
||||
a = min(a, hi)
|
||||
a = max(a, lo)
|
||||
|
||||
z := -a
|
||||
|
||||
@@ -1650,8 +1650,8 @@ func neg64(a uint64, ensureAllBranchesCouldHappen func() bool) uint64 {
|
||||
}
|
||||
func neg64mightOverflowDuringNeg(a uint64, ensureAllBranchesCouldHappen func() bool) uint64 {
|
||||
var lo, hi uint64 = 0, 0xfff
|
||||
a &= hi
|
||||
a |= lo
|
||||
a = min(a, hi)
|
||||
a = max(a, lo)
|
||||
|
||||
z := -a
|
||||
|
||||
@@ -1691,6 +1691,317 @@ func phiMin(a, b []byte) {
|
||||
_ = b[:y] // ERROR "Proved IsSliceInBounds"
|
||||
}
|
||||
|
||||
func minPhiLeq[T uint | int](x, y T) (z T) {
|
||||
if x <= y {
|
||||
z = x
|
||||
} else {
|
||||
z = y
|
||||
}
|
||||
return z
|
||||
}
|
||||
func maxPhiLeq[T uint | int](x, y T) (z T) {
|
||||
if y <= x {
|
||||
z = x
|
||||
} else {
|
||||
z = y
|
||||
}
|
||||
return z
|
||||
}
|
||||
func mathBasedOnPhiLosangeMinUFirstLeq(x uint, ensureAllBranchesCouldHappen func() bool) uint {
|
||||
const maxc = 0xf2a
|
||||
const minc = 0xf0a
|
||||
x = minPhiLeq(x, maxc)
|
||||
x = maxPhiLeq(x, minc)
|
||||
|
||||
const k = 1
|
||||
x += k
|
||||
|
||||
if ensureAllBranchesCouldHappen() && x > maxc+k { // ERROR "Disproved Less64U$"
|
||||
return 42
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x <= maxc+k { // ERROR "Proved Leq64U$"
|
||||
return 4242
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x < minc+k { // ERROR "Disproved Less64U$"
|
||||
return 424242
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x >= minc+k { // ERROR "Proved Leq64U$"
|
||||
return 42424242
|
||||
}
|
||||
return x
|
||||
}
|
||||
func mathBasedOnPhiLosangeMinUSecondLeq(x uint, ensureAllBranchesCouldHappen func() bool) uint {
|
||||
const maxc = 0xf2a
|
||||
const minc = 0xf0a
|
||||
x = maxPhiLeq(x, minc)
|
||||
x = minPhiLeq(x, maxc)
|
||||
|
||||
const k = 1
|
||||
x += k
|
||||
|
||||
if ensureAllBranchesCouldHappen() && x > maxc+k { // ERROR "Disproved Less64U$"
|
||||
return 42
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x <= maxc+k { // ERROR "Proved Leq64U$"
|
||||
return 4242
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x < minc+k { // ERROR "Disproved Less64U$"
|
||||
return 424242
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x >= minc+k { // ERROR "Proved Leq64U$"
|
||||
return 42424242
|
||||
}
|
||||
return x
|
||||
}
|
||||
func mathBasedOnPhiLosangeMinFirstLeq(x int, ensureAllBranchesCouldHappen func() bool) int {
|
||||
const maxc = 0xf2a
|
||||
const minc = 0xf0a
|
||||
x = minPhiLeq(x, maxc)
|
||||
x = maxPhiLeq(x, minc)
|
||||
|
||||
const k = 1
|
||||
x += k
|
||||
|
||||
if ensureAllBranchesCouldHappen() && x > maxc+k { // ERROR "Disproved Less64$"
|
||||
return 42
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x <= maxc+k { // ERROR "Proved Leq64$"
|
||||
return 4242
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x < minc+k { // ERROR "Disproved Less64$"
|
||||
return 424242
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x >= minc+k { // ERROR "Proved Leq64$"
|
||||
return 42424242
|
||||
}
|
||||
return x
|
||||
}
|
||||
func mathBasedOnPhiLosangeMinSecondLeq(x int, ensureAllBranchesCouldHappen func() bool) int {
|
||||
const maxc = 0xf2a
|
||||
const minc = 0xf0a
|
||||
x = maxPhiLeq(x, minc)
|
||||
x = minPhiLeq(x, maxc)
|
||||
|
||||
const k = 1
|
||||
x += k
|
||||
|
||||
if ensureAllBranchesCouldHappen() && x > maxc+k { // ERROR "Disproved Less64$"
|
||||
return 42
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x <= maxc+k { // ERROR "Proved Leq64$"
|
||||
return 4242
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x < minc+k { // ERROR "Disproved Less64$"
|
||||
return 424242
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x >= minc+k { // ERROR "Proved Leq64$"
|
||||
return 42424242
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func minPhiLess[T uint | int](x, y T) (z T) {
|
||||
if x < y {
|
||||
z = x
|
||||
} else {
|
||||
z = y
|
||||
}
|
||||
return z
|
||||
}
|
||||
func maxPhiLess[T uint | int](x, y T) (z T) {
|
||||
if y < x {
|
||||
z = x
|
||||
} else {
|
||||
z = y
|
||||
}
|
||||
return z
|
||||
}
|
||||
func mathBasedOnPhiLosangeMinUFirstLess(x uint, ensureAllBranchesCouldHappen func() bool) uint {
|
||||
const maxc = 0xf2a
|
||||
const minc = 0xf0a
|
||||
x = minPhiLess(x, maxc)
|
||||
x = maxPhiLess(x, minc)
|
||||
|
||||
const k = 1
|
||||
x += k
|
||||
|
||||
if ensureAllBranchesCouldHappen() && x > maxc+k { // ERROR "Disproved Less64U$"
|
||||
return 42
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x <= maxc+k { // ERROR "Proved Leq64U$"
|
||||
return 4242
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x < minc+k { // ERROR "Disproved Less64U$"
|
||||
return 424242
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x >= minc+k { // ERROR "Proved Leq64U$"
|
||||
return 42424242
|
||||
}
|
||||
return x
|
||||
}
|
||||
func mathBasedOnPhiLosangeMinUSecondLess(x uint, ensureAllBranchesCouldHappen func() bool) uint {
|
||||
const maxc = 0xf2a
|
||||
const minc = 0xf0a
|
||||
x = maxPhiLess(x, minc)
|
||||
x = minPhiLess(x, maxc)
|
||||
|
||||
const k = 1
|
||||
x += k
|
||||
|
||||
if ensureAllBranchesCouldHappen() && x > maxc+k { // ERROR "Disproved Less64U$"
|
||||
return 42
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x <= maxc+k { // ERROR "Proved Leq64U$"
|
||||
return 4242
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x < minc+k { // ERROR "Disproved Less64U$"
|
||||
return 424242
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x >= minc+k { // ERROR "Proved Leq64U$"
|
||||
return 42424242
|
||||
}
|
||||
return x
|
||||
}
|
||||
func mathBasedOnPhiLosangeMinFirstLess(x int, ensureAllBranchesCouldHappen func() bool) int {
|
||||
const maxc = 0xf2a
|
||||
const minc = 0xf0a
|
||||
x = minPhiLess(x, maxc)
|
||||
x = maxPhiLess(x, minc)
|
||||
|
||||
const k = 1
|
||||
x += k
|
||||
|
||||
if ensureAllBranchesCouldHappen() && x > maxc+k { // ERROR "Disproved Less64$"
|
||||
return 42
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x <= maxc+k { // ERROR "Proved Leq64$"
|
||||
return 4242
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x < minc+k { // ERROR "Disproved Less64$"
|
||||
return 424242
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x >= minc+k { // ERROR "Proved Leq64$"
|
||||
return 42424242
|
||||
}
|
||||
return x
|
||||
}
|
||||
func mathBasedOnPhiLosangeMinSecondLess(x int, ensureAllBranchesCouldHappen func() bool) int {
|
||||
const maxc = 0xf2a
|
||||
const minc = 0xf0a
|
||||
x = maxPhiLess(x, minc)
|
||||
x = minPhiLess(x, maxc)
|
||||
|
||||
const k = 1
|
||||
x += k
|
||||
|
||||
if ensureAllBranchesCouldHappen() && x > maxc+k { // ERROR "Disproved Less64$"
|
||||
return 42
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x <= maxc+k { // ERROR "Proved Leq64$"
|
||||
return 4242
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x < minc+k { // ERROR "Disproved Less64$"
|
||||
return 424242
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x >= minc+k { // ERROR "Proved Leq64$"
|
||||
return 42424242
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func mathBasedOnPhiBuiltinMinUFirst(x uint, ensureAllBranchesCouldHappen func() bool) uint {
|
||||
const maxc = 0xf2a
|
||||
const minc = 0xf0a
|
||||
x = min(x, maxc)
|
||||
x = max(x, minc)
|
||||
|
||||
const k = 1
|
||||
x += k
|
||||
|
||||
if ensureAllBranchesCouldHappen() && x > maxc+k { // ERROR "Disproved Less64U$"
|
||||
return 42
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x <= maxc+k { // ERROR "Proved Leq64U$"
|
||||
return 4242
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x < minc+k { // ERROR "Disproved Less64U$"
|
||||
return 424242
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x >= minc+k { // ERROR "Proved Leq64U$"
|
||||
return 42424242
|
||||
}
|
||||
return x
|
||||
}
|
||||
func mathBasedOnPhiBuiltinMinUSecond(x uint, ensureAllBranchesCouldHappen func() bool) uint {
|
||||
const maxc = 0xf2a
|
||||
const minc = 0xf0a
|
||||
x = max(x, minc)
|
||||
x = min(x, maxc)
|
||||
|
||||
const k = 1
|
||||
x += k
|
||||
|
||||
if ensureAllBranchesCouldHappen() && x > maxc+k { // ERROR "Disproved Less64U$"
|
||||
return 42
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x <= maxc+k { // ERROR "Proved Leq64U$"
|
||||
return 4242
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x < minc+k { // ERROR "Disproved Less64U$"
|
||||
return 424242
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x >= minc+k { // ERROR "Proved Leq64U$"
|
||||
return 42424242
|
||||
}
|
||||
return x
|
||||
}
|
||||
func mathBasedOnPhiBuiltinMinFirst(x int, ensureAllBranchesCouldHappen func() bool) int {
|
||||
const maxc = 0xf2a
|
||||
const minc = 0xf0a
|
||||
x = min(x, maxc)
|
||||
x = max(x, minc)
|
||||
|
||||
const k = 1
|
||||
x += k
|
||||
|
||||
if ensureAllBranchesCouldHappen() && x > maxc+k { // ERROR "Disproved Less64$"
|
||||
return 42
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x <= maxc+k { // ERROR "Proved Leq64$"
|
||||
return 4242
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x < minc+k { // ERROR "Disproved Less64$"
|
||||
return 424242
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x >= minc+k { // ERROR "Proved Leq64$"
|
||||
return 42424242
|
||||
}
|
||||
return x
|
||||
}
|
||||
func mathBasedOnPhiBuiltinMinSecond(x int, ensureAllBranchesCouldHappen func() bool) int {
|
||||
const maxc = 0xf2a
|
||||
const minc = 0xf0a
|
||||
x = max(x, minc)
|
||||
x = min(x, maxc)
|
||||
|
||||
const k = 1
|
||||
x += k
|
||||
|
||||
if ensureAllBranchesCouldHappen() && x > maxc+k { // ERROR "Disproved Less64$"
|
||||
return 42
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x <= maxc+k { // ERROR "Proved Leq64$"
|
||||
return 4242
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x < minc+k { // ERROR "Disproved Less64$"
|
||||
return 424242
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && x >= minc+k { // ERROR "Proved Leq64$"
|
||||
return 42424242
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func issue16833(a, b []byte) {
|
||||
n := copy(a, b)
|
||||
_ = a[n:] // ERROR "Proved IsSliceInBounds"
|
||||
@@ -1712,6 +2023,24 @@ func clampedIdx2(x []int, i int) int {
|
||||
return x[max(min(i, len(x)-1), 0)] // TODO: can't get rid of this bounds check yet
|
||||
}
|
||||
|
||||
func cvtBoolToUint8Disprove(b bool) byte {
|
||||
var c byte
|
||||
if b {
|
||||
c = 1
|
||||
}
|
||||
if c == 2 { // ERROR "Disproved Eq8"
|
||||
c = 3
|
||||
}
|
||||
return c
|
||||
}
|
||||
func cvtBoolToUint8BCE(b bool, a [2]int64) int64 {
|
||||
c := byte(0)
|
||||
if b {
|
||||
c = 1
|
||||
}
|
||||
return a[c] // ERROR "Proved IsInBounds$"
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func useInt(a int) {
|
||||
}
|
||||
|
||||
60
test/prove_popcount.go
Normal file
60
test/prove_popcount.go
Normal file
@@ -0,0 +1,60 @@
|
||||
// errorcheck -0 -d=ssa/prove/debug=1
|
||||
|
||||
//go:build amd64.v3 || arm64
|
||||
|
||||
// Copyright 2025 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.
|
||||
|
||||
// FIXME(@Jorropo): this file exists because I havn't yet bothered to
|
||||
// make prove work on the pure go function call fallback.
|
||||
// My idea was to wait until CL 637936 is merged, then we can always emit
|
||||
// the PopCount SSA operation and translate them to pure function calls
|
||||
// in late-opt.
|
||||
|
||||
package main
|
||||
|
||||
import "math/bits"
|
||||
|
||||
func onesCountsBounds(x uint64, ensureAllBranchesCouldHappen func() bool) int {
|
||||
z := bits.OnesCount64(x)
|
||||
if ensureAllBranchesCouldHappen() && z > 64 { // ERROR "Disproved Less64$"
|
||||
return 42
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && z <= 64 { // ERROR "Proved Leq64$"
|
||||
return 4242
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && z < 0 { // ERROR "Disproved Less64$"
|
||||
return 424242
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && z >= 0 { // ERROR "Proved Leq64$"
|
||||
return 42424242
|
||||
}
|
||||
return z
|
||||
}
|
||||
|
||||
func onesCountsTight(x uint64, ensureAllBranchesCouldHappen func() bool) int {
|
||||
const maxv = 0xff0f
|
||||
const minv = 0xff00
|
||||
x = max(x, minv)
|
||||
x = min(x, maxv)
|
||||
|
||||
z := bits.OnesCount64(x)
|
||||
|
||||
if ensureAllBranchesCouldHappen() && z > bits.OnesCount64(maxv) { // ERROR "Disproved Less64$"
|
||||
return 42
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && z <= bits.OnesCount64(maxv) { // ERROR "Proved Leq64$"
|
||||
return 4242
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && z < bits.OnesCount64(minv) { // ERROR "Disproved Less64$"
|
||||
return 424242
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && z >= bits.OnesCount64(minv) { // ERROR "Proved Leq64$"
|
||||
return 42424242
|
||||
}
|
||||
return z
|
||||
}
|
||||
|
||||
func main() {
|
||||
}
|
||||
@@ -9,14 +9,20 @@
|
||||
package main
|
||||
|
||||
var (
|
||||
e any
|
||||
ts uint16
|
||||
ga, gb, gc, gd int
|
||||
)
|
||||
|
||||
func moveValuesWithMemoryArg(len int) {
|
||||
for n := 0; n < len; n++ {
|
||||
// Load of e.data is lowed as a MOVDload op, which has a memory
|
||||
// argument. It's moved near where it's used.
|
||||
_ = e != ts // ERROR "MOVDload is moved$" "MOVDaddr is moved$"
|
||||
// Loads of b and d can be delayed until inside the outer "if".
|
||||
a := ga
|
||||
b := gb // ERROR "MOVDload is moved$"
|
||||
c := gc
|
||||
d := gd // ERROR "MOVDload is moved$"
|
||||
if a == c {
|
||||
if b == d {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user