Update to go1.24.0
This commit is contained in:
@@ -46,8 +46,8 @@ var _ A0 = T0{}
|
||||
var _ T0 = A0{}
|
||||
|
||||
// But aliases and original types cannot be used with new types based on them.
|
||||
var _ N0 = T0{} // ERROR "cannot use T0{} \(value of type T0\) as N0 value in variable declaration"
|
||||
var _ N0 = A0{} // ERROR "cannot use A0{} \(value of type A0\) as N0 value in variable declaration"
|
||||
var _ N0 = T0{} // ERROR "cannot use T0{} \(value of struct type T0\) as N0 value in variable declaration"
|
||||
var _ N0 = A0{} // ERROR "cannot use A0{} \(value of struct type A0\) as N0 value in variable declaration"
|
||||
|
||||
var _ A5 = Value{}
|
||||
|
||||
@@ -82,10 +82,10 @@ func _() {
|
||||
var _ A0 = T0{}
|
||||
var _ T0 = A0{}
|
||||
|
||||
var _ N0 = T0{} // ERROR "cannot use T0{} \(value of type T0\) as N0 value in variable declaration"
|
||||
var _ N0 = A0{} // ERROR "cannot use A0{} \(value of type A0\) as N0 value in variable declaration"
|
||||
var _ N0 = T0{} // ERROR "cannot use T0{} \(value of struct type T0\) as N0 value in variable declaration"
|
||||
var _ N0 = A0{} // ERROR "cannot use A0{} \(value of struct type A0\) as N0 value in variable declaration"
|
||||
|
||||
var _ A5 = Value{} // ERROR "cannot use Value{} \(value of type reflect\.Value\) as A5 value in variable declaration"
|
||||
var _ A5 = Value{} // ERROR "cannot use Value{} \(value of struct type reflect\.Value\) as A5 value in variable declaration"
|
||||
}
|
||||
|
||||
// Invalid type alias declarations.
|
||||
|
||||
@@ -9,7 +9,10 @@
|
||||
|
||||
package main
|
||||
|
||||
import "sync"
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type T struct {
|
||||
int
|
||||
@@ -38,7 +41,7 @@ func main() {
|
||||
_ = x
|
||||
}
|
||||
{
|
||||
x := sync.Mutex{0, 0} // ERROR "assignment.*Mutex"
|
||||
x := time.Time{0, 0, nil} // ERROR "assignment.*Time"
|
||||
_ = x
|
||||
}
|
||||
{
|
||||
|
||||
@@ -159,16 +159,14 @@ func decode1(data []byte) (x uint64) {
|
||||
}
|
||||
|
||||
func decode2(data []byte) (x uint64) {
|
||||
// TODO(rasky): this should behave like decode1 and compile to no
|
||||
// boundchecks. We're currently not able to remove all of them.
|
||||
for len(data) >= 32 {
|
||||
x += binary.BigEndian.Uint64(data)
|
||||
data = data[8:]
|
||||
x += binary.BigEndian.Uint64(data) // ERROR "Found IsInBounds$"
|
||||
x += binary.BigEndian.Uint64(data)
|
||||
data = data[8:]
|
||||
x += binary.BigEndian.Uint64(data) // ERROR "Found IsInBounds$"
|
||||
x += binary.BigEndian.Uint64(data)
|
||||
data = data[8:]
|
||||
x += binary.BigEndian.Uint64(data) // ERROR "Found IsInBounds$"
|
||||
x += binary.BigEndian.Uint64(data)
|
||||
data = data[8:]
|
||||
}
|
||||
return x
|
||||
|
||||
@@ -20,6 +20,7 @@ func main() {
|
||||
if x := func() int { // ERROR "can inline main.func2" "func literal does not escape"
|
||||
return 1
|
||||
}; x() != 1 { // ERROR "inlining call to main.func2"
|
||||
_ = x // prevent simple deadcode elimination after inlining
|
||||
ppanic("x() != 1")
|
||||
}
|
||||
}
|
||||
@@ -33,6 +34,7 @@ func main() {
|
||||
if y := func(x int) int { // ERROR "can inline main.func4" "func literal does not escape"
|
||||
return x + 2
|
||||
}; y(40) != 42 { // ERROR "inlining call to main.func4"
|
||||
_ = y // prevent simple deadcode elimination after inlining
|
||||
ppanic("y(40) != 42")
|
||||
}
|
||||
}
|
||||
@@ -50,7 +52,7 @@ func main() {
|
||||
}
|
||||
|
||||
{
|
||||
func() { // ERROR "func literal does not escape"
|
||||
func() { // ERROR "can inline main.func7"
|
||||
y := func(x int) int { // ERROR "can inline main.func7.1" "func literal does not escape"
|
||||
return x + 2
|
||||
}
|
||||
@@ -60,7 +62,7 @@ func main() {
|
||||
if y(40) != 41 {
|
||||
ppanic("y(40) != 41")
|
||||
}
|
||||
}()
|
||||
}() // ERROR "func literal does not escape" "inlining call to main.func7"
|
||||
}
|
||||
|
||||
{
|
||||
@@ -76,7 +78,7 @@ func main() {
|
||||
}
|
||||
|
||||
{
|
||||
func() { // ERROR "func literal does not escape"
|
||||
func() { // ERROR "can inline main.func10"
|
||||
y := func(x int) int { // ERROR "can inline main.func10.1" "func literal does not escape"
|
||||
return x + 2
|
||||
}
|
||||
@@ -86,7 +88,7 @@ func main() {
|
||||
if y(40) != 41 {
|
||||
ppanic("y(40) != 41")
|
||||
}
|
||||
}()
|
||||
}() // ERROR "func literal does not escape" "inlining call to main.func10"
|
||||
}
|
||||
|
||||
{
|
||||
@@ -94,7 +96,7 @@ func main() {
|
||||
return x + 2
|
||||
}
|
||||
y, sink = func() (func(int) int, int) { // ERROR "can inline main.func12"
|
||||
return func(x int) int { // ERROR "can inline main.func12"
|
||||
return func(x int) int { // ERROR "can inline main.func12" "func literal escapes to heap"
|
||||
return x + 1
|
||||
}, 42
|
||||
}() // ERROR "func literal does not escape" "inlining call to main.func12"
|
||||
@@ -104,19 +106,19 @@ func main() {
|
||||
}
|
||||
|
||||
{
|
||||
func() { // ERROR "func literal does not escape"
|
||||
func() { // ERROR "can inline main.func13"
|
||||
y := func(x int) int { // ERROR "func literal does not escape" "can inline main.func13.1"
|
||||
return x + 2
|
||||
}
|
||||
y, sink = func() (func(int) int, int) { // ERROR "can inline main.func13.2"
|
||||
return func(x int) int { // ERROR "can inline main.func13.2"
|
||||
y, sink = func() (func(int) int, int) { // ERROR "can inline main.func13.2" "can inline main.main.func13.func35"
|
||||
return func(x int) int { // ERROR "can inline main.func13.2" "func literal escapes to heap"
|
||||
return x + 1
|
||||
}, 42
|
||||
}() // ERROR "func literal does not escape" "inlining call to main.func13.2"
|
||||
if y(40) != 41 {
|
||||
ppanic("y(40) != 41")
|
||||
}
|
||||
}()
|
||||
}() // ERROR "func literal does not escape" "inlining call to main.func13" "inlining call to main.main.func13.func35"
|
||||
}
|
||||
|
||||
{
|
||||
@@ -132,7 +134,7 @@ func main() {
|
||||
}
|
||||
|
||||
{
|
||||
func() { // ERROR "func literal does not escape"
|
||||
func() { // ERROR "can inline main.func16"
|
||||
y := func(x int) int { // ERROR "can inline main.func16.1" "func literal does not escape"
|
||||
return x + 2
|
||||
}
|
||||
@@ -142,7 +144,7 @@ func main() {
|
||||
if y(40) != 41 {
|
||||
ppanic("y(40) != 41")
|
||||
}
|
||||
}()
|
||||
}() // ERROR "func literal does not escape" "inlining call to main.func16" "map\[int\]func\(int\) int{...} does not escape" "func literal escapes to heap"
|
||||
}
|
||||
|
||||
{
|
||||
@@ -158,7 +160,7 @@ func main() {
|
||||
}
|
||||
|
||||
{
|
||||
func() { // ERROR "func literal does not escape"
|
||||
func() { // ERROR "can inline main.func19"
|
||||
y := func(x int) int { // ERROR "can inline main.func19.1" "func literal does not escape"
|
||||
return x + 2
|
||||
}
|
||||
@@ -168,7 +170,7 @@ func main() {
|
||||
if y(40) != 41 {
|
||||
ppanic("y(40) != 41")
|
||||
}
|
||||
}()
|
||||
}() // ERROR "func literal does not escape" "inlining call to main.func19"
|
||||
}
|
||||
|
||||
{
|
||||
@@ -181,6 +183,7 @@ func main() {
|
||||
if y := func() int { // ERROR "can inline main.func21" "func literal does not escape"
|
||||
return x
|
||||
}; y() != 42 { // ERROR "inlining call to main.func21"
|
||||
_ = y // prevent simple deadcode elimination after inlining
|
||||
ppanic("y() != 42")
|
||||
}
|
||||
}
|
||||
@@ -188,17 +191,18 @@ func main() {
|
||||
{
|
||||
x := 42
|
||||
if z := func(y int) int { // ERROR "can inline main.func22"
|
||||
return func() int { // ERROR "can inline main.func22.1" "can inline main.main.func22.func30"
|
||||
return func() int { // ERROR "can inline main.func22.1" "can inline main.main.func22.func40"
|
||||
return x + y
|
||||
}() // ERROR "inlining call to main.func22.1"
|
||||
}(1); z != 43 { // ERROR "inlining call to main.func22" "inlining call to main.main.func22.func30"
|
||||
}(1); z != 43 { // ERROR "inlining call to main.func22" "inlining call to main.main.func22.func40"
|
||||
ppanic("z != 43")
|
||||
}
|
||||
if z := func(y int) int { // ERROR "func literal does not escape" "can inline main.func23"
|
||||
return func() int { // ERROR "can inline main.func23.1" "can inline main.main.func23.func31"
|
||||
return func() int { // ERROR "can inline main.func23.1" "can inline main.main.func23.func41"
|
||||
return x + y
|
||||
}() // ERROR "inlining call to main.func23.1"
|
||||
}; z(1) != 43 { // ERROR "inlining call to main.func23" "inlining call to main.main.func23.func31"
|
||||
}; z(1) != 43 { // ERROR "inlining call to main.func23" "inlining call to main.main.func23.func41"
|
||||
_ = z // prevent simple deadcode elimination after inlining
|
||||
ppanic("z(1) != 43")
|
||||
}
|
||||
}
|
||||
@@ -206,10 +210,10 @@ func main() {
|
||||
{
|
||||
a := 1
|
||||
func() { // ERROR "can inline main.func24"
|
||||
func() { // ERROR "can inline main.func24" "can inline main.main.func24.func32"
|
||||
func() { // ERROR "can inline main.func24" "can inline main.main.func24.func42"
|
||||
a = 2
|
||||
}() // ERROR "inlining call to main.func24"
|
||||
}() // ERROR "inlining call to main.func24" "inlining call to main.main.func24.func32"
|
||||
}() // ERROR "inlining call to main.func24" "inlining call to main.main.func24.func42"
|
||||
if a != 2 {
|
||||
ppanic("a != 2")
|
||||
}
|
||||
@@ -217,14 +221,14 @@ func main() {
|
||||
|
||||
{
|
||||
b := 2
|
||||
func(b int) { // ERROR "func literal does not escape"
|
||||
func() { // ERROR "can inline main.func25.1"
|
||||
func(b int) { // ERROR "can inline main.func25"
|
||||
func() { // ERROR "can inline main.func25.1" "can inline main.main.func25.func43"
|
||||
b = 3
|
||||
}() // ERROR "inlining call to main.func25.1"
|
||||
if b != 3 {
|
||||
ppanic("b != 3")
|
||||
}
|
||||
}(b)
|
||||
}(b) // ERROR "inlining call to main.func25" "inlining call to main.main.func25.func43"
|
||||
if b != 2 {
|
||||
ppanic("b != 2")
|
||||
}
|
||||
@@ -254,13 +258,13 @@ func main() {
|
||||
// revisit those. E.g., func34 and func36 are constructed by the inliner.
|
||||
if r := func(x int) int { // ERROR "can inline main.func27"
|
||||
b := 3
|
||||
return func(y int) int { // ERROR "can inline main.func27.1" "can inline main.main.func27.func34"
|
||||
return func(y int) int { // ERROR "can inline main.func27.1" "can inline main.main.func27.func45"
|
||||
c := 5
|
||||
return func(z int) int { // ERROR "can inline main.func27.1.1" "can inline main.main.func27.func34.1" "can inline main.func27.main.func27.1.2" "can inline main.main.func27.main.main.func27.func34.func36"
|
||||
return func(z int) int { // ERROR "can inline main.func27.1.1" "can inline main.main.func27.func45.1" "can inline main.func27.main.func27.1.2" "can inline main.main.func27.main.main.func27.func45.func48"
|
||||
return a*x + b*y + c*z
|
||||
}(10) // ERROR "inlining call to main.func27.1.1"
|
||||
}(100) // ERROR "inlining call to main.func27.1" "inlining call to main.func27.main.func27.1.2"
|
||||
}(1000); r != 2350 { // ERROR "inlining call to main.func27" "inlining call to main.main.func27.func34" "inlining call to main.main.func27.main.main.func27.func34.func36"
|
||||
}(1000); r != 2350 { // ERROR "inlining call to main.func27" "inlining call to main.main.func27.func45" "inlining call to main.main.func27.main.main.func27.func45.func48"
|
||||
ppanic("r != 2350")
|
||||
}
|
||||
}
|
||||
@@ -269,16 +273,16 @@ func main() {
|
||||
a := 2
|
||||
if r := func(x int) int { // ERROR "can inline main.func28"
|
||||
b := 3
|
||||
return func(y int) int { // ERROR "can inline main.func28.1" "can inline main.main.func28.func35"
|
||||
return func(y int) int { // ERROR "can inline main.func28.1" "can inline main.main.func28.func46"
|
||||
c := 5
|
||||
func(z int) { // ERROR "can inline main.func28.1.1" "can inline main.func28.main.func28.1.2" "can inline main.main.func28.func35.1" "can inline main.main.func28.main.main.func28.func35.func37"
|
||||
func(z int) { // ERROR "can inline main.func28.1.1" "can inline main.func28.main.func28.1.2" "can inline main.main.func28.func46.1" "can inline main.main.func28.main.main.func28.func46.func49"
|
||||
a = a * x
|
||||
b = b * y
|
||||
c = c * z
|
||||
}(10) // ERROR "inlining call to main.func28.1.1"
|
||||
return a + c
|
||||
}(100) + b // ERROR "inlining call to main.func28.1" "inlining call to main.func28.main.func28.1.2"
|
||||
}(1000); r != 2350 { // ERROR "inlining call to main.func28" "inlining call to main.main.func28.func35" "inlining call to main.main.func28.main.main.func28.func35.func37"
|
||||
}(1000); r != 2350 { // ERROR "inlining call to main.func28" "inlining call to main.main.func28.func46" "inlining call to main.main.func28.main.main.func28.func46.func49"
|
||||
ppanic("r != 2350")
|
||||
}
|
||||
if a != 2000 {
|
||||
@@ -287,6 +291,25 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func notmain() {
|
||||
{
|
||||
// This duplicates the first block in main, but without the "_ = x" for closure x.
|
||||
// This allows dead code elimination of x before escape analysis,
|
||||
// thus "func literal does not escape" should not appear.
|
||||
if x := func() int { // ERROR "can inline notmain.func1"
|
||||
return 1
|
||||
}(); x != 1 { // ERROR "inlining call to notmain.func1"
|
||||
ppanic("x != 1")
|
||||
}
|
||||
if x := func() int { // ERROR "can inline notmain.func2"
|
||||
return 1
|
||||
}; x() != 1 { // ERROR "inlining call to notmain.func2"
|
||||
ppanic("x() != 1")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func ppanic(s string) { // ERROR "leaking param: s"
|
||||
panic(s) // ERROR "s escapes to heap"
|
||||
|
||||
@@ -629,3 +629,39 @@ func constantFold3(i, j int) int {
|
||||
r := (5 * i) * (6 * j)
|
||||
return r
|
||||
}
|
||||
|
||||
// ----------------- //
|
||||
// Integer Min/Max //
|
||||
// ----------------- //
|
||||
|
||||
func Int64Min(a, b int64) int64 {
|
||||
// amd64: "CMPQ","CMOVQLT"
|
||||
// arm64: "CMP","CSEL"
|
||||
// riscv64/rva20u64:"BLT\t"
|
||||
// riscv64/rva22u64:"MIN\t"
|
||||
return min(a, b)
|
||||
}
|
||||
|
||||
func Int64Max(a, b int64) int64 {
|
||||
// amd64: "CMPQ","CMOVQGT"
|
||||
// arm64: "CMP","CSEL"
|
||||
// riscv64/rva20u64:"BLT\t"
|
||||
// riscv64/rva22u64:"MAX\t"
|
||||
return max(a, b)
|
||||
}
|
||||
|
||||
func Uint64Min(a, b uint64) uint64 {
|
||||
// amd64: "CMPQ","CMOVQCS"
|
||||
// arm64: "CMP","CSEL"
|
||||
// riscv64/rva20u64:"BLTU"
|
||||
// riscv64/rva22u64:"MINU"
|
||||
return min(a, b)
|
||||
}
|
||||
|
||||
func Uint64Max(a, b uint64) uint64 {
|
||||
// amd64: "CMPQ","CMOVQHI"
|
||||
// arm64: "CMP","CSEL"
|
||||
// riscv64/rva20u64:"BLTU"
|
||||
// riscv64/rva22u64:"MAXU"
|
||||
return max(a, b)
|
||||
}
|
||||
|
||||
@@ -22,6 +22,74 @@ func (c *Counter) Increment() {
|
||||
// arm64/v8.1:"LDADDALW"
|
||||
// arm64/v8.0:".*arm64HasATOMICS"
|
||||
// arm64/v8.1:-".*arm64HasATOMICS"
|
||||
// amd64:"LOCK",-"CMPXCHG"
|
||||
atomic.AddInt32(&c.count, 1)
|
||||
}
|
||||
|
||||
func atomicLogical64(x *atomic.Uint64) uint64 {
|
||||
var r uint64
|
||||
|
||||
// arm64/v8.0:"LDCLRALD"
|
||||
// arm64/v8.1:"LDCLRALD"
|
||||
// arm64/v8.0:".*arm64HasATOMICS"
|
||||
// arm64/v8.1:-".*arm64HasATOMICS"
|
||||
// On amd64, make sure we use LOCK+AND instead of CMPXCHG when we don't use the result.
|
||||
// amd64:"LOCK",-"CMPXCHGQ"
|
||||
x.And(11)
|
||||
// arm64/v8.0:"LDCLRALD"
|
||||
// arm64/v8.1:"LDCLRALD"
|
||||
// arm64/v8.0:".*arm64HasATOMICS"
|
||||
// arm64/v8.1:-".*arm64HasATOMICS"
|
||||
// amd64:"LOCK","CMPXCHGQ"
|
||||
r += x.And(22)
|
||||
|
||||
// arm64/v8.0:"LDORALD"
|
||||
// arm64/v8.1:"LDORALD"
|
||||
// arm64/v8.0:".*arm64HasATOMICS"
|
||||
// arm64/v8.1:-".*arm64HasATOMICS"
|
||||
// On amd64, make sure we use LOCK+OR instead of CMPXCHG when we don't use the result.
|
||||
// amd64:"LOCK",-"CMPXCHGQ"
|
||||
x.Or(33)
|
||||
// arm64/v8.0:"LDORALD"
|
||||
// arm64/v8.1:"LDORALD"
|
||||
// arm64/v8.0:".*arm64HasATOMICS"
|
||||
// arm64/v8.1:-".*arm64HasATOMICS"
|
||||
// amd64:"LOCK","CMPXCHGQ"
|
||||
r += x.Or(44)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func atomicLogical32(x *atomic.Uint32) uint32 {
|
||||
var r uint32
|
||||
|
||||
// arm64/v8.0:"LDCLRALW"
|
||||
// arm64/v8.1:"LDCLRALW"
|
||||
// arm64/v8.0:".*arm64HasATOMICS"
|
||||
// arm64/v8.1:-".*arm64HasATOMICS"
|
||||
// On amd64, make sure we use LOCK+AND instead of CMPXCHG when we don't use the result.
|
||||
// amd64:"LOCK",-"CMPXCHGL"
|
||||
x.And(11)
|
||||
// arm64/v8.0:"LDCLRALW"
|
||||
// arm64/v8.1:"LDCLRALW"
|
||||
// arm64/v8.0:".*arm64HasATOMICS"
|
||||
// arm64/v8.1:-".*arm64HasATOMICS"
|
||||
// amd64:"LOCK","CMPXCHGL"
|
||||
r += x.And(22)
|
||||
|
||||
// arm64/v8.0:"LDORALW"
|
||||
// arm64/v8.1:"LDORALW"
|
||||
// arm64/v8.0:".*arm64HasATOMICS"
|
||||
// arm64/v8.1:-".*arm64HasATOMICS"
|
||||
// On amd64, make sure we use LOCK+OR instead of CMPXCHG when we don't use the result.
|
||||
// amd64:"LOCK",-"CMPXCHGL"
|
||||
x.Or(33)
|
||||
// arm64/v8.0:"LDORALW"
|
||||
// arm64/v8.1:"LDORALW"
|
||||
// arm64/v8.0:".*arm64HasATOMICS"
|
||||
// arm64/v8.1:-".*arm64HasATOMICS"
|
||||
// amd64:"LOCK","CMPXCHGL"
|
||||
r += x.Or(44)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
@@ -358,11 +358,15 @@ func rev16w(c uint32) (uint32, uint32, uint32) {
|
||||
|
||||
func shift(x uint32, y uint16, z uint8) uint64 {
|
||||
// arm64:-`MOVWU`,-`LSR\t[$]32`
|
||||
// loong64:-`MOVWU`,-`SRLV\t[$]32`
|
||||
a := uint64(x) >> 32
|
||||
// arm64:-`MOVHU
|
||||
// loong64:-`MOVHU`,-`SRLV\t[$]16`
|
||||
b := uint64(y) >> 16
|
||||
// arm64:-`MOVBU`
|
||||
// loong64:-`MOVBU`,-`SRLV\t[$]8`
|
||||
c := uint64(z) >> 8
|
||||
// arm64:`MOVD\tZR`,-`ADD\tR[0-9]+>>16`,-`ADD\tR[0-9]+>>8`,
|
||||
// loong64:`MOVV\t[$]0`,-`ADDVU`
|
||||
return a + b + c
|
||||
}
|
||||
|
||||
@@ -366,6 +366,7 @@ func issue48467(x, y uint64) uint64 {
|
||||
|
||||
func foldConst(x, y uint64) uint64 {
|
||||
// arm64: "ADDS\t[$]7",-"MOVD\t[$]7"
|
||||
// ppc64x: "ADDC\t[$]7,"
|
||||
d, b := bits.Add64(x, 7, 0)
|
||||
return b & d
|
||||
}
|
||||
|
||||
@@ -217,53 +217,53 @@ func TestSetInvGeFp64(x float64, y float64) bool {
|
||||
}
|
||||
func TestLogicalCompareZero(x *[64]uint64) {
|
||||
// ppc64x:"ANDCC",^"AND"
|
||||
b := x[0]&3
|
||||
if b!=0 {
|
||||
b := x[0] & 3
|
||||
if b != 0 {
|
||||
x[0] = b
|
||||
}
|
||||
// ppc64x:"ANDCC",^"AND"
|
||||
b = x[1]&x[2]
|
||||
if b!=0 {
|
||||
b = x[1] & x[2]
|
||||
if b != 0 {
|
||||
x[1] = b
|
||||
}
|
||||
// ppc64x:"ANDNCC",^"ANDN"
|
||||
b = x[1]&^x[2]
|
||||
if b!=0 {
|
||||
b = x[1] &^ x[2]
|
||||
if b != 0 {
|
||||
x[1] = b
|
||||
}
|
||||
// ppc64x:"ORCC",^"OR"
|
||||
b = x[3]|x[4]
|
||||
if b!=0 {
|
||||
b = x[3] | x[4]
|
||||
if b != 0 {
|
||||
x[3] = b
|
||||
}
|
||||
// ppc64x:"SUBCC",^"SUB"
|
||||
b = x[5]-x[6]
|
||||
if b!=0 {
|
||||
b = x[5] - x[6]
|
||||
if b != 0 {
|
||||
x[5] = b
|
||||
}
|
||||
// ppc64x:"NORCC",^"NOR"
|
||||
b = ^(x[5]|x[6])
|
||||
if b!=0 {
|
||||
b = ^(x[5] | x[6])
|
||||
if b != 0 {
|
||||
x[5] = b
|
||||
}
|
||||
// ppc64x:"XORCC",^"XOR"
|
||||
b = x[7]^x[8]
|
||||
if b!=0 {
|
||||
b = x[7] ^ x[8]
|
||||
if b != 0 {
|
||||
x[7] = b
|
||||
}
|
||||
// ppc64x:"ADDCC",^"ADD"
|
||||
b = x[9]+x[10]
|
||||
if b!=0 {
|
||||
b = x[9] + x[10]
|
||||
if b != 0 {
|
||||
x[9] = b
|
||||
}
|
||||
// ppc64x:"NEGCC",^"NEG"
|
||||
b = -x[11]
|
||||
if b!=0 {
|
||||
if b != 0 {
|
||||
x[11] = b
|
||||
}
|
||||
// ppc64x:"CNTLZDCC",^"CNTLZD"
|
||||
b = uint64(bits.LeadingZeros64(x[12]))
|
||||
if b!=0 {
|
||||
if b != 0 {
|
||||
x[12] = b
|
||||
}
|
||||
|
||||
@@ -273,4 +273,17 @@ func TestLogicalCompareZero(x *[64]uint64) {
|
||||
x[12] = uint64(c)
|
||||
}
|
||||
|
||||
// ppc64x:"MULHDUCC",^"MULHDU"
|
||||
hi, _ := bits.Mul64(x[13], x[14])
|
||||
if hi != 0 {
|
||||
x[14] = hi
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func constantWrite(b bool, p *bool) {
|
||||
if b {
|
||||
// amd64:`MOVB\t[$]1, \(`
|
||||
*p = b
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,9 +233,9 @@ func CmpToZero(a, b, d int32, e, f int64, deOptC0, deOptC1 bool) int32 {
|
||||
// arm:`AND`,-`TST`
|
||||
// 386:`ANDL`
|
||||
c6 := a&d >= 0
|
||||
// arm64:`TST\sR[0-9]+<<3,\sR[0-9]+`
|
||||
// For arm64, could be TST+BGE or AND+TBZ
|
||||
c7 := e&(f<<3) < 0
|
||||
// arm64:`CMN\sR[0-9]+<<3,\sR[0-9]+`
|
||||
// For arm64, could be CMN+BPL or ADD+TBZ
|
||||
c8 := e+(f<<3) < 0
|
||||
// arm64:`TST\sR[0-9],\sR[0-9]+`
|
||||
c9 := e&(-19) < 0
|
||||
@@ -268,7 +268,7 @@ func CmpToZero(a, b, d int32, e, f int64, deOptC0, deOptC1 bool) int32 {
|
||||
}
|
||||
}
|
||||
|
||||
func CmpLogicalToZero(a, b, c uint32, d, e uint64) uint64 {
|
||||
func CmpLogicalToZero(a, b, c uint32, d, e, f, g uint64) uint64 {
|
||||
|
||||
// ppc64x:"ANDCC",-"CMPW"
|
||||
// wasm:"I64Eqz",-"I32Eqz",-"I64ExtendI32U",-"I32WrapI64"
|
||||
@@ -289,7 +289,7 @@ func CmpLogicalToZero(a, b, c uint32, d, e uint64) uint64 {
|
||||
}
|
||||
// ppc64x:"ORCC",-"CMP"
|
||||
// wasm:"I64Eqz",-"I32Eqz",-"I64ExtendI32U",-"I32WrapI64"
|
||||
if d|e == 0 {
|
||||
if f|g == 0 {
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
@@ -95,6 +95,7 @@ func moveArchLowering1(b []byte, x *[1]byte) {
|
||||
_ = b[1]
|
||||
// amd64:-".*memmove"
|
||||
// arm64:-".*memmove"
|
||||
// loong64:-".*memmove"
|
||||
// ppc64x:-".*memmove"
|
||||
copy(b, x[:])
|
||||
}
|
||||
@@ -103,6 +104,7 @@ func moveArchLowering2(b []byte, x *[2]byte) {
|
||||
_ = b[2]
|
||||
// amd64:-".*memmove"
|
||||
// arm64:-".*memmove"
|
||||
// loong64:-".*memmove"
|
||||
// ppc64x:-".*memmove"
|
||||
copy(b, x[:])
|
||||
}
|
||||
@@ -111,6 +113,7 @@ func moveArchLowering4(b []byte, x *[4]byte) {
|
||||
_ = b[4]
|
||||
// amd64:-".*memmove"
|
||||
// arm64:-".*memmove"
|
||||
// loong64:-".*memmove"
|
||||
// ppc64x:-".*memmove"
|
||||
copy(b, x[:])
|
||||
}
|
||||
|
||||
@@ -54,11 +54,13 @@ func DivPow2(f1, f2, f3 float64) (float64, float64, float64) {
|
||||
|
||||
func indexLoad(b0 []float32, b1 float32, idx int) float32 {
|
||||
// arm64:`FMOVS\s\(R[0-9]+\)\(R[0-9]+<<2\),\sF[0-9]+`
|
||||
// loong64:`MOVF\s\(R[0-9]+\)\(R[0-9]+\),\sF[0-9]+`
|
||||
return b0[idx] * b1
|
||||
}
|
||||
|
||||
func indexStore(b0 []float64, b1 float64, idx int) {
|
||||
// arm64:`FMOVD\sF[0-9]+,\s\(R[0-9]+\)\(R[0-9]+<<3\)`
|
||||
// loong64:`MOVD\sF[0-9]+,\s\(R[0-9]+\)\(R[0-9]+\)`
|
||||
b0[idx] = b1
|
||||
}
|
||||
|
||||
@@ -70,6 +72,7 @@ func FusedAdd32(x, y, z float32) float32 {
|
||||
// s390x:"FMADDS\t"
|
||||
// ppc64x:"FMADDS\t"
|
||||
// arm64:"FMADDS"
|
||||
// loong64:"FMADDF\t"
|
||||
// riscv64:"FMADDS\t"
|
||||
return x*y + z
|
||||
}
|
||||
@@ -78,11 +81,13 @@ func FusedSub32_a(x, y, z float32) float32 {
|
||||
// s390x:"FMSUBS\t"
|
||||
// ppc64x:"FMSUBS\t"
|
||||
// riscv64:"FMSUBS\t"
|
||||
// loong64:"FMSUBF\t"
|
||||
return x*y - z
|
||||
}
|
||||
|
||||
func FusedSub32_b(x, y, z float32) float32 {
|
||||
// arm64:"FMSUBS"
|
||||
// loong64:"FNMSUBF\t"
|
||||
// riscv64:"FNMSUBS\t"
|
||||
return z - x*y
|
||||
}
|
||||
@@ -91,6 +96,7 @@ func FusedAdd64(x, y, z float64) float64 {
|
||||
// s390x:"FMADD\t"
|
||||
// ppc64x:"FMADD\t"
|
||||
// arm64:"FMADDD"
|
||||
// loong64:"FMADDD\t"
|
||||
// riscv64:"FMADDD\t"
|
||||
return x*y + z
|
||||
}
|
||||
@@ -99,11 +105,13 @@ func FusedSub64_a(x, y, z float64) float64 {
|
||||
// s390x:"FMSUB\t"
|
||||
// ppc64x:"FMSUB\t"
|
||||
// riscv64:"FMSUBD\t"
|
||||
// loong64:"FMSUBD\t"
|
||||
return x*y - z
|
||||
}
|
||||
|
||||
func FusedSub64_b(x, y, z float64) float64 {
|
||||
// arm64:"FMSUBD"
|
||||
// loong64:"FNMSUBD\t"
|
||||
// riscv64:"FNMSUBD\t"
|
||||
return z - x*y
|
||||
}
|
||||
@@ -164,6 +172,7 @@ func ArrayCopy(a [16]byte) (b [16]byte) {
|
||||
func Float64Min(a, b float64) float64 {
|
||||
// amd64:"MINSD"
|
||||
// arm64:"FMIND"
|
||||
// loong64:"FMIND"
|
||||
// riscv64:"FMIN"
|
||||
// ppc64/power9:"XSMINJDP"
|
||||
// ppc64/power10:"XSMINJDP"
|
||||
@@ -173,6 +182,7 @@ func Float64Min(a, b float64) float64 {
|
||||
func Float64Max(a, b float64) float64 {
|
||||
// amd64:"MINSD"
|
||||
// arm64:"FMAXD"
|
||||
// loong64:"FMAXD"
|
||||
// riscv64:"FMAX"
|
||||
// ppc64/power9:"XSMAXJDP"
|
||||
// ppc64/power10:"XSMAXJDP"
|
||||
@@ -182,6 +192,7 @@ func Float64Max(a, b float64) float64 {
|
||||
func Float32Min(a, b float32) float32 {
|
||||
// amd64:"MINSS"
|
||||
// arm64:"FMINS"
|
||||
// loong64:"FMINF"
|
||||
// riscv64:"FMINS"
|
||||
// ppc64/power9:"XSMINJDP"
|
||||
// ppc64/power10:"XSMINJDP"
|
||||
@@ -191,6 +202,7 @@ func Float32Min(a, b float32) float32 {
|
||||
func Float32Max(a, b float32) float32 {
|
||||
// amd64:"MINSS"
|
||||
// arm64:"FMAXS"
|
||||
// loong64:"FMAXF"
|
||||
// riscv64:"FMAXS"
|
||||
// ppc64/power9:"XSMAXJDP"
|
||||
// ppc64/power10:"XSMAXJDP"
|
||||
@@ -227,3 +239,12 @@ func Float64DenormalFloat32Constant() float64 {
|
||||
// ppc64x:"FMOVD\t[$]f64\\.3800000000000000\\(SB\\)"
|
||||
return 0x1p-127
|
||||
}
|
||||
|
||||
func Float64ConstantStore(p *float64) {
|
||||
// amd64: "MOVQ\t[$]4617801906721357038"
|
||||
*p = 5.432
|
||||
}
|
||||
func Float32ConstantStore(p *float32) {
|
||||
// amd64: "MOVL\t[$]1085133554"
|
||||
*p = 5.432
|
||||
}
|
||||
|
||||
17
test/codegen/issue59297.go
Normal file
17
test/codegen/issue59297.go
Normal file
@@ -0,0 +1,17 @@
|
||||
// asmcheck
|
||||
|
||||
// Copyright 2023 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(x, y int, p *int) {
|
||||
// amd64:`MOVQ\sAX, BX`
|
||||
h(8, x)
|
||||
*p = y
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func h(a, b int) {
|
||||
}
|
||||
52
test/codegen/issue68845.go
Normal file
52
test/codegen/issue68845.go
Normal file
@@ -0,0 +1,52 @@
|
||||
// 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
|
||||
|
||||
type T1 struct {
|
||||
x string
|
||||
}
|
||||
|
||||
func f1() *T1 {
|
||||
// amd64:-`MOVQ\s[$]0`,-`MOVUPS\sX15`
|
||||
return &T1{}
|
||||
}
|
||||
|
||||
type T2 struct {
|
||||
x, y string
|
||||
}
|
||||
|
||||
func f2() *T2 {
|
||||
// amd64:-`MOVQ\s[$]0`,-`MOVUPS\sX15`
|
||||
return &T2{}
|
||||
}
|
||||
|
||||
type T3 struct {
|
||||
x complex128
|
||||
}
|
||||
|
||||
func f3() *T3 {
|
||||
// amd64:-`MOVQ\s[$]0`,-`MOVUPS\sX15`
|
||||
return &T3{}
|
||||
}
|
||||
|
||||
type T4 struct {
|
||||
x []byte
|
||||
}
|
||||
|
||||
func f4() *T4 {
|
||||
// amd64:-`MOVQ\s[$]0`,-`MOVUPS\sX15`
|
||||
return &T4{}
|
||||
}
|
||||
|
||||
type T5 struct {
|
||||
x any
|
||||
}
|
||||
|
||||
func f5() *T5 {
|
||||
// amd64:-`MOVQ\s[$]0`,-`MOVUPS\sX15`
|
||||
return &T5{}
|
||||
}
|
||||
13
test/codegen/issue69635.go
Normal file
13
test/codegen/issue69635.go
Normal file
@@ -0,0 +1,13 @@
|
||||
// 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
|
||||
|
||||
func calc(a uint64) uint64 {
|
||||
v := a >> 20 & 0x7f
|
||||
// amd64: `SHRQ\s\$17, AX$`, `ANDL\s\$1016, AX$`
|
||||
return v << 3
|
||||
}
|
||||
@@ -74,7 +74,7 @@ func LookupStringConversionKeyedArrayLit(m map[[2]string]int, bytes []byte) int
|
||||
|
||||
func MapClearReflexive(m map[int]int) {
|
||||
// amd64:`.*runtime\.mapclear`
|
||||
// amd64:-`.*runtime\.mapiterinit`
|
||||
// amd64:-`.*runtime\.(mapiterinit|mapIterStart)`
|
||||
for k := range m {
|
||||
delete(m, k)
|
||||
}
|
||||
@@ -83,7 +83,7 @@ func MapClearReflexive(m map[int]int) {
|
||||
func MapClearIndirect(m map[int]int) {
|
||||
s := struct{ m map[int]int }{m: m}
|
||||
// amd64:`.*runtime\.mapclear`
|
||||
// amd64:-`.*runtime\.mapiterinit`
|
||||
// amd64:-`.*runtime\.(mapiterinit|mapIterStart)`
|
||||
for k := range s.m {
|
||||
delete(s.m, k)
|
||||
}
|
||||
@@ -91,14 +91,14 @@ func MapClearIndirect(m map[int]int) {
|
||||
|
||||
func MapClearPointer(m map[*byte]int) {
|
||||
// amd64:`.*runtime\.mapclear`
|
||||
// amd64:-`.*runtime\.mapiterinit`
|
||||
// amd64:-`.*runtime\.(mapiterinit|mapIterStart)`
|
||||
for k := range m {
|
||||
delete(m, k)
|
||||
}
|
||||
}
|
||||
|
||||
func MapClearNotReflexive(m map[float64]int) {
|
||||
// amd64:`.*runtime\.mapiterinit`
|
||||
// amd64:`.*runtime\.(mapiterinit|mapIterStart)`
|
||||
// amd64:-`.*runtime\.mapclear`
|
||||
for k := range m {
|
||||
delete(m, k)
|
||||
@@ -106,7 +106,7 @@ func MapClearNotReflexive(m map[float64]int) {
|
||||
}
|
||||
|
||||
func MapClearInterface(m map[interface{}]int) {
|
||||
// amd64:`.*runtime\.mapiterinit`
|
||||
// amd64:`.*runtime\.(mapiterinit|mapIterStart)`
|
||||
// amd64:-`.*runtime\.mapclear`
|
||||
for k := range m {
|
||||
delete(m, k)
|
||||
@@ -115,7 +115,7 @@ func MapClearInterface(m map[interface{}]int) {
|
||||
|
||||
func MapClearSideEffect(m map[int]int) int {
|
||||
k := 0
|
||||
// amd64:`.*runtime\.mapiterinit`
|
||||
// amd64:`.*runtime\.(mapiterinit|mapIterStart)`
|
||||
// amd64:-`.*runtime\.mapclear`
|
||||
for k = range m {
|
||||
delete(m, k)
|
||||
|
||||
@@ -132,6 +132,7 @@ func fma(x, y, z float64) float64 {
|
||||
// amd64:"VFMADD231SD"
|
||||
// arm/6:"FMULAD"
|
||||
// arm64:"FMADDD"
|
||||
// loong64:"FMADDD"
|
||||
// s390x:"FMADD"
|
||||
// ppc64x:"FMADD"
|
||||
// riscv64:"FMADDD"
|
||||
@@ -156,6 +157,7 @@ func fnma(x, y, z float64) float64 {
|
||||
func fromFloat64(f64 float64) uint64 {
|
||||
// amd64:"MOVQ\tX.*, [^X].*"
|
||||
// arm64:"FMOVD\tF.*, R.*"
|
||||
// loong64:"MOVV\tF.*, R.*"
|
||||
// ppc64x:"MFVSRD"
|
||||
// mips64/hardfloat:"MOVV\tF.*, R.*"
|
||||
return math.Float64bits(f64+1) + 1
|
||||
@@ -164,6 +166,7 @@ func fromFloat64(f64 float64) uint64 {
|
||||
func fromFloat32(f32 float32) uint32 {
|
||||
// amd64:"MOVL\tX.*, [^X].*"
|
||||
// arm64:"FMOVS\tF.*, R.*"
|
||||
// loong64:"MOVW\tF.*, R.*"
|
||||
// mips64/hardfloat:"MOVW\tF.*, R.*"
|
||||
return math.Float32bits(f32+1) + 1
|
||||
}
|
||||
@@ -171,6 +174,7 @@ func fromFloat32(f32 float32) uint32 {
|
||||
func toFloat64(u64 uint64) float64 {
|
||||
// amd64:"MOVQ\t[^X].*, X.*"
|
||||
// arm64:"FMOVD\tR.*, F.*"
|
||||
// loong64:"MOVV\tR.*, F.*"
|
||||
// ppc64x:"MTVSRD"
|
||||
// mips64/hardfloat:"MOVV\tR.*, F.*"
|
||||
return math.Float64frombits(u64+1) + 1
|
||||
@@ -179,6 +183,7 @@ func toFloat64(u64 uint64) float64 {
|
||||
func toFloat32(u32 uint32) float32 {
|
||||
// amd64:"MOVL\t[^X].*, X.*"
|
||||
// arm64:"FMOVS\tR.*, F.*"
|
||||
// loong64:"MOVW\tR.*, F.*"
|
||||
// mips64/hardfloat:"MOVW\tR.*, F.*"
|
||||
return math.Float32frombits(u32+1) + 1
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ func LeadingZeros(n uint) int {
|
||||
// amd64/v3:"LZCNTQ", -"BSRQ"
|
||||
// s390x:"FLOGR"
|
||||
// arm:"CLZ" arm64:"CLZ"
|
||||
// loong64:"CLZV",-"SUB"
|
||||
// mips:"CLZ"
|
||||
// wasm:"I64Clz"
|
||||
// ppc64x:"CNTLZD"
|
||||
@@ -28,6 +29,7 @@ func LeadingZeros64(n uint64) int {
|
||||
// amd64/v3:"LZCNTQ", -"BSRQ"
|
||||
// s390x:"FLOGR"
|
||||
// arm:"CLZ" arm64:"CLZ"
|
||||
// loong64:"CLZV",-"SUB"
|
||||
// mips:"CLZ"
|
||||
// wasm:"I64Clz"
|
||||
// ppc64x:"CNTLZD"
|
||||
@@ -39,6 +41,7 @@ func LeadingZeros32(n uint32) int {
|
||||
// amd64/v3: "LZCNTL",- "BSRL"
|
||||
// s390x:"FLOGR"
|
||||
// arm:"CLZ" arm64:"CLZW"
|
||||
// loong64:"CLZW",-"SUB"
|
||||
// mips:"CLZ"
|
||||
// wasm:"I64Clz"
|
||||
// ppc64x:"CNTLZW"
|
||||
@@ -50,6 +53,7 @@ func LeadingZeros16(n uint16) int {
|
||||
// amd64/v3: "LZCNTL",- "BSRL"
|
||||
// s390x:"FLOGR"
|
||||
// arm:"CLZ" arm64:"CLZ"
|
||||
// loong64:"CLZV"
|
||||
// mips:"CLZ"
|
||||
// wasm:"I64Clz"
|
||||
// ppc64x:"CNTLZD"
|
||||
@@ -61,6 +65,7 @@ func LeadingZeros8(n uint8) int {
|
||||
// amd64/v3: "LZCNTL",- "BSRL"
|
||||
// s390x:"FLOGR"
|
||||
// arm:"CLZ" arm64:"CLZ"
|
||||
// loong64:"CLZV"
|
||||
// mips:"CLZ"
|
||||
// wasm:"I64Clz"
|
||||
// ppc64x:"CNTLZD"
|
||||
@@ -76,6 +81,7 @@ func Len(n uint) int {
|
||||
// amd64/v3: "LZCNTQ"
|
||||
// s390x:"FLOGR"
|
||||
// arm:"CLZ" arm64:"CLZ"
|
||||
// loong64:"CLZV"
|
||||
// mips:"CLZ"
|
||||
// wasm:"I64Clz"
|
||||
// ppc64x:"SUBC","CNTLZD"
|
||||
@@ -87,6 +93,7 @@ func Len64(n uint64) int {
|
||||
// amd64/v3: "LZCNTQ"
|
||||
// s390x:"FLOGR"
|
||||
// arm:"CLZ" arm64:"CLZ"
|
||||
// loong64:"CLZV"
|
||||
// mips:"CLZ"
|
||||
// wasm:"I64Clz"
|
||||
// ppc64x:"SUBC","CNTLZD"
|
||||
@@ -94,15 +101,22 @@ func Len64(n uint64) int {
|
||||
}
|
||||
|
||||
func SubFromLen64(n uint64) int {
|
||||
// loong64:"CLZV",-"ADD"
|
||||
// ppc64x:"CNTLZD",-"SUBC"
|
||||
return 64 - bits.Len64(n)
|
||||
}
|
||||
|
||||
func CompareWithLen64(n uint64) bool {
|
||||
// loong64:"CLZV",-"ADD",-"[$]64",-"[$]9"
|
||||
return bits.Len64(n) < 9
|
||||
}
|
||||
|
||||
func Len32(n uint32) int {
|
||||
// amd64/v1,amd64/v2:"BSRQ","LEAQ",-"CMOVQEQ"
|
||||
// amd64/v3: "LZCNTL"
|
||||
// s390x:"FLOGR"
|
||||
// arm:"CLZ" arm64:"CLZ"
|
||||
// loong64:"CLZW"
|
||||
// mips:"CLZ"
|
||||
// wasm:"I64Clz"
|
||||
// ppc64x: "CNTLZW"
|
||||
@@ -114,6 +128,7 @@ func Len16(n uint16) int {
|
||||
// amd64/v3: "LZCNTL"
|
||||
// s390x:"FLOGR"
|
||||
// arm:"CLZ" arm64:"CLZ"
|
||||
// loong64:"CLZV"
|
||||
// mips:"CLZ"
|
||||
// wasm:"I64Clz"
|
||||
// ppc64x:"SUBC","CNTLZD"
|
||||
@@ -125,6 +140,7 @@ func Len8(n uint8) int {
|
||||
// amd64/v3: "LZCNTL"
|
||||
// s390x:"FLOGR"
|
||||
// arm:"CLZ" arm64:"CLZ"
|
||||
// loong64:"CLZV"
|
||||
// mips:"CLZ"
|
||||
// wasm:"I64Clz"
|
||||
// ppc64x:"SUBC","CNTLZD"
|
||||
@@ -140,6 +156,7 @@ func OnesCount(n uint) int {
|
||||
// amd64/v2:-".*x86HasPOPCNT" amd64/v3:-".*x86HasPOPCNT"
|
||||
// amd64:"POPCNTQ"
|
||||
// arm64:"VCNT","VUADDLV"
|
||||
// loong64:"VPCNTV"
|
||||
// s390x:"POPCNT"
|
||||
// ppc64x:"POPCNTD"
|
||||
// wasm:"I64Popcnt"
|
||||
@@ -150,6 +167,7 @@ func OnesCount64(n uint64) int {
|
||||
// amd64/v2:-".*x86HasPOPCNT" amd64/v3:-".*x86HasPOPCNT"
|
||||
// amd64:"POPCNTQ"
|
||||
// arm64:"VCNT","VUADDLV"
|
||||
// loong64:"VPCNTV"
|
||||
// s390x:"POPCNT"
|
||||
// ppc64x:"POPCNTD"
|
||||
// wasm:"I64Popcnt"
|
||||
@@ -160,6 +178,7 @@ func OnesCount32(n uint32) int {
|
||||
// amd64/v2:-".*x86HasPOPCNT" amd64/v3:-".*x86HasPOPCNT"
|
||||
// amd64:"POPCNTL"
|
||||
// arm64:"VCNT","VUADDLV"
|
||||
// loong64:"VPCNTW"
|
||||
// s390x:"POPCNT"
|
||||
// ppc64x:"POPCNTW"
|
||||
// wasm:"I64Popcnt"
|
||||
@@ -170,6 +189,7 @@ func OnesCount16(n uint16) int {
|
||||
// amd64/v2:-".*x86HasPOPCNT" amd64/v3:-".*x86HasPOPCNT"
|
||||
// amd64:"POPCNTL"
|
||||
// arm64:"VCNT","VUADDLV"
|
||||
// loong64:"VPCNTH"
|
||||
// s390x:"POPCNT"
|
||||
// ppc64x:"POPCNTW"
|
||||
// wasm:"I64Popcnt"
|
||||
@@ -183,6 +203,35 @@ func OnesCount8(n uint8) int {
|
||||
return bits.OnesCount8(n)
|
||||
}
|
||||
|
||||
// ------------------ //
|
||||
// bits.Reverse //
|
||||
// ------------------ //
|
||||
|
||||
func Reverse(n uint) uint {
|
||||
// loong64:"BITREVV"
|
||||
return bits.Reverse(n)
|
||||
}
|
||||
|
||||
func Reverse64(n uint64) uint64 {
|
||||
// loong64:"BITREVV"
|
||||
return bits.Reverse64(n)
|
||||
}
|
||||
|
||||
func Reverse32(n uint32) uint32 {
|
||||
// loong64:"BITREVW"
|
||||
return bits.Reverse32(n)
|
||||
}
|
||||
|
||||
func Reverse16(n uint16) uint16 {
|
||||
// loong64:"BITREV4B","REVB2H"
|
||||
return bits.Reverse16(n)
|
||||
}
|
||||
|
||||
func Reverse8(n uint8) uint8 {
|
||||
// loong64:"BITREV4B"
|
||||
return bits.Reverse8(n)
|
||||
}
|
||||
|
||||
// ----------------------- //
|
||||
// bits.ReverseBytes //
|
||||
// ----------------------- //
|
||||
@@ -192,6 +241,7 @@ func ReverseBytes(n uint) uint {
|
||||
// 386:"BSWAPL"
|
||||
// s390x:"MOVDBR"
|
||||
// arm64:"REV"
|
||||
// loong64:"REVBV"
|
||||
return bits.ReverseBytes(n)
|
||||
}
|
||||
|
||||
@@ -201,6 +251,7 @@ func ReverseBytes64(n uint64) uint64 {
|
||||
// s390x:"MOVDBR"
|
||||
// arm64:"REV"
|
||||
// ppc64x/power10: "BRD"
|
||||
// loong64:"REVBV"
|
||||
return bits.ReverseBytes64(n)
|
||||
}
|
||||
|
||||
@@ -209,6 +260,7 @@ func ReverseBytes32(n uint32) uint32 {
|
||||
// 386:"BSWAPL"
|
||||
// s390x:"MOVWBR"
|
||||
// arm64:"REVW"
|
||||
// loong64:"REVB2W"
|
||||
// ppc64x/power10: "BRW"
|
||||
return bits.ReverseBytes32(n)
|
||||
}
|
||||
@@ -219,6 +271,7 @@ func ReverseBytes16(n uint16) uint16 {
|
||||
// arm/5:"SLL","SRL","ORR"
|
||||
// arm/6:"REV16"
|
||||
// arm/7:"REV16"
|
||||
// loong64:"REVB2H"
|
||||
// ppc64x/power10: "BRH"
|
||||
return bits.ReverseBytes16(n)
|
||||
}
|
||||
@@ -230,7 +283,9 @@ func ReverseBytes16(n uint16) uint16 {
|
||||
func RotateLeft64(n uint64) uint64 {
|
||||
// amd64:"ROLQ"
|
||||
// arm64:"ROR"
|
||||
// loong64:"ROTRV"
|
||||
// ppc64x:"ROTL"
|
||||
// riscv64:"RORI"
|
||||
// s390x:"RISBGZ\t[$]0, [$]63, [$]37, "
|
||||
// wasm:"I64Rotl"
|
||||
return bits.RotateLeft64(n, 37)
|
||||
@@ -240,7 +295,9 @@ func RotateLeft32(n uint32) uint32 {
|
||||
// amd64:"ROLL" 386:"ROLL"
|
||||
// arm:`MOVW\tR[0-9]+@>23`
|
||||
// arm64:"RORW"
|
||||
// loong64:"ROTR\t"
|
||||
// ppc64x:"ROTLW"
|
||||
// riscv64:"RORIW"
|
||||
// s390x:"RLL"
|
||||
// wasm:"I32Rotl"
|
||||
return bits.RotateLeft32(n, 9)
|
||||
@@ -249,19 +306,23 @@ func RotateLeft32(n uint32) uint32 {
|
||||
func RotateLeft16(n uint16, s int) uint16 {
|
||||
// amd64:"ROLW" 386:"ROLW"
|
||||
// arm64:"RORW",-"CSEL"
|
||||
// loong64:"ROTR\t","SLLV"
|
||||
return bits.RotateLeft16(n, s)
|
||||
}
|
||||
|
||||
func RotateLeft8(n uint8, s int) uint8 {
|
||||
// amd64:"ROLB" 386:"ROLB"
|
||||
// arm64:"LSL","LSR",-"CSEL"
|
||||
// loong64:"OR","SLLV","SRLV"
|
||||
return bits.RotateLeft8(n, s)
|
||||
}
|
||||
|
||||
func RotateLeftVariable(n uint, m int) uint {
|
||||
// amd64:"ROLQ"
|
||||
// arm64:"ROR"
|
||||
// loong64:"ROTRV"
|
||||
// ppc64x:"ROTL"
|
||||
// riscv64:"ROL"
|
||||
// s390x:"RLLG"
|
||||
// wasm:"I64Rotl"
|
||||
return bits.RotateLeft(n, m)
|
||||
@@ -270,7 +331,9 @@ func RotateLeftVariable(n uint, m int) uint {
|
||||
func RotateLeftVariable64(n uint64, m int) uint64 {
|
||||
// amd64:"ROLQ"
|
||||
// arm64:"ROR"
|
||||
// loong64:"ROTRV"
|
||||
// ppc64x:"ROTL"
|
||||
// riscv64:"ROL"
|
||||
// s390x:"RLLG"
|
||||
// wasm:"I64Rotl"
|
||||
return bits.RotateLeft64(n, m)
|
||||
@@ -280,7 +343,9 @@ func RotateLeftVariable32(n uint32, m int) uint32 {
|
||||
// arm:`MOVW\tR[0-9]+@>R[0-9]+`
|
||||
// amd64:"ROLL"
|
||||
// arm64:"RORW"
|
||||
// loong64:"ROTR\t"
|
||||
// ppc64x:"ROTLW"
|
||||
// riscv64:"ROLW"
|
||||
// s390x:"RLL"
|
||||
// wasm:"I32Rotl"
|
||||
return bits.RotateLeft32(n, m)
|
||||
@@ -296,6 +361,7 @@ func TrailingZeros(n uint) int {
|
||||
// 386:"BSFL"
|
||||
// arm:"CLZ"
|
||||
// arm64:"RBIT","CLZ"
|
||||
// loong64:"CTZV"
|
||||
// s390x:"FLOGR"
|
||||
// ppc64x/power8:"ANDN","POPCNTD"
|
||||
// ppc64x/power9: "CNTTZD"
|
||||
@@ -308,6 +374,7 @@ func TrailingZeros64(n uint64) int {
|
||||
// amd64/v3:"TZCNTQ"
|
||||
// 386:"BSFL"
|
||||
// arm64:"RBIT","CLZ"
|
||||
// loong64:"CTZV"
|
||||
// s390x:"FLOGR"
|
||||
// ppc64x/power8:"ANDN","POPCNTD"
|
||||
// ppc64x/power9: "CNTTZD"
|
||||
@@ -327,6 +394,7 @@ func TrailingZeros32(n uint32) int {
|
||||
// 386:"BSFL"
|
||||
// arm:"CLZ"
|
||||
// arm64:"RBITW","CLZW"
|
||||
// loong64:"CTZW"
|
||||
// s390x:"FLOGR","MOVWZ"
|
||||
// ppc64x/power8:"ANDN","POPCNTW"
|
||||
// ppc64x/power9: "CNTTZW"
|
||||
@@ -339,6 +407,7 @@ func TrailingZeros16(n uint16) int {
|
||||
// 386:"BSFL\t"
|
||||
// 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/power9:"CNTTZD","ORIS\\t\\$1"
|
||||
@@ -351,6 +420,7 @@ func TrailingZeros8(n uint8) int {
|
||||
// 386:"BSFL"
|
||||
// arm:"ORR\t\\$256","CLZ",-"MOVBU\tR"
|
||||
// arm64:"ORR\t\\$256","RBITW","CLZW",-"MOVBU\tR",-"RBIT\t",-"CLZ\t"
|
||||
// loong64:"CTZV"
|
||||
// s390x:"FLOGR","OR\t\\$256"
|
||||
// wasm:"I64Ctz"
|
||||
return bits.TrailingZeros8(n)
|
||||
|
||||
@@ -19,6 +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]+\),`
|
||||
// ppc64le:`MOVD\s`,-`MOV[BHW]Z`
|
||||
// ppc64:`MOVDBR\s`,-`MOV[BHW]Z`
|
||||
return binary.LittleEndian.Uint64(b)
|
||||
@@ -28,6 +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]+\),`
|
||||
// ppc64le:`MOVD\s`,-`MOV[BHW]Z\s`
|
||||
// ppc64:`MOVDBR\s`,-`MOV[BHW]Z\s`
|
||||
return binary.LittleEndian.Uint64(b[idx:])
|
||||
@@ -38,6 +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]+\),`
|
||||
// ppc64le:`MOVWZ\s`,-`MOV[BH]Z\s`
|
||||
// ppc64:`MOVWBR\s`,-`MOV[BH]Z\s`
|
||||
return binary.LittleEndian.Uint32(b)
|
||||
@@ -48,6 +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]+\),`
|
||||
// ppc64le:`MOVWZ\s`,-`MOV[BH]Z\s`
|
||||
// ppc64:`MOVWBR\s`,-`MOV[BH]Z\s'
|
||||
return binary.LittleEndian.Uint32(b[idx:])
|
||||
@@ -57,6 +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]+\),`
|
||||
// s390x:`MOVHBR\s\(.*\),`
|
||||
// ppc64:`MOVHBR\s`,-`MOVBZ`
|
||||
return binary.LittleEndian.Uint16(b)
|
||||
@@ -67,6 +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]+\),`
|
||||
// s390x:`MOVHBR\s\(.*\)\(.*\*1\),`
|
||||
return binary.LittleEndian.Uint16(b[idx:])
|
||||
}
|
||||
@@ -938,3 +944,29 @@ func issue66413(p *struct {
|
||||
p.c = true
|
||||
p.d = 12
|
||||
}
|
||||
|
||||
func issue70300(v uint64) (b [8]byte) {
|
||||
// amd64:"MOVQ",-"MOVB"
|
||||
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
|
||||
}
|
||||
|
||||
func issue70300Reverse(v uint64) (b [8]byte) {
|
||||
// amd64:"MOVQ",-"MOVB"
|
||||
b[7] = byte(v >> 56)
|
||||
b[6] = byte(v >> 48)
|
||||
b[5] = byte(v >> 40)
|
||||
b[4] = byte(v >> 32)
|
||||
b[3] = byte(v >> 24)
|
||||
b[2] = byte(v >> 16)
|
||||
b[1] = byte(v >> 8)
|
||||
b[0] = byte(v)
|
||||
return b
|
||||
}
|
||||
|
||||
@@ -462,12 +462,6 @@ func checkMergedShifts64(a [256]uint32, b [256]uint64, c [256]byte, v uint64) {
|
||||
a[2] = a[v>>25&0x7F]
|
||||
// ppc64x: -"CLRLSLDI", "RLWNM\t[$]3, R[0-9]+, [$]29, [$]29, R[0-9]+"
|
||||
a[3] = a[(v>>31)&0x01]
|
||||
// ppc64x: "SRD", "CLRLSLDI", -"RLWNM"
|
||||
a[4] = a[(v>>30)&0x07]
|
||||
// ppc64x: "SRD", "CLRLSLDI", -"RLWNM"
|
||||
a[5] = a[(v>>32)&0x01]
|
||||
// ppc64x: "SRD", "CLRLSLDI", -"RLWNM"
|
||||
a[6] = a[(v>>34)&0x03]
|
||||
// ppc64x: -"CLRLSLDI", "RLWNM\t[$]12, R[0-9]+, [$]21, [$]28, R[0-9]+"
|
||||
b[0] = b[uint8(v>>23)]
|
||||
// ppc64x: -"CLRLSLDI", "RLWNM\t[$]15, R[0-9]+, [$]21, [$]28, R[0-9]+"
|
||||
@@ -476,7 +470,7 @@ func checkMergedShifts64(a [256]uint32, b [256]uint64, c [256]byte, v uint64) {
|
||||
b[2] = b[((uint64((uint32(v) >> 21)) & 0x3f) << 4)]
|
||||
// ppc64x: "RLWNM\t[$]11, R[0-9]+, [$]10, [$]15"
|
||||
c[0] = c[((v>>5)&0x3F)<<16]
|
||||
// ppc64x: "RLWNM\t[$]0, R[0-9]+, [$]19, [$]24"
|
||||
// ppc64x: "ANDCC\t[$]8064,"
|
||||
c[1] = c[((v>>7)&0x3F)<<7]
|
||||
}
|
||||
|
||||
@@ -520,3 +514,20 @@ func checkShiftToMask(u []uint64, s []int64) {
|
||||
// amd64:-"SHR",-"SHL","ANDQ"
|
||||
u[1] = u[1] << 5 >> 5
|
||||
}
|
||||
|
||||
//
|
||||
// Left shift with addition.
|
||||
//
|
||||
|
||||
func checkLeftShiftWithAddition(a int64, b int64) int64 {
|
||||
// riscv64/rva20u64: "SLLI","ADD"
|
||||
// riscv64/rva22u64: "SH1ADD"
|
||||
a = a + b<<1
|
||||
// riscv64/rva20u64: "SLLI","ADD"
|
||||
// riscv64/rva22u64: "SH2ADD"
|
||||
a = a + b<<2
|
||||
// riscv64/rva20u64: "SLLI","ADD"
|
||||
// riscv64/rva22u64: "SH3ADD"
|
||||
a = a + b<<3
|
||||
return a
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ func SliceExtensionConst(s []int) []int {
|
||||
// amd64:-`.*runtime\.makeslice`
|
||||
// amd64:-`.*runtime\.panicmakeslicelen`
|
||||
// amd64:"MOVUPS\tX15"
|
||||
// loong64:-`.*runtime\.memclrNoHeapPointers`
|
||||
// ppc64x:-`.*runtime\.memclrNoHeapPointers`
|
||||
// ppc64x:-`.*runtime\.makeslice`
|
||||
// ppc64x:-`.*runtime\.panicmakeslicelen`
|
||||
@@ -58,6 +59,7 @@ func SliceExtensionConstInt64(s []int) []int {
|
||||
// amd64:-`.*runtime\.makeslice`
|
||||
// amd64:-`.*runtime\.panicmakeslicelen`
|
||||
// amd64:"MOVUPS\tX15"
|
||||
// loong64:-`.*runtime\.memclrNoHeapPointers`
|
||||
// ppc64x:-`.*runtime\.memclrNoHeapPointers`
|
||||
// ppc64x:-`.*runtime\.makeslice`
|
||||
// ppc64x:-`.*runtime\.panicmakeslicelen`
|
||||
@@ -69,6 +71,7 @@ func SliceExtensionConstUint64(s []int) []int {
|
||||
// amd64:-`.*runtime\.makeslice`
|
||||
// amd64:-`.*runtime\.panicmakeslicelen`
|
||||
// amd64:"MOVUPS\tX15"
|
||||
// loong64:-`.*runtime\.memclrNoHeapPointers`
|
||||
// ppc64x:-`.*runtime\.memclrNoHeapPointers`
|
||||
// ppc64x:-`.*runtime\.makeslice`
|
||||
// ppc64x:-`.*runtime\.panicmakeslicelen`
|
||||
@@ -80,16 +83,18 @@ func SliceExtensionConstUint(s []int) []int {
|
||||
// amd64:-`.*runtime\.makeslice`
|
||||
// amd64:-`.*runtime\.panicmakeslicelen`
|
||||
// amd64:"MOVUPS\tX15"
|
||||
// loong64:-`.*runtime\.memclrNoHeapPointers`
|
||||
// ppc64x:-`.*runtime\.memclrNoHeapPointers`
|
||||
// ppc64x:-`.*runtime\.makeslice`
|
||||
// ppc64x:-`.*runtime\.panicmakeslicelen`
|
||||
return append(s, make([]int, uint(1<<2))...)
|
||||
}
|
||||
|
||||
// On ppc64x continue to use memclrNoHeapPointers
|
||||
// On ppc64x and loong64 continue to use memclrNoHeapPointers
|
||||
// for sizes >= 512.
|
||||
func SliceExtensionConst512(s []int) []int {
|
||||
// amd64:-`.*runtime\.memclrNoHeapPointers`
|
||||
// loong64:`.*runtime\.memclrNoHeapPointers`
|
||||
// ppc64x:`.*runtime\.memclrNoHeapPointers`
|
||||
return append(s, make([]int, 1<<9)...)
|
||||
}
|
||||
|
||||
31
test/codegen/spills.go
Normal file
31
test/codegen/spills.go
Normal file
@@ -0,0 +1,31 @@
|
||||
// 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
|
||||
|
||||
func i64(a, b int64) int64 { // arm64:`STP\s`,`LDP\s`
|
||||
g()
|
||||
return a + b
|
||||
}
|
||||
|
||||
func i32(a, b int32) int32 { // arm64:`STPW`,`LDPW`
|
||||
g()
|
||||
return a + b
|
||||
}
|
||||
|
||||
func f64(a, b float64) float64 { // arm64:`FSTPD`,`FLDPD`
|
||||
g()
|
||||
return a + b
|
||||
}
|
||||
|
||||
func f32(a, b float32) float32 { // arm64:`FSTPS`,`FLDPS`
|
||||
g()
|
||||
return a + b
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func g() {
|
||||
}
|
||||
@@ -26,6 +26,11 @@ func ToByteSlice() []byte { // Issue #24698
|
||||
return []byte("foo")
|
||||
}
|
||||
|
||||
func ConvertToByteSlice(a, b, c string) []byte {
|
||||
// amd64:`.*runtime.concatbyte3`
|
||||
return []byte(a + b + c)
|
||||
}
|
||||
|
||||
// Loading from read-only symbols should get transformed into constants.
|
||||
func ConstantLoad() {
|
||||
// 12592 = 0x3130
|
||||
|
||||
67
test/codegen/typeswitch.go
Normal file
67
test/codegen/typeswitch.go
Normal file
@@ -0,0 +1,67 @@
|
||||
// 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
|
||||
|
||||
type Ix interface {
|
||||
X()
|
||||
}
|
||||
|
||||
type Iy interface {
|
||||
Y()
|
||||
}
|
||||
|
||||
type Iz interface {
|
||||
Z()
|
||||
}
|
||||
|
||||
func swXYZ(a Ix) {
|
||||
switch t := a.(type) {
|
||||
case Iy: // amd64:-".*typeAssert"
|
||||
t.Y()
|
||||
case Iz: // amd64:-".*typeAssert"
|
||||
t.Z()
|
||||
}
|
||||
}
|
||||
|
||||
type Ig[T any] interface {
|
||||
G() T
|
||||
}
|
||||
|
||||
func swGYZ[T any](a Ig[T]) {
|
||||
switch t := a.(type) {
|
||||
case Iy: // amd64:-".*typeAssert"
|
||||
t.Y()
|
||||
case Iz: // amd64:-".*typeAssert"
|
||||
t.Z()
|
||||
case interface{ G() T }: // amd64:-".*typeAssert",-".*assertE2I\\(",".*assertE2I2"
|
||||
t.G()
|
||||
}
|
||||
}
|
||||
|
||||
func swE2G[T any](a any) {
|
||||
switch t := a.(type) {
|
||||
case Iy:
|
||||
t.Y()
|
||||
case Ig[T]: // amd64:-".*assertE2I\\(",".*assertE2I2"
|
||||
t.G()
|
||||
}
|
||||
}
|
||||
|
||||
func swI2G[T any](a Ix) {
|
||||
switch t := a.(type) {
|
||||
case Iy:
|
||||
t.Y()
|
||||
case Ig[T]: // amd64:-".*assertE2I\\(",".*assertE2I2"
|
||||
t.G()
|
||||
}
|
||||
}
|
||||
|
||||
func swCaller() {
|
||||
swGYZ[int]((Ig[int])(nil))
|
||||
swE2G[int]((Ig[int])(nil))
|
||||
swI2G[int]((Ix)(nil))
|
||||
}
|
||||
16
test/codegen/unsafe.go
Normal file
16
test/codegen/unsafe.go
Normal file
@@ -0,0 +1,16 @@
|
||||
// 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
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func f(p unsafe.Pointer, x, y uintptr) int64 {
|
||||
p = unsafe.Pointer(uintptr(p) + x + y)
|
||||
// amd64:`MOVQ\s\(.*\)\(.*\*1\), `
|
||||
// arm64:`MOVD\s\(R[0-9]+\)\(R[0-9]+\), `
|
||||
return *(*int64)(p)
|
||||
}
|
||||
@@ -54,6 +54,16 @@ func combine4slice(p *[4][]byte, a, b, c, d []byte) {
|
||||
p[3] = d
|
||||
}
|
||||
|
||||
func trickyWriteNil(p *int, q **int) {
|
||||
if p == nil {
|
||||
// We change "= p" to "= 0" in the prove pass, which
|
||||
// means we have one less pointer that needs to go
|
||||
// into the write barrier buffer.
|
||||
// amd64:`.*runtime[.]gcWriteBarrier1`
|
||||
*q = p
|
||||
}
|
||||
}
|
||||
|
||||
type S struct {
|
||||
a, b string
|
||||
c *int
|
||||
|
||||
@@ -84,3 +84,57 @@ label:
|
||||
fmt.Println("defer")
|
||||
}()
|
||||
}
|
||||
|
||||
// Test for function with too many exits, which will disable open-coded defer
|
||||
// even though the number of defer statements is not greater than 8.
|
||||
func f7() {
|
||||
defer println(1) // ERROR "open-coded defer"
|
||||
defer println(1) // ERROR "open-coded defer"
|
||||
defer println(1) // ERROR "open-coded defer"
|
||||
defer println(1) // ERROR "open-coded defer"
|
||||
|
||||
switch glob {
|
||||
case 1:
|
||||
return
|
||||
case 2:
|
||||
return
|
||||
case 3:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func f8() {
|
||||
defer println(1) // ERROR "stack-allocated defer"
|
||||
defer println(1) // ERROR "stack-allocated defer"
|
||||
defer println(1) // ERROR "stack-allocated defer"
|
||||
defer println(1) // ERROR "stack-allocated defer"
|
||||
|
||||
switch glob {
|
||||
case 1:
|
||||
return
|
||||
case 2:
|
||||
return
|
||||
case 3:
|
||||
return
|
||||
case 4:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func f9() {
|
||||
defer println(1) // ERROR "open-coded defer"
|
||||
defer println(1) // ERROR "open-coded defer"
|
||||
defer println(1) // ERROR "open-coded defer"
|
||||
defer println(1) // ERROR "open-coded defer"
|
||||
|
||||
switch glob {
|
||||
case 1:
|
||||
return
|
||||
case 2:
|
||||
return
|
||||
case 3:
|
||||
return
|
||||
case 4:
|
||||
panic("")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ func f1() {
|
||||
// Escape analysis used to miss inlined code in closures.
|
||||
|
||||
func() { // ERROR "can inline f1.func1"
|
||||
p = alloc(3) // ERROR "inlining call to alloc"
|
||||
p = alloc(3) // ERROR "inlining call to alloc" "moved to heap: x"
|
||||
}() // ERROR "inlining call to f1.func1" "inlining call to alloc" "moved to heap: x"
|
||||
|
||||
f = func() { // ERROR "func literal escapes to heap" "can inline f1.func2"
|
||||
|
||||
@@ -134,7 +134,7 @@ func ClosureCallArgs14() {
|
||||
func ClosureCallArgs15() {
|
||||
x := 0 // ERROR "moved to heap: x"
|
||||
p := &x
|
||||
sink = func(p **int) *int { // ERROR "leaking param content: p" "func literal does not escape"
|
||||
sink = func(p **int) *int { // ERROR "leaking param: p to result ~r0 level=1" "func literal does not escape"
|
||||
return *p
|
||||
}(&p)
|
||||
}
|
||||
|
||||
@@ -423,7 +423,7 @@ func mapdelete(m map[string]string, k string) { // ERROR "m does not escape" "le
|
||||
}
|
||||
|
||||
// Unfortunate: v doesn't need to leak.
|
||||
func setiterkey1(v reflect.Value, it *reflect.MapIter) { // ERROR "leaking param: v$" "it does not escape"
|
||||
func setiterkey1(v reflect.Value, it *reflect.MapIter) { // ERROR "leaking param: v$" "leaking param content: it$"
|
||||
v.SetIterKey(it)
|
||||
}
|
||||
|
||||
@@ -434,7 +434,7 @@ func setiterkey2(v reflect.Value, m map[string]string) { // ERROR "leaking param
|
||||
}
|
||||
|
||||
// Unfortunate: v doesn't need to leak.
|
||||
func setitervalue1(v reflect.Value, it *reflect.MapIter) { // ERROR "leaking param: v$" "it does not escape"
|
||||
func setitervalue1(v reflect.Value, it *reflect.MapIter) { // ERROR "leaking param: v$" "leaking param content: it$"
|
||||
v.SetIterValue(it)
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ type I4 interface { // GC_ERROR "invalid recursive type: I4 refers to itself"
|
||||
I4 // GCCGO_ERROR "interface"
|
||||
}
|
||||
|
||||
type I5 interface { // GC_ERROR "invalid recursive type I5\n\tLINE:.* I5 refers to\n\tLINE+4:.* I6 refers to\n\tLINE:.* I5$"
|
||||
type I5 interface { // GC_ERROR "invalid recursive type I5\n\tLINE:.* I5 refers to I6\n\tLINE+4:.* I6 refers to I5$"
|
||||
I6
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@
|
||||
package main
|
||||
import "runtime"
|
||||
|
||||
func foo(runtime.UintType, i int) { // ERROR "cannot declare name runtime.UintType|mixed named and unnamed|undefined identifier"
|
||||
func foo(runtime.UintType, i int) { // ERROR "cannot declare name runtime.UintType|missing parameter name|undefined identifier"
|
||||
println(i, runtime.UintType) // GCCGO_ERROR "undefined identifier"
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
package a
|
||||
var? // ERROR "invalid character U\+003F '\?'|invalid character 0x3f in input file"
|
||||
|
||||
var x int // ERROR "unexpected var|expected identifier|expected type"
|
||||
var x int // ERROR "unexpected keyword var|expected identifier|expected type"
|
||||
|
||||
func main() {
|
||||
}
|
||||
|
||||
79
test/fixedbugs/issue16241.go
Normal file
79
test/fixedbugs/issue16241.go
Normal file
@@ -0,0 +1,79 @@
|
||||
// errorcheck -0 -m -l
|
||||
|
||||
// Copyright 2023 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 foo
|
||||
|
||||
import "sync/atomic"
|
||||
|
||||
func AddInt32(x *int32) { // ERROR "x does not escape$"
|
||||
atomic.AddInt32(x, 42)
|
||||
}
|
||||
func AddUint32(x *uint32) { // ERROR "x does not escape$"
|
||||
atomic.AddUint32(x, 42)
|
||||
}
|
||||
func AddUintptr(x *uintptr) { // ERROR "x does not escape$"
|
||||
atomic.AddUintptr(x, 42)
|
||||
}
|
||||
|
||||
func AndInt32(x *int32) { // ERROR "x does not escape$"
|
||||
atomic.AndInt32(x, 42)
|
||||
}
|
||||
func AndUint32(x *uint32) { // ERROR "x does not escape$"
|
||||
atomic.AndUint32(x, 42)
|
||||
}
|
||||
func AndUintptr(x *uintptr) { // ERROR "x does not escape$"
|
||||
atomic.AndUintptr(x, 42)
|
||||
}
|
||||
|
||||
func CompareAndSwapInt32(x *int32) { // ERROR "x does not escape$"
|
||||
atomic.CompareAndSwapInt32(x, 42, 42)
|
||||
}
|
||||
func CompareAndSwapUint32(x *uint32) { // ERROR "x does not escape$"
|
||||
atomic.CompareAndSwapUint32(x, 42, 42)
|
||||
}
|
||||
func CompareAndSwapUintptr(x *uintptr) { // ERROR "x does not escape$"
|
||||
atomic.CompareAndSwapUintptr(x, 42, 42)
|
||||
}
|
||||
|
||||
func LoadInt32(x *int32) { // ERROR "x does not escape$"
|
||||
atomic.LoadInt32(x)
|
||||
}
|
||||
func LoadUint32(x *uint32) { // ERROR "x does not escape$"
|
||||
atomic.LoadUint32(x)
|
||||
}
|
||||
func LoadUintptr(x *uintptr) { // ERROR "x does not escape$"
|
||||
atomic.LoadUintptr(x)
|
||||
}
|
||||
|
||||
func OrInt32(x *int32) { // ERROR "x does not escape$"
|
||||
atomic.OrInt32(x, 42)
|
||||
}
|
||||
func OrUint32(x *uint32) { // ERROR "x does not escape$"
|
||||
atomic.OrUint32(x, 42)
|
||||
}
|
||||
func OrUintptr(x *uintptr) { // ERROR "x does not escape$"
|
||||
atomic.OrUintptr(x, 42)
|
||||
}
|
||||
|
||||
func StoreInt32(x *int32) { // ERROR "x does not escape$"
|
||||
atomic.StoreInt32(x, 42)
|
||||
}
|
||||
func StoreUint32(x *uint32) { // ERROR "x does not escape$"
|
||||
atomic.StoreUint32(x, 42)
|
||||
}
|
||||
func StoreUintptr(x *uintptr) { // ERROR "x does not escape$"
|
||||
atomic.StoreUintptr(x, 42)
|
||||
}
|
||||
|
||||
func SwapInt32(x *int32) { // ERROR "x does not escape$"
|
||||
atomic.SwapInt32(x, 42)
|
||||
}
|
||||
func SwapUint32(x *uint32) { // ERROR "x does not escape$"
|
||||
atomic.SwapUint32(x, 42)
|
||||
}
|
||||
func SwapUintptr(x *uintptr) { // ERROR "x does not escape$"
|
||||
atomic.SwapUintptr(x, 42)
|
||||
}
|
||||
60
test/fixedbugs/issue16241_64.go
Normal file
60
test/fixedbugs/issue16241_64.go
Normal file
@@ -0,0 +1,60 @@
|
||||
//go:build !(386 || arm || mips || mipsle)
|
||||
|
||||
// errorcheck -0 -m -l
|
||||
|
||||
// Copyright 2023 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 foo
|
||||
|
||||
import "sync/atomic"
|
||||
|
||||
func AddInt64(x *int64) { // ERROR "x does not escape$"
|
||||
atomic.AddInt64(x, 42)
|
||||
}
|
||||
func AddUint64(x *uint64) { // ERROR "x does not escape$"
|
||||
atomic.AddUint64(x, 42)
|
||||
}
|
||||
|
||||
func AndInt64(x *int64) { // ERROR "x does not escape$"
|
||||
atomic.AndInt64(x, 42)
|
||||
}
|
||||
func AndUint64(x *uint64) { // ERROR "x does not escape$"
|
||||
atomic.AndUint64(x, 42)
|
||||
}
|
||||
|
||||
func CompareAndSwapInt64(x *int64) { // ERROR "x does not escape$"
|
||||
atomic.CompareAndSwapInt64(x, 42, 42)
|
||||
}
|
||||
func CompareAndSwapUint64(x *uint64) { // ERROR "x does not escape$"
|
||||
atomic.CompareAndSwapUint64(x, 42, 42)
|
||||
}
|
||||
|
||||
func LoadInt64(x *int64) { // ERROR "x does not escape$"
|
||||
atomic.LoadInt64(x)
|
||||
}
|
||||
func LoadUint64(x *uint64) { // ERROR "x does not escape$"
|
||||
atomic.LoadUint64(x)
|
||||
}
|
||||
|
||||
func OrInt64(x *int64) { // ERROR "x does not escape$"
|
||||
atomic.OrInt64(x, 42)
|
||||
}
|
||||
func OrUint64(x *uint64) { // ERROR "x does not escape$"
|
||||
atomic.OrUint64(x, 42)
|
||||
}
|
||||
|
||||
func StoreInt64(x *int64) { // ERROR "x does not escape$"
|
||||
atomic.StoreInt64(x, 42)
|
||||
}
|
||||
func StoreUint64(x *uint64) { // ERROR "x does not escape$"
|
||||
atomic.StoreUint64(x, 42)
|
||||
}
|
||||
|
||||
func SwapInt64(x *int64) { // ERROR "x does not escape$"
|
||||
atomic.SwapInt64(x, 42)
|
||||
}
|
||||
func SwapUint64(x *uint64) { // ERROR "x does not escape$"
|
||||
atomic.SwapUint64(x, 42)
|
||||
}
|
||||
13
test/fixedbugs/issue20027.go
Normal file
13
test/fixedbugs/issue20027.go
Normal file
@@ -0,0 +1,13 @@
|
||||
// errorcheck
|
||||
|
||||
// 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 p
|
||||
|
||||
var _ chan [0x2FFFF]byte // ERROR "channel element type too large"
|
||||
var _ = make(chan [0x2FFFF]byte) // ERROR "channel element type too large"
|
||||
|
||||
var c1 chan [0x2FFFF]byte // ERROR "channel element type too large"
|
||||
var c2 = make(chan [0x2FFFF]byte) // ERROR "channel element type too large"
|
||||
19
test/fixedbugs/issue24755.go
Normal file
19
test/fixedbugs/issue24755.go
Normal file
@@ -0,0 +1,19 @@
|
||||
// errorcheck
|
||||
|
||||
// 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 p
|
||||
|
||||
type I interface {
|
||||
F()
|
||||
}
|
||||
|
||||
type T struct {
|
||||
}
|
||||
|
||||
const _ = I((*T)(nil)) // ERROR "is not constant"
|
||||
|
||||
func (*T) F() {
|
||||
}
|
||||
@@ -27,3 +27,12 @@ func z() {
|
||||
z := t{&i}.f // ERROR "t{...}.f escapes to heap"
|
||||
z()
|
||||
}
|
||||
|
||||
// Should match cmd/compile/internal/ir/cfg.go:MaxStackVarSize.
|
||||
const maxStack = 128 * 1024
|
||||
|
||||
func w(i int) byte {
|
||||
var x [maxStack]byte
|
||||
var y [maxStack + 1]byte // ERROR "moved to heap: y"
|
||||
return x[i] + y[i]
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
package p
|
||||
|
||||
type T1 struct { // ERROR "invalid recursive type T1\n\tLINE: T1 refers to\n\tLINE+4: T2 refers to\n\tLINE: T1$|invalid recursive type"
|
||||
type T1 struct { // ERROR "invalid recursive type T1\n.*T1 refers to T2\n.*T2 refers to T1|invalid recursive type"
|
||||
f2 T2
|
||||
}
|
||||
|
||||
@@ -15,21 +15,21 @@ type T2 struct { // GCCGO_ERROR "invalid recursive type"
|
||||
}
|
||||
|
||||
type a b // GCCGO_ERROR "invalid recursive type"
|
||||
type b c // ERROR "invalid recursive type b\n\tLINE: b refers to\n\tLINE+1: c refers to\n\tLINE: b$|invalid recursive type"
|
||||
type b c // ERROR "invalid recursive type b\n.*b refers to c\n.*c refers to b|invalid recursive type|invalid recursive type"
|
||||
type c b // GCCGO_ERROR "invalid recursive type"
|
||||
|
||||
type d e
|
||||
type e f
|
||||
type f f // ERROR "invalid recursive type f\n\tLINE: f refers to\n\tLINE: f$|invalid recursive type"
|
||||
type f f // ERROR "invalid recursive type: f refers to itself|invalid recursive type|invalid recursive type"
|
||||
|
||||
type g struct { // ERROR "invalid recursive type g\n\tLINE: g refers to\n\tLINE: g$|invalid recursive type"
|
||||
type g struct { // ERROR "invalid recursive type: g refers to itself|invalid recursive type"
|
||||
h struct {
|
||||
g
|
||||
}
|
||||
}
|
||||
|
||||
type w x
|
||||
type x y // ERROR "invalid recursive type x\n\tLINE: x refers to\n\tLINE+1: y refers to\n\tLINE+2: z refers to\n\tLINE: x$|invalid recursive type"
|
||||
type x y // ERROR "invalid recursive type x\n.*x refers to y\n.*y refers to z\n.*z refers to x|invalid recursive type"
|
||||
type y struct{ z } // GCCGO_ERROR "invalid recursive type"
|
||||
type z [10]x
|
||||
|
||||
|
||||
@@ -51,6 +51,6 @@ func g() {
|
||||
_ = i.(T6) // ERROR "impossible type assertion: i.\(T6\)\n\tT6 does not implement I \(missing method M\)\n\t\thave m\(int\) string\n\t\twant M\(int\)"
|
||||
|
||||
var t *T4
|
||||
t = i // ERROR "cannot use i \(variable of type I\) as \*T4 value in assignment: need type assertion"
|
||||
t = i // ERROR "cannot use i \(variable of interface type I\) as \*T4 value in assignment: need type assertion"
|
||||
_ = t
|
||||
}
|
||||
|
||||
@@ -6,4 +6,4 @@ package b
|
||||
|
||||
import "./a"
|
||||
|
||||
type T a.T[T] // ERROR "invalid recursive type T\n.*T refers to\n.*a\.T refers to\n.*T"
|
||||
type T a.T[T] // ERROR "invalid recursive type T\n.*T refers to a\.T\n.*a\.T refers to T"
|
||||
|
||||
@@ -6,27 +6,6 @@
|
||||
|
||||
package p
|
||||
|
||||
import (
|
||||
"crypto/ecdh"
|
||||
"crypto/rand"
|
||||
)
|
||||
|
||||
func F(peerShare []byte) ([]byte, error) { // ERROR "leaking param: peerShare"
|
||||
p256 := ecdh.P256() // ERROR "inlining call to ecdh.P256"
|
||||
|
||||
ourKey, err := p256.GenerateKey(rand.Reader) // ERROR "devirtualizing p256.GenerateKey" "inlining call to ecdh.*GenerateKey"
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
peerPublic, err := p256.NewPublicKey(peerShare) // ERROR "devirtualizing p256.NewPublicKey" "inlining call to ecdh.*NewPublicKey"
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ourKey.ECDH(peerPublic)
|
||||
}
|
||||
|
||||
// Test that inlining doesn't break if devirtualization exposes a new
|
||||
// inlinable callee.
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ func run() { // ERROR "cannot inline run: recursive"
|
||||
g() // ERROR "inlining call to g"
|
||||
}
|
||||
f() // ERROR "inlining call to run.func1" "inlining call to g"
|
||||
_ = f
|
||||
run()
|
||||
}
|
||||
|
||||
|
||||
27
test/fixedbugs/issue67329.go
Normal file
27
test/fixedbugs/issue67329.go
Normal file
@@ -0,0 +1,27 @@
|
||||
// errorcheck -0 -d=ssa/check_bce/debug=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.
|
||||
|
||||
package x
|
||||
|
||||
func Found(x []string) string {
|
||||
switch len(x) {
|
||||
default:
|
||||
return x[0]
|
||||
case 0, 1:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func NotFound(x []string) string {
|
||||
switch len(x) {
|
||||
default:
|
||||
return x[0]
|
||||
case 0:
|
||||
return ""
|
||||
case 1:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
12
test/fixedbugs/issue68292.go
Normal file
12
test/fixedbugs/issue68292.go
Normal file
@@ -0,0 +1,12 @@
|
||||
// errorcheck
|
||||
|
||||
// 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 main
|
||||
|
||||
func f[S any, T any](T) {}
|
||||
func g() {
|
||||
f(0) // ERROR "in call to f, cannot infer S \(declared at issue68292.go:9:8\)"
|
||||
}
|
||||
16
test/fixedbugs/issue68526.dir/a/a.go
Normal file
16
test/fixedbugs/issue68526.dir/a/a.go
Normal file
@@ -0,0 +1,16 @@
|
||||
// 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.
|
||||
|
||||
//go:build goexperiment.aliastypeparams
|
||||
|
||||
package a
|
||||
|
||||
type A[T any] = struct{ F T }
|
||||
|
||||
type B = struct{ F int }
|
||||
|
||||
func F() B {
|
||||
type a[T any] = struct{ F T }
|
||||
return a[int]{}
|
||||
}
|
||||
45
test/fixedbugs/issue68526.dir/main.go
Normal file
45
test/fixedbugs/issue68526.dir/main.go
Normal file
@@ -0,0 +1,45 @@
|
||||
// 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.
|
||||
|
||||
//go:build goexperiment.aliastypeparams
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"issue68526.dir/a"
|
||||
)
|
||||
|
||||
func main() {
|
||||
unexported()
|
||||
exported()
|
||||
}
|
||||
|
||||
func unexported() {
|
||||
var want struct{ F int }
|
||||
|
||||
if any(want) != any(a.B{}) || any(want) != any(a.F()) {
|
||||
panic("zero value of alias and concrete type not identical")
|
||||
}
|
||||
}
|
||||
|
||||
func exported() {
|
||||
var (
|
||||
astr a.A[string]
|
||||
aint a.A[int]
|
||||
)
|
||||
|
||||
if any(astr) != any(struct{ F string }{}) || any(aint) != any(struct{ F int }{}) {
|
||||
panic("zero value of alias and concrete type not identical")
|
||||
}
|
||||
|
||||
if any(astr) == any(aint) {
|
||||
panic("zero value of struct{ F string } and struct{ F int } are not distinct")
|
||||
}
|
||||
|
||||
if got := fmt.Sprintf("%T", astr); got != "struct { F string }" {
|
||||
panic(got)
|
||||
}
|
||||
}
|
||||
7
test/fixedbugs/issue68526.go
Normal file
7
test/fixedbugs/issue68526.go
Normal file
@@ -0,0 +1,7 @@
|
||||
// runindir -goexperiment aliastypeparams -gomodversion "1.23"
|
||||
|
||||
// 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 ignored
|
||||
17
test/fixedbugs/issue68734.go
Normal file
17
test/fixedbugs/issue68734.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.
|
||||
|
||||
// The gofrontend had a bug handling panic of an untyped constant expression.
|
||||
|
||||
package issue68734
|
||||
|
||||
func F1() {
|
||||
panic(1 + 2)
|
||||
}
|
||||
|
||||
func F2() {
|
||||
panic("a" + "b")
|
||||
}
|
||||
19
test/fixedbugs/issue68809.go
Normal file
19
test/fixedbugs/issue68809.go
Normal file
@@ -0,0 +1,19 @@
|
||||
// run
|
||||
|
||||
// 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 main
|
||||
|
||||
func main() {
|
||||
cnt := 0
|
||||
for i := 1; i <= 11; i++ {
|
||||
if i-6 > 4 {
|
||||
cnt++
|
||||
}
|
||||
}
|
||||
if cnt != 1 {
|
||||
panic("bad")
|
||||
}
|
||||
}
|
||||
41
test/fixedbugs/issue68816.go
Normal file
41
test/fixedbugs/issue68816.go
Normal file
@@ -0,0 +1,41 @@
|
||||
// run
|
||||
|
||||
// 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 main
|
||||
|
||||
func main() {
|
||||
mustPanic(func() {
|
||||
f1(1)
|
||||
})
|
||||
f2(1, 0) // must not panic
|
||||
mustPanic(func() {
|
||||
f2(1, 2)
|
||||
})
|
||||
}
|
||||
|
||||
var v []func()
|
||||
|
||||
//go:noinline
|
||||
func f1(i int) {
|
||||
v = make([]func(), -2|i)
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func f2(i, j int) {
|
||||
if j > 0 {
|
||||
v = make([]func(), -2|i)
|
||||
}
|
||||
}
|
||||
|
||||
func mustPanic(f func()) {
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r == nil {
|
||||
panic("didn't panic")
|
||||
}
|
||||
}()
|
||||
f()
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
// run
|
||||
|
||||
//go:build !goexperiment.swissmap
|
||||
|
||||
// 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.
|
||||
|
||||
@@ -7,167 +7,55 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"iter"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// WordReader is the struct that implements io.Reader
|
||||
type WordReader struct {
|
||||
scanner *bufio.Scanner
|
||||
}
|
||||
|
||||
// NewWordReader creates a new WordReader from an io.Reader
|
||||
func NewWordReader(r io.Reader) *WordReader {
|
||||
scanner := bufio.NewScanner(r)
|
||||
scanner.Split(bufio.ScanWords)
|
||||
return &WordReader{
|
||||
scanner: scanner,
|
||||
}
|
||||
}
|
||||
|
||||
// Read reads data from the input stream and returns a single lowercase word at a time
|
||||
func (wr *WordReader) Read(p []byte) (n int, err error) {
|
||||
if !wr.scanner.Scan() {
|
||||
if err := wr.scanner.Err(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return 0, io.EOF
|
||||
}
|
||||
word := wr.scanner.Text()
|
||||
cleanedWord := removeNonAlphabetic(word)
|
||||
if len(cleanedWord) == 0 {
|
||||
return wr.Read(p)
|
||||
}
|
||||
n = copy(p, []byte(cleanedWord))
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// All returns an iterator allowing the caller to iterate over the WordReader using for/range.
|
||||
func (wr *WordReader) All() iter.Seq[string] {
|
||||
word := make([]byte, 1024)
|
||||
return func(yield func(string) bool) {
|
||||
var err error
|
||||
var n int
|
||||
for n, err = wr.Read(word); err == nil; n, err = wr.Read(word) {
|
||||
if !yield(string(word[:n])) {
|
||||
func All() iter.Seq[int] {
|
||||
return func(yield func(int) bool) {
|
||||
for i := 0; i < 10; i++ {
|
||||
growStack(512)
|
||||
if !yield(i) {
|
||||
return
|
||||
}
|
||||
}
|
||||
if err != io.EOF {
|
||||
fmt.Fprintf(os.Stderr, "error reading word: %v\n", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// removeNonAlphabetic removes non-alphabetic characters from a word using strings.Map
|
||||
func removeNonAlphabetic(word string) string {
|
||||
return strings.Map(func(r rune) rune {
|
||||
if unicode.IsLetter(r) {
|
||||
return unicode.ToLower(r)
|
||||
}
|
||||
return -1
|
||||
}, word)
|
||||
type S struct {
|
||||
round int
|
||||
}
|
||||
|
||||
// ProbabilisticSkipper determines if an item should be retained with probability 1/(1<<n)
|
||||
type ProbabilisticSkipper struct {
|
||||
n int
|
||||
counter uint64
|
||||
bitmask uint64
|
||||
func NewS(round int) *S {
|
||||
s := &S{round: round}
|
||||
return s
|
||||
}
|
||||
|
||||
// NewProbabilisticSkipper initializes the ProbabilisticSkipper
|
||||
func NewProbabilisticSkipper(n int) *ProbabilisticSkipper {
|
||||
pr := &ProbabilisticSkipper{n: n}
|
||||
pr.refreshCounter()
|
||||
return pr
|
||||
}
|
||||
|
||||
// check panics if pr.n is not the expected value
|
||||
func (pr *ProbabilisticSkipper) check(n int) {
|
||||
if pr.n != n {
|
||||
panic(fmt.Sprintf("check: pr.n != n %d != %d", pr.n, n))
|
||||
func (s *S) check(round int) {
|
||||
if s.round != round {
|
||||
panic("bad round")
|
||||
}
|
||||
}
|
||||
|
||||
// refreshCounter refreshes the counter with a new random value
|
||||
func (pr *ProbabilisticSkipper) refreshCounter() {
|
||||
if pr.n == 0 {
|
||||
pr.bitmask = ^uint64(0) // All bits set to 1
|
||||
} else {
|
||||
pr.bitmask = rand.Uint64()
|
||||
for i := 0; i < pr.n-1; i++ {
|
||||
pr.bitmask &= rand.Uint64()
|
||||
}
|
||||
}
|
||||
pr.counter = 64
|
||||
}
|
||||
|
||||
// ShouldSkip returns true with probability 1/(1<<n)
|
||||
func (pr *ProbabilisticSkipper) ShouldSkip() bool {
|
||||
remove := pr.bitmask&1 == 0
|
||||
pr.bitmask >>= 1
|
||||
pr.counter--
|
||||
if pr.counter == 0 {
|
||||
pr.refreshCounter()
|
||||
}
|
||||
return remove
|
||||
}
|
||||
|
||||
// EstimateUniqueWordsIter estimates the number of unique words using a probabilistic counting method
|
||||
func EstimateUniqueWordsIter(reader io.Reader, memorySize int) int {
|
||||
wordReader := NewWordReader(reader)
|
||||
words := make(map[string]struct{}, memorySize)
|
||||
|
||||
func f() {
|
||||
rounds := 0
|
||||
roundRemover := NewProbabilisticSkipper(1)
|
||||
wordSkipper := NewProbabilisticSkipper(rounds)
|
||||
wordSkipper.check(rounds)
|
||||
s := NewS(rounds)
|
||||
s.check(rounds)
|
||||
|
||||
for word := range wordReader.All() {
|
||||
wordSkipper.check(rounds)
|
||||
if wordSkipper.ShouldSkip() {
|
||||
delete(words, word)
|
||||
} else {
|
||||
words[word] = struct{}{}
|
||||
|
||||
if len(words) >= memorySize {
|
||||
rounds++
|
||||
|
||||
wordSkipper = NewProbabilisticSkipper(rounds)
|
||||
for w := range words {
|
||||
if roundRemover.ShouldSkip() {
|
||||
delete(words, w)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
wordSkipper.check(rounds)
|
||||
for range All() {
|
||||
s.check(rounds)
|
||||
rounds++
|
||||
s = NewS(rounds)
|
||||
s.check(rounds)
|
||||
}
|
||||
}
|
||||
|
||||
if len(words) == 0 {
|
||||
return 0
|
||||
func growStack(i int) {
|
||||
if i == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
invProbability := 1 << rounds
|
||||
estimatedUniqueWords := len(words) * invProbability
|
||||
return estimatedUniqueWords
|
||||
growStack(i - 1)
|
||||
}
|
||||
|
||||
func main() {
|
||||
input := "Hello, world! This is a test. Hello, world, hello!"
|
||||
expectedUniqueWords := 6 // "hello", "world", "this", "is", "a", "test" (but "hello" and "world" are repeated)
|
||||
memorySize := 6
|
||||
|
||||
reader := strings.NewReader(input)
|
||||
estimatedUniqueWords := EstimateUniqueWordsIter(reader, memorySize)
|
||||
if estimatedUniqueWords != expectedUniqueWords {
|
||||
// ...
|
||||
}
|
||||
f()
|
||||
}
|
||||
|
||||
18
test/fixedbugs/issue69825.go
Normal file
18
test/fixedbugs/issue69825.go
Normal file
@@ -0,0 +1,18 @@
|
||||
// compile -d=libfuzzer
|
||||
|
||||
// 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 main
|
||||
|
||||
type T struct {
|
||||
A
|
||||
}
|
||||
|
||||
type A struct {
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func (a *A) Foo(s [2]string) {
|
||||
}
|
||||
23
test/fixedbugs/issue70156.go
Normal file
23
test/fixedbugs/issue70156.go
Normal file
@@ -0,0 +1,23 @@
|
||||
// run
|
||||
|
||||
// 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 main
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func main() {
|
||||
pi := new(interface{})
|
||||
v := reflect.ValueOf(pi).Elem()
|
||||
if v.Kind() != reflect.Interface {
|
||||
panic(0)
|
||||
}
|
||||
if (v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface) && v.IsNil() {
|
||||
return
|
||||
}
|
||||
panic(1)
|
||||
}
|
||||
17
test/fixedbugs/issue70175.go
Normal file
17
test/fixedbugs/issue70175.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 main
|
||||
|
||||
func f() {
|
||||
_:
|
||||
|
||||
_:
|
||||
}
|
||||
|
||||
func main() {
|
||||
f()
|
||||
}
|
||||
38
test/fixedbugs/issue70189.go
Normal file
38
test/fixedbugs/issue70189.go
Normal file
@@ -0,0 +1,38 @@
|
||||
// run -goexperiment noswissmap
|
||||
|
||||
// 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 main
|
||||
|
||||
func nan() float64 {
|
||||
var x, y float64
|
||||
return x / y
|
||||
}
|
||||
|
||||
func main() {
|
||||
m := map[float64]int{}
|
||||
|
||||
// Make a small map with nan keys
|
||||
for i := 0; i < 8; i++ {
|
||||
m[nan()] = i
|
||||
}
|
||||
|
||||
// Start iterating on it.
|
||||
start := true
|
||||
for _, v := range m {
|
||||
if start {
|
||||
// Add some more elements.
|
||||
for i := 0; i < 10; i++ {
|
||||
m[float64(i)] = i
|
||||
}
|
||||
// Now clear the map.
|
||||
clear(m)
|
||||
start = false
|
||||
} else {
|
||||
// We should never reach here.
|
||||
panic(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
20
test/fixedbugs/issue70481.go
Normal file
20
test/fixedbugs/issue70481.go
Normal file
@@ -0,0 +1,20 @@
|
||||
// run
|
||||
|
||||
// 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 main
|
||||
|
||||
const maxUint64 = (1 << 64) - 1
|
||||
|
||||
//go:noinline
|
||||
func f(n uint64) uint64 {
|
||||
return maxUint64 - maxUint64%n
|
||||
}
|
||||
|
||||
func main() {
|
||||
for i := uint64(1); i < 20; i++ {
|
||||
println(i, maxUint64-f(i))
|
||||
}
|
||||
}
|
||||
19
test/fixedbugs/issue70481.out
Normal file
19
test/fixedbugs/issue70481.out
Normal file
@@ -0,0 +1,19 @@
|
||||
1 0
|
||||
2 1
|
||||
3 0
|
||||
4 3
|
||||
5 0
|
||||
6 3
|
||||
7 1
|
||||
8 7
|
||||
9 6
|
||||
10 5
|
||||
11 4
|
||||
12 3
|
||||
13 2
|
||||
14 1
|
||||
15 0
|
||||
16 15
|
||||
17 0
|
||||
18 15
|
||||
19 16
|
||||
@@ -4,12 +4,15 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Test type-checking errors for go:notinheap.
|
||||
// Test type-checking errors for not-in-heap types.
|
||||
|
||||
//go:build cgo
|
||||
|
||||
package p
|
||||
|
||||
//go:notinheap
|
||||
type nih struct{}
|
||||
import "runtime/cgo"
|
||||
|
||||
type nih struct{ _ cgo.Incomplete }
|
||||
|
||||
type embed4 map[nih]int // ERROR "incomplete \(or unallocatable\) map key not allowed"
|
||||
|
||||
@@ -27,25 +30,8 @@ type okay4 interface {
|
||||
f(x nih) nih
|
||||
}
|
||||
|
||||
// Type conversions don't let you sneak past notinheap.
|
||||
|
||||
type t1 struct{ x int }
|
||||
|
||||
//go:notinheap
|
||||
type t2 t1
|
||||
|
||||
//go:notinheap
|
||||
type t3 byte
|
||||
|
||||
//go:notinheap
|
||||
type t4 rune
|
||||
|
||||
var sink interface{}
|
||||
|
||||
func i() {
|
||||
sink = new(t1) // no error
|
||||
sink = (*t2)(new(t1)) // ERROR "cannot convert(.|\n)*t2 is incomplete \(or unallocatable\)"
|
||||
sink = (*t2)(new(struct{ x int })) // ERROR "cannot convert(.|\n)*t2 is incomplete \(or unallocatable\)"
|
||||
sink = []t3("foo") // ERROR "cannot convert(.|\n)*t3 is incomplete \(or unallocatable\)"
|
||||
sink = []t4("bar") // ERROR "cannot convert(.|\n)*t4 is incomplete \(or unallocatable\)"
|
||||
func f() {
|
||||
type embed7 map[nih]int // ERROR "incomplete \(or unallocatable\) map key not allowed"
|
||||
type embed8 map[int]nih // ERROR "incomplete \(or unallocatable\) map value not allowed"
|
||||
type emebd9 chan nih // ERROR "chan of incomplete \(or unallocatable\) type not allowed"
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@ type t1 int
|
||||
type t2 int
|
||||
type t3 int
|
||||
|
||||
func f1(*t2, x t3) // ERROR "named"
|
||||
func f2(t1, *t2, x t3) // ERROR "named"
|
||||
func f3() (x int, *string) // ERROR "named"
|
||||
func f1(*t2, x t3) // ERROR "missing parameter name"
|
||||
func f2(t1, *t2, x t3) // ERROR "missing parameter name"
|
||||
func f3() (x int, *string) // ERROR "missing parameter name"
|
||||
|
||||
func f4() (t1 t1) // legal - scope of parameter named t1 starts in body of f4.
|
||||
|
||||
@@ -148,11 +148,11 @@ func fEqInterEqInter(a interface{}, f float64) bool {
|
||||
}
|
||||
|
||||
func fEqInterNeqInter(a interface{}, f float64) bool {
|
||||
return a == nil && f > Cf2 || a != nil && f < -Cf2
|
||||
return a == nil && f > Cf2 || a != nil && f < -Cf2 // ERROR "Redirect IsNonNil based on IsNonNil"
|
||||
}
|
||||
|
||||
func fNeqInterEqInter(a interface{}, f float64) bool {
|
||||
return a != nil && f > Cf2 || a == nil && f < -Cf2
|
||||
return a != nil && f > Cf2 || a == nil && f < -Cf2 // ERROR "Redirect IsNonNil based on IsNonNil"
|
||||
}
|
||||
|
||||
func fNeqInterNeqInter(a interface{}, f float64) bool {
|
||||
@@ -164,11 +164,11 @@ func fEqSliceEqSlice(a []int, f float64) bool {
|
||||
}
|
||||
|
||||
func fEqSliceNeqSlice(a []int, f float64) bool {
|
||||
return a == nil && f > Cf2 || a != nil && f < -Cf2
|
||||
return a == nil && f > Cf2 || a != nil && f < -Cf2 // ERROR "Redirect IsNonNil based on IsNonNil"
|
||||
}
|
||||
|
||||
func fNeqSliceEqSlice(a []int, f float64) bool {
|
||||
return a != nil && f > Cf2 || a == nil && f < -Cf2
|
||||
return a != nil && f > Cf2 || a == nil && f < -Cf2 // ERROR "Redirect IsNonNil based on IsNonNil"
|
||||
}
|
||||
|
||||
func fNeqSliceNeqSlice(a []int, f float64) bool {
|
||||
|
||||
@@ -11,7 +11,7 @@ package main
|
||||
|
||||
var (
|
||||
x int = a
|
||||
a int = b // ERROR "a refers to\n.*b refers to\n.*c refers to\n.*a|initialization loop"
|
||||
a int = b // ERROR "a refers to b\n.*b refers to c\n.*c refers to a|initialization loop"
|
||||
b int = c
|
||||
c int = a
|
||||
)
|
||||
|
||||
@@ -73,6 +73,7 @@ func l(x, y int) (int, int, error) { // ERROR "can inline l"
|
||||
f := e
|
||||
f(nil) // ERROR "inlining call to l.func1"
|
||||
}
|
||||
_ = e // prevent simple deadcode elimination after inlining
|
||||
return y, x, nil
|
||||
}
|
||||
|
||||
@@ -109,6 +110,7 @@ func p() int { // ERROR "can inline p"
|
||||
|
||||
func q(x int) int { // ERROR "can inline q"
|
||||
foo := func() int { return x * 2 } // ERROR "can inline q.func1" "func literal does not escape"
|
||||
_ = foo // prevent simple deadcode elimination after inlining
|
||||
return foo() // ERROR "inlining call to q.func1"
|
||||
}
|
||||
|
||||
@@ -121,6 +123,8 @@ func r(z int) int {
|
||||
return 2*y + x*z
|
||||
}(x) // ERROR "inlining call to r.func2.1"
|
||||
}
|
||||
_, _ = foo, bar // prevent simple deadcode elimination after inlining
|
||||
|
||||
return foo(42) + bar(42) // ERROR "inlining call to r.func1" "inlining call to r.func2" "inlining call to r.r.func2.func3"
|
||||
}
|
||||
|
||||
@@ -128,7 +132,8 @@ func s0(x int) int { // ERROR "can inline s0"
|
||||
foo := func() { // ERROR "can inline s0.func1" "func literal does not escape"
|
||||
x = x + 1
|
||||
}
|
||||
foo() // ERROR "inlining call to s0.func1"
|
||||
foo() // ERROR "inlining call to s0.func1"
|
||||
_ = foo // prevent simple deadcode elimination after inlining
|
||||
return x
|
||||
}
|
||||
|
||||
@@ -137,6 +142,7 @@ func s1(x int) int { // ERROR "can inline s1"
|
||||
return x
|
||||
}
|
||||
x = x + 1
|
||||
_ = foo // prevent simple deadcode elimination after inlining
|
||||
return foo() // ERROR "inlining call to s1.func1"
|
||||
}
|
||||
|
||||
|
||||
37
test/inline_testingbloop.go
Normal file
37
test/inline_testingbloop.go
Normal file
@@ -0,0 +1,37 @@
|
||||
// errorcheck -0 -m=2
|
||||
|
||||
// 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 no inlining of function calls in testing.B.Loop.
|
||||
// See issue #61515.
|
||||
|
||||
package foo
|
||||
|
||||
import "testing"
|
||||
|
||||
func caninline(x int) int { // ERROR "can inline caninline"
|
||||
return x
|
||||
}
|
||||
|
||||
func cannotinline(b *testing.B) { // ERROR "b does not escape" "cannot inline cannotinline.*"
|
||||
for i := 0; i < b.N; i++ {
|
||||
caninline(1) // ERROR "inlining call to caninline"
|
||||
}
|
||||
for b.Loop() { // ERROR "skip inlining within testing.B.loop" "inlining call to testing\.\(\*B\)\.Loop"
|
||||
caninline(1)
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
caninline(1) // ERROR "inlining call to caninline"
|
||||
}
|
||||
for b.Loop() { // ERROR "skip inlining within testing.B.loop" "inlining call to testing\.\(\*B\)\.Loop"
|
||||
caninline(1)
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
caninline(1) // ERROR "inlining call to caninline"
|
||||
}
|
||||
for b.Loop() { // ERROR "skip inlining within testing.B.loop" "inlining call to testing\.\(\*B\)\.Loop"
|
||||
caninline(1)
|
||||
}
|
||||
}
|
||||
7
test/internal/runtime/sys/README
Normal file
7
test/internal/runtime/sys/README
Normal file
@@ -0,0 +1,7 @@
|
||||
// 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.
|
||||
|
||||
The internal/runtime/sys directory contains tests that specifically need to be
|
||||
compiled as-if in the internal/runtime/sys package. For error-check tests,
|
||||
these require the additional flags -+ and -p=internal/runtime/sys.
|
||||
@@ -1,19 +1,19 @@
|
||||
// errorcheck -0 -+ -p=runtime -m
|
||||
// errorcheck -0 -+ -p=internal/runtime/sys -m
|
||||
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// 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 runtime
|
||||
package sys
|
||||
|
||||
// A function that calls runtime.getcallerpc or runtime.getcallersp()
|
||||
// A function that calls sys.GetCallerPC or sys.GetCallerSP
|
||||
// cannot be inlined, no matter how small it is.
|
||||
|
||||
func getcallerpc() uintptr
|
||||
func getcallersp() uintptr
|
||||
func GetCallerPC() uintptr
|
||||
func GetCallerSP() uintptr
|
||||
|
||||
func pc() uintptr {
|
||||
return getcallerpc() + 1
|
||||
return GetCallerPC() + 1
|
||||
}
|
||||
|
||||
func cpc() uintptr { // ERROR "can inline cpc"
|
||||
@@ -21,7 +21,7 @@ func cpc() uintptr { // ERROR "can inline cpc"
|
||||
}
|
||||
|
||||
func sp() uintptr {
|
||||
return getcallersp() + 3
|
||||
return GetCallerSP() + 3
|
||||
}
|
||||
|
||||
func csp() uintptr { // ERROR "can inline csp"
|
||||
@@ -6,7 +6,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
T "runtime/internal/sys"
|
||||
T "internal/runtime/sys"
|
||||
)
|
||||
|
||||
var A = []uint64{0x0102030405060708, 0x1122334455667788}
|
||||
|
||||
20
test/live.go
20
test/live.go
@@ -458,14 +458,14 @@ func f28(b bool) {
|
||||
|
||||
func f29(b bool) {
|
||||
if b {
|
||||
for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ runtime.hiter$"
|
||||
for k := range m { // ERROR "live at call to (mapiterinit|mapIterStart): .autotmp_[0-9]+$" "live at call to (mapiternext|mapIterNext): .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ (runtime.hiter|internal/runtime/maps.Iter)$"
|
||||
printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$"
|
||||
}
|
||||
}
|
||||
for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$"
|
||||
for k := range m { // ERROR "live at call to (mapiterinit|mapIterStart): .autotmp_[0-9]+$" "live at call to (mapiternext|mapIterNext): .autotmp_[0-9]+$"
|
||||
printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$"
|
||||
}
|
||||
for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$"
|
||||
for k := range m { // ERROR "live at call to (mapiterinit|mapIterStart): .autotmp_[0-9]+$" "live at call to (mapiternext|mapIterNext): .autotmp_[0-9]+$"
|
||||
printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$"
|
||||
}
|
||||
}
|
||||
@@ -659,15 +659,9 @@ func newT40() *T40 {
|
||||
return &ret
|
||||
}
|
||||
|
||||
func bad40() {
|
||||
t := newT40()
|
||||
_ = t
|
||||
printnl()
|
||||
}
|
||||
|
||||
func good40() {
|
||||
ret := T40{} // ERROR "stack object ret T40$"
|
||||
ret.m = make(map[int]int) // ERROR "live at call to rand32: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ runtime.hmap$"
|
||||
ret.m = make(map[int]int) // ERROR "live at call to rand(32)?: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ (runtime.hmap|internal/runtime/maps.Map)$"
|
||||
t := &ret
|
||||
printnl() // ERROR "live at call to printnl: ret$"
|
||||
// Note: ret is live at the printnl because the compiler moves &ret
|
||||
@@ -675,6 +669,12 @@ func good40() {
|
||||
useT40(t)
|
||||
}
|
||||
|
||||
func bad40() {
|
||||
t := newT40()
|
||||
_ = t
|
||||
printnl()
|
||||
}
|
||||
|
||||
func ddd1(x, y *int) { // ERROR "live at entry to ddd1: x y$"
|
||||
ddd2(x, y) // ERROR "stack object .autotmp_[0-9]+ \[2\]\*int$"
|
||||
printnl()
|
||||
|
||||
@@ -27,14 +27,14 @@ func newT40() *T40 {
|
||||
}
|
||||
|
||||
func bad40() {
|
||||
t := newT40() // ERROR "stack object ret T40$" "stack object .autotmp_[0-9]+ runtime.hmap$"
|
||||
t := newT40() // ERROR "stack object ret T40$" "stack object .autotmp_[0-9]+ (runtime.hmap|internal/runtime/maps.Map)$"
|
||||
printnl() // ERROR "live at call to printnl: ret$"
|
||||
useT40(t)
|
||||
}
|
||||
|
||||
func good40() {
|
||||
ret := T40{} // ERROR "stack object ret T40$"
|
||||
ret.m = make(map[int]int, 42) // ERROR "stack object .autotmp_[0-9]+ runtime.hmap$"
|
||||
ret.m = make(map[int]int, 42) // ERROR "stack object .autotmp_[0-9]+ (runtime.hmap|internal/runtime/maps.Map)$"
|
||||
t := &ret
|
||||
printnl() // ERROR "live at call to printnl: ret$"
|
||||
useT40(t)
|
||||
|
||||
@@ -278,6 +278,7 @@ func f17b(p *byte) { // ERROR "live at entry to f17b: p$"
|
||||
// key temporary
|
||||
if b {
|
||||
m2s[str()] = p // ERROR "live at call to mapassign_faststr: p$" "live at call to str: p$"
|
||||
|
||||
}
|
||||
m2s[str()] = p // ERROR "live at call to mapassign_faststr: p$" "live at call to str: p$"
|
||||
m2s[str()] = p // ERROR "live at call to mapassign_faststr: p$" "live at call to str: p$"
|
||||
@@ -455,14 +456,14 @@ func f28(b bool) {
|
||||
|
||||
func f29(b bool) {
|
||||
if b {
|
||||
for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ runtime.hiter$"
|
||||
for k := range m { // ERROR "live at call to (mapiterinit|mapIterStart): .autotmp_[0-9]+$" "live at call to (mapiternext|mapIterNext): .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ (runtime.hiter|internal/runtime/maps.Iter)$"
|
||||
printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$"
|
||||
}
|
||||
}
|
||||
for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$"
|
||||
for k := range m { // ERROR "live at call to (mapiterinit|mapIterStart): .autotmp_[0-9]+$" "live at call to (mapiternext|mapIterNext): .autotmp_[0-9]+$"
|
||||
printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$"
|
||||
}
|
||||
for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$"
|
||||
for k := range m { // ERROR "live at call to (mapiterinit|mapIterStart): .autotmp_[0-9]+$" "live at call to (mapiternext|mapIterNext): .autotmp_[0-9]+$"
|
||||
printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$"
|
||||
}
|
||||
}
|
||||
@@ -656,15 +657,9 @@ func newT40() *T40 {
|
||||
return &ret
|
||||
}
|
||||
|
||||
func bad40() {
|
||||
t := newT40()
|
||||
_ = t
|
||||
printnl()
|
||||
}
|
||||
|
||||
func good40() {
|
||||
ret := T40{} // ERROR "stack object ret T40$"
|
||||
ret.m = make(map[int]int) // ERROR "live at call to rand32: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ runtime.hmap$"
|
||||
ret.m = make(map[int]int) // ERROR "live at call to rand(32)?: .autotmp_[0-9]+$" "stack object .autotmp_[0-9]+ (runtime.hmap|internal/runtime/maps.Map)$"
|
||||
t := &ret
|
||||
printnl() // ERROR "live at call to printnl: ret$"
|
||||
// Note: ret is live at the printnl because the compiler moves &ret
|
||||
@@ -672,6 +667,12 @@ func good40() {
|
||||
useT40(t)
|
||||
}
|
||||
|
||||
func bad40() {
|
||||
t := newT40()
|
||||
_ = t
|
||||
printnl()
|
||||
}
|
||||
|
||||
func ddd1(x, y *int) { // ERROR "live at entry to ddd1: x y$"
|
||||
ddd2(x, y) // ERROR "stack object .autotmp_[0-9]+ \[2\]\*int$"
|
||||
printnl()
|
||||
|
||||
@@ -27,7 +27,7 @@ func f0c(a []int) int {
|
||||
x := 0
|
||||
for i := range a { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
|
||||
b := a[:i+1] // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$"
|
||||
x += b[0]
|
||||
x += b[0] // ERROR "(\([0-9]+\) )?Proved IsInBounds$"
|
||||
}
|
||||
return x
|
||||
}
|
||||
@@ -168,7 +168,7 @@ func g2() int {
|
||||
func g3a() {
|
||||
a := "this string has length 25"
|
||||
for i := 0; i < len(a); i += 5 { // ERROR "Induction variable: limits \[0,20\], increment 5$"
|
||||
useString(a[i:]) // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$"
|
||||
useString(a[i:]) // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$"
|
||||
useString(a[:i+3]) // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$"
|
||||
useString(a[:i+5]) // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$"
|
||||
useString(a[:i+6])
|
||||
@@ -294,8 +294,10 @@ func k3neg2(a [100]int) [100]int {
|
||||
}
|
||||
|
||||
func k4(a [100]int) [100]int {
|
||||
min := (-1) << 63
|
||||
for i := min; i < min+50; i++ { // ERROR "Induction variable: limits \[-9223372036854775808,-9223372036854775758\), increment 1$"
|
||||
// Note: can't use (-1)<<63 here, because i-min doesn't get rewritten to i+(-min),
|
||||
// and it isn't worth adding that special case to prove.
|
||||
min := (-1)<<63 + 1
|
||||
for i := min; i < min+50; i++ { // ERROR "Induction variable: limits \[-9223372036854775807,-9223372036854775757\), increment 1$"
|
||||
a[i-min] = i // ERROR "(\([0-9]+\) )?Proved IsInBounds$"
|
||||
}
|
||||
return a
|
||||
@@ -314,7 +316,7 @@ func d1(a [100]int) [100]int {
|
||||
for i := 0; i < 100; i++ { // ERROR "Induction variable: limits \[0,100\), increment 1$"
|
||||
for j := 0; j < i; j++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
|
||||
a[j] = 0 // ERROR "Proved IsInBounds$"
|
||||
a[j+1] = 0 // FIXME: this boundcheck should be eliminated
|
||||
a[j+1] = 0 // ERROR "Proved IsInBounds$"
|
||||
a[j+2] = 0
|
||||
}
|
||||
}
|
||||
@@ -325,7 +327,7 @@ func d2(a [100]int) [100]int {
|
||||
for i := 0; i < 100; i++ { // ERROR "Induction variable: limits \[0,100\), increment 1$"
|
||||
for j := 0; i > j; j++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
|
||||
a[j] = 0 // ERROR "Proved IsInBounds$"
|
||||
a[j+1] = 0 // FIXME: this boundcheck should be eliminated
|
||||
a[j+1] = 0 // ERROR "Proved IsInBounds$"
|
||||
a[j+2] = 0
|
||||
}
|
||||
}
|
||||
@@ -419,12 +421,12 @@ func nobce2(a string) {
|
||||
for i := int64(0); i < int64(len(a))-31337; i++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
|
||||
useString(a[i:]) // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$"
|
||||
}
|
||||
for i := int64(0); i < int64(len(a))+int64(-1<<63); i++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
|
||||
useString(a[i:]) // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$"
|
||||
for i := int64(0); i < int64(len(a))+int64(-1<<63); i++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$" "Disproved Less64"
|
||||
useString(a[i:])
|
||||
}
|
||||
j := int64(len(a)) - 123
|
||||
for i := int64(0); i < j+123+int64(-1<<63); i++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
|
||||
useString(a[i:]) // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$"
|
||||
for i := int64(0); i < j+123+int64(-1<<63); i++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$" "Disproved Less64"
|
||||
useString(a[i:])
|
||||
}
|
||||
for i := int64(0); i < j+122+int64(-1<<63); i++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
|
||||
// len(a)-123+122+MinInt overflows when len(a) == 0, so a bound check is needed here
|
||||
|
||||
@@ -73,6 +73,7 @@ func l(x, y int) (int, int, error) { // ERROR "can inline l"
|
||||
f := e
|
||||
f(nil) // ERROR "inlining call to l.func1"
|
||||
}
|
||||
_ = e // prevent simple deadcode elimination
|
||||
return y, x, nil
|
||||
}
|
||||
|
||||
@@ -109,6 +110,7 @@ func p() int { // ERROR "can inline p"
|
||||
|
||||
func q(x int) int { // ERROR "can inline q"
|
||||
foo := func() int { return x * 2 } // ERROR "can inline q.func1" "func literal does not escape"
|
||||
_ = foo // prevent simple deadcode elimination
|
||||
return foo() // ERROR "inlining call to q.func1"
|
||||
}
|
||||
|
||||
@@ -121,6 +123,8 @@ func r(z int) int { // ERROR "can inline r"
|
||||
return 2*y + x*z
|
||||
}(x) // ERROR "inlining call to r.func2.1"
|
||||
}
|
||||
_ = foo // prevent simple deadcode elimination
|
||||
_ = bar // prevent simple deadcode elimination
|
||||
return foo(42) + bar(42) // ERROR "inlining call to r.func1" "inlining call to r.func2" "inlining call to r.r.func2.func3"
|
||||
}
|
||||
|
||||
@@ -128,7 +132,8 @@ func s0(x int) int { // ERROR "can inline s0"
|
||||
foo := func() { // ERROR "can inline s0.func1" "func literal does not escape"
|
||||
x = x + 1
|
||||
}
|
||||
foo() // ERROR "inlining call to s0.func1"
|
||||
foo() // ERROR "inlining call to s0.func1"
|
||||
_ = foo // prevent simple deadcode elimination
|
||||
return x
|
||||
}
|
||||
|
||||
@@ -137,6 +142,7 @@ func s1(x int) int { // ERROR "can inline s1"
|
||||
return x
|
||||
}
|
||||
x = x + 1
|
||||
_ = foo // prevent simple deadcode elimination
|
||||
return foo() // ERROR "inlining call to s1.func1"
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// run
|
||||
|
||||
//go:build !nacl && !js && !aix && !wasip1 && !gcflags_noopt && gc
|
||||
//go:build !nacl && !js && !aix && !openbsd && !wasip1 && !gcflags_noopt && gc
|
||||
|
||||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
||||
632
test/prove.go
632
test/prove.go
@@ -8,7 +8,10 @@
|
||||
|
||||
package main
|
||||
|
||||
import "math"
|
||||
import (
|
||||
"math"
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
func f0(a []int) int {
|
||||
a[0] = 1
|
||||
@@ -400,8 +403,8 @@ func f13f(a, b int64) int64 {
|
||||
if b != math.MaxInt64 {
|
||||
return 42
|
||||
}
|
||||
if a > b {
|
||||
if a == 0 { // ERROR "Disproved Eq64$"
|
||||
if a > b { // ERROR "Disproved Less64$"
|
||||
if a == 0 {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
@@ -684,20 +687,6 @@ func constsuffix(s string) bool {
|
||||
return suffix(s, "abc") // ERROR "Proved IsSliceInBounds$"
|
||||
}
|
||||
|
||||
// oforuntil tests the pattern created by OFORUNTIL blocks. These are
|
||||
// handled by addLocalInductiveFacts rather than findIndVar.
|
||||
func oforuntil(b []int) {
|
||||
i := 0
|
||||
if len(b) > i {
|
||||
top:
|
||||
println(b[i]) // ERROR "Induction variable: limits \[0,\?\), increment 1$" "Proved IsInBounds$"
|
||||
i++
|
||||
if i < len(b) {
|
||||
goto top
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func atexit(foobar []func()) {
|
||||
for i := len(foobar) - 1; i >= 0; i-- { // ERROR "Induction variable: limits \[0,\?\], increment 1"
|
||||
f := foobar[i]
|
||||
@@ -877,11 +866,11 @@ func unrollDecMin(a []int, b int) int {
|
||||
return 42
|
||||
}
|
||||
var i, x int
|
||||
for i = len(a); i >= b; i -= 2 {
|
||||
for i = len(a); i >= b; i -= 2 { // ERROR "Proved Leq64"
|
||||
x += a[i-1]
|
||||
x += a[i-2]
|
||||
}
|
||||
if i == 1 { // ERROR "Disproved Eq64$"
|
||||
if i == 1 {
|
||||
x += a[i-1]
|
||||
}
|
||||
return x
|
||||
@@ -893,11 +882,11 @@ func unrollIncMin(a []int, b int) int {
|
||||
return 42
|
||||
}
|
||||
var i, x int
|
||||
for i = len(a); i >= b; i += 2 {
|
||||
for i = len(a); i >= b; i += 2 { // ERROR "Proved Leq64"
|
||||
x += a[i-1]
|
||||
x += a[i-2]
|
||||
}
|
||||
if i == 1 { // ERROR "Disproved Eq64$"
|
||||
if i == 1 {
|
||||
x += a[i-1]
|
||||
}
|
||||
return x
|
||||
@@ -1107,7 +1096,7 @@ func modu2(x, y uint) int {
|
||||
|
||||
func issue57077(s []int) (left, right []int) {
|
||||
middle := len(s) / 2
|
||||
left = s[:middle] // ERROR "Proved IsSliceInBounds$"
|
||||
left = s[:middle] // ERROR "Proved IsSliceInBounds$"
|
||||
right = s[middle:] // ERROR "Proved IsSliceInBounds$"
|
||||
return
|
||||
}
|
||||
@@ -1124,6 +1113,605 @@ func issue45928(x int) {
|
||||
useInt(combinedFrac)
|
||||
}
|
||||
|
||||
func constantBounds1(i, j uint) int {
|
||||
var a [10]int
|
||||
if j < 11 && i < j {
|
||||
return a[i] // ERROR "Proved IsInBounds$"
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func constantBounds2(i, j uint) int {
|
||||
var a [10]int
|
||||
if i < j && j < 11 {
|
||||
return a[i] // ERROR "Proved IsInBounds"
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func constantBounds3(i, j, k, l uint) int {
|
||||
var a [8]int
|
||||
if i < j && j < k && k < l && l < 11 {
|
||||
return a[i] // ERROR "Proved IsInBounds"
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func equalityPropagation(a [1]int, i, j uint) int {
|
||||
if i == j && i == 5 {
|
||||
return a[j-5] // ERROR "Proved IsInBounds"
|
||||
}
|
||||
return 0
|
||||
}
|
||||
func inequalityPropagation(a [1]int, i, j uint) int {
|
||||
if i != j && j >= 5 && j <= 6 && i == 5 {
|
||||
return a[j-6] // ERROR "Proved IsInBounds"
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func issue66826a(a [21]byte) {
|
||||
for i := 0; i <= 10; i++ { // ERROR "Induction variable: limits \[0,10\], increment 1$"
|
||||
_ = a[2*i] // ERROR "Proved IsInBounds"
|
||||
}
|
||||
}
|
||||
func issue66826b(a [31]byte, i int) {
|
||||
if i < 0 || i > 10 {
|
||||
return
|
||||
}
|
||||
_ = a[3*i] // ERROR "Proved IsInBounds"
|
||||
}
|
||||
|
||||
func f20(a, b bool) int {
|
||||
if a == b {
|
||||
if a {
|
||||
if b { // ERROR "Proved Arg"
|
||||
return 1
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func f21(a, b *int) int {
|
||||
if a == b {
|
||||
if a != nil {
|
||||
if b != nil { // ERROR "Proved IsNonNil"
|
||||
return 1
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func f22(b bool, x, y int) int {
|
||||
b2 := x < y
|
||||
if b == b2 {
|
||||
if b {
|
||||
if x >= y { // ERROR "Disproved Leq64$"
|
||||
return 1
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func ctz64(x uint64, ensureBothBranchesCouldHappen bool) int {
|
||||
const max = math.MaxUint64
|
||||
sz := bits.Len64(max)
|
||||
|
||||
log2half := uint64(max) >> (sz / 2)
|
||||
if x >= log2half || x == 0 {
|
||||
return 42
|
||||
}
|
||||
|
||||
y := bits.TrailingZeros64(x) // ERROR "Proved Ctz64 non-zero$""
|
||||
|
||||
z := sz / 2
|
||||
if ensureBothBranchesCouldHappen {
|
||||
if y < z { // ERROR "Proved Less64$"
|
||||
return -42
|
||||
}
|
||||
} else {
|
||||
if y >= z { // ERROR "Disproved Leq64$"
|
||||
return 1337
|
||||
}
|
||||
}
|
||||
|
||||
return y
|
||||
}
|
||||
func ctz32(x uint32, ensureBothBranchesCouldHappen bool) int {
|
||||
const max = math.MaxUint32
|
||||
sz := bits.Len32(max)
|
||||
|
||||
log2half := uint32(max) >> (sz / 2)
|
||||
if x >= log2half || x == 0 {
|
||||
return 42
|
||||
}
|
||||
|
||||
y := bits.TrailingZeros32(x) // ERROR "Proved Ctz32 non-zero$""
|
||||
|
||||
z := sz / 2
|
||||
if ensureBothBranchesCouldHappen {
|
||||
if y < z { // ERROR "Proved Less64$"
|
||||
return -42
|
||||
}
|
||||
} else {
|
||||
if y >= z { // ERROR "Disproved Leq64$"
|
||||
return 1337
|
||||
}
|
||||
}
|
||||
|
||||
return y
|
||||
}
|
||||
func ctz16(x uint16, ensureBothBranchesCouldHappen bool) int {
|
||||
const max = math.MaxUint16
|
||||
sz := bits.Len16(max)
|
||||
|
||||
log2half := uint16(max) >> (sz / 2)
|
||||
if x >= log2half || x == 0 {
|
||||
return 42
|
||||
}
|
||||
|
||||
y := bits.TrailingZeros16(x) // ERROR "Proved Ctz16 non-zero$""
|
||||
|
||||
z := sz / 2
|
||||
if ensureBothBranchesCouldHappen {
|
||||
if y < z { // ERROR "Proved Less64$"
|
||||
return -42
|
||||
}
|
||||
} else {
|
||||
if y >= z { // ERROR "Disproved Leq64$"
|
||||
return 1337
|
||||
}
|
||||
}
|
||||
|
||||
return y
|
||||
}
|
||||
func ctz8(x uint8, ensureBothBranchesCouldHappen bool) int {
|
||||
const max = math.MaxUint8
|
||||
sz := bits.Len8(max)
|
||||
|
||||
log2half := uint8(max) >> (sz / 2)
|
||||
if x >= log2half || x == 0 {
|
||||
return 42
|
||||
}
|
||||
|
||||
y := bits.TrailingZeros8(x) // ERROR "Proved Ctz8 non-zero$""
|
||||
|
||||
z := sz / 2
|
||||
if ensureBothBranchesCouldHappen {
|
||||
if y < z { // ERROR "Proved Less64$"
|
||||
return -42
|
||||
}
|
||||
} else {
|
||||
if y >= z { // ERROR "Disproved Leq64$"
|
||||
return 1337
|
||||
}
|
||||
}
|
||||
|
||||
return y
|
||||
}
|
||||
|
||||
func bitLen64(x uint64, ensureBothBranchesCouldHappen bool) int {
|
||||
const max = math.MaxUint64
|
||||
sz := bits.Len64(max)
|
||||
|
||||
if x >= max>>3 {
|
||||
return 42
|
||||
}
|
||||
if x <= max>>6 {
|
||||
return 42
|
||||
}
|
||||
|
||||
y := bits.Len64(x)
|
||||
|
||||
if ensureBothBranchesCouldHappen {
|
||||
if sz-6 <= y && y <= sz-3 { // ERROR "Proved Leq64$"
|
||||
return -42
|
||||
}
|
||||
} else {
|
||||
if y < sz-6 || sz-3 < y { // ERROR "Disproved Less64$"
|
||||
return 1337
|
||||
}
|
||||
}
|
||||
return y
|
||||
}
|
||||
func bitLen32(x uint32, ensureBothBranchesCouldHappen bool) int {
|
||||
const max = math.MaxUint32
|
||||
sz := bits.Len32(max)
|
||||
|
||||
if x >= max>>3 {
|
||||
return 42
|
||||
}
|
||||
if x <= max>>6 {
|
||||
return 42
|
||||
}
|
||||
|
||||
y := bits.Len32(x)
|
||||
|
||||
if ensureBothBranchesCouldHappen {
|
||||
if sz-6 <= y && y <= sz-3 { // ERROR "Proved Leq64$"
|
||||
return -42
|
||||
}
|
||||
} else {
|
||||
if y < sz-6 || sz-3 < y { // ERROR "Disproved Less64$"
|
||||
return 1337
|
||||
}
|
||||
}
|
||||
return y
|
||||
}
|
||||
func bitLen16(x uint16, ensureBothBranchesCouldHappen bool) int {
|
||||
const max = math.MaxUint16
|
||||
sz := bits.Len16(max)
|
||||
|
||||
if x >= max>>3 {
|
||||
return 42
|
||||
}
|
||||
if x <= max>>6 {
|
||||
return 42
|
||||
}
|
||||
|
||||
y := bits.Len16(x)
|
||||
|
||||
if ensureBothBranchesCouldHappen {
|
||||
if sz-6 <= y && y <= sz-3 { // ERROR "Proved Leq64$"
|
||||
return -42
|
||||
}
|
||||
} else {
|
||||
if y < sz-6 || sz-3 < y { // ERROR "Disproved Less64$"
|
||||
return 1337
|
||||
}
|
||||
}
|
||||
return y
|
||||
}
|
||||
func bitLen8(x uint8, ensureBothBranchesCouldHappen bool) int {
|
||||
const max = math.MaxUint8
|
||||
sz := bits.Len8(max)
|
||||
|
||||
if x >= max>>3 {
|
||||
return 42
|
||||
}
|
||||
if x <= max>>6 {
|
||||
return 42
|
||||
}
|
||||
|
||||
y := bits.Len8(x)
|
||||
|
||||
if ensureBothBranchesCouldHappen {
|
||||
if sz-6 <= y && y <= sz-3 { // ERROR "Proved Leq64$"
|
||||
return -42
|
||||
}
|
||||
} else {
|
||||
if y < sz-6 || sz-3 < y { // ERROR "Disproved Less64$"
|
||||
return 1337
|
||||
}
|
||||
}
|
||||
return y
|
||||
}
|
||||
|
||||
func xor64(a, b uint64, ensureBothBranchesCouldHappen bool) int {
|
||||
a &= 0xff
|
||||
b &= 0xfff
|
||||
|
||||
z := a ^ b
|
||||
|
||||
if ensureBothBranchesCouldHappen {
|
||||
if z > 0xfff { // ERROR "Disproved Less64U$"
|
||||
return 42
|
||||
}
|
||||
} else {
|
||||
if z <= 0xfff { // ERROR "Proved Leq64U$"
|
||||
return 1337
|
||||
}
|
||||
}
|
||||
return int(z)
|
||||
}
|
||||
|
||||
func or64(a, b uint64, ensureBothBranchesCouldHappen bool) int {
|
||||
a &= 0xff
|
||||
b &= 0xfff
|
||||
|
||||
z := a | b
|
||||
|
||||
if ensureBothBranchesCouldHappen {
|
||||
if z > 0xfff { // ERROR "Disproved Less64U$"
|
||||
return 42
|
||||
}
|
||||
} else {
|
||||
if z <= 0xfff { // ERROR "Proved Leq64U$"
|
||||
return 1337
|
||||
}
|
||||
}
|
||||
return int(z)
|
||||
}
|
||||
|
||||
func mod64uWithSmallerDividendMax(a, b uint64, ensureBothBranchesCouldHappen bool) int {
|
||||
a &= 0xff
|
||||
b &= 0xfff
|
||||
|
||||
z := bits.Len64(a % b) // see go.dev/issue/68857 for bits.Len64
|
||||
|
||||
if ensureBothBranchesCouldHappen {
|
||||
if z > bits.Len64(0xff) { // ERROR "Disproved Less64$"
|
||||
return 42
|
||||
}
|
||||
} else {
|
||||
if z <= bits.Len64(0xff) { // ERROR "Proved Leq64$"
|
||||
return 1337
|
||||
}
|
||||
}
|
||||
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)
|
||||
|
||||
z := bits.Len64(a % b) // see go.dev/issue/68857 for bits.Len64
|
||||
|
||||
if ensureBothBranchesCouldHappen {
|
||||
if z > bits.Len64(0x10-1) { // ERROR "Disproved Less64$"
|
||||
return 42
|
||||
}
|
||||
} else {
|
||||
if z <= bits.Len64(0x10-1) { // ERROR "Proved Leq64$"
|
||||
return 1337
|
||||
}
|
||||
}
|
||||
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)
|
||||
|
||||
z := bits.Len64(a % b) // see go.dev/issue/68857 for bits.Len64
|
||||
|
||||
if ensureBothBranchesCouldHappen {
|
||||
if z > bits.Len64(0x10-1) { // ERROR "Disproved Less64$"
|
||||
return 42
|
||||
}
|
||||
} else {
|
||||
if z <= bits.Len64(0x10-1) { // ERROR "Proved Leq64$"
|
||||
return 1337
|
||||
}
|
||||
}
|
||||
return z
|
||||
}
|
||||
func mod64sPositiveWithSmallerDividendMax(a, b int64, ensureBothBranchesCouldHappen bool) int64 {
|
||||
if a < 0 || b < 0 {
|
||||
return 42
|
||||
}
|
||||
a &= 0xff
|
||||
b &= 0xfff
|
||||
|
||||
z := a % b // ERROR "Proved Mod64 does not need fix-up$"
|
||||
|
||||
if ensureBothBranchesCouldHappen {
|
||||
if z > 0xff { // ERROR "Disproved Less64$"
|
||||
return 42
|
||||
}
|
||||
} else {
|
||||
if z <= 0xff { // ERROR "Proved Leq64$"
|
||||
return 1337
|
||||
}
|
||||
}
|
||||
return z
|
||||
}
|
||||
func mod64sPositiveWithSmallerDivisorMax(a, b int64, ensureBothBranchesCouldHappen bool) int64 {
|
||||
if a < 0 || b < 0 {
|
||||
return 42
|
||||
}
|
||||
a &= 0xfff
|
||||
b &= 0xff
|
||||
|
||||
z := a % b // ERROR "Proved Mod64 does not need fix-up$"
|
||||
|
||||
if ensureBothBranchesCouldHappen {
|
||||
if z > 0xff-1 { // ERROR "Disproved Less64$"
|
||||
return 42
|
||||
}
|
||||
} else {
|
||||
if z <= 0xff-1 { // ERROR "Proved Leq64$"
|
||||
return 1337
|
||||
}
|
||||
}
|
||||
return z
|
||||
}
|
||||
func mod64sPositiveWithIdenticalMax(a, b int64, ensureBothBranchesCouldHappen bool) int64 {
|
||||
if a < 0 || b < 0 {
|
||||
return 42
|
||||
}
|
||||
a &= 0xfff
|
||||
b &= 0xfff
|
||||
|
||||
z := a % b // ERROR "Proved Mod64 does not need fix-up$"
|
||||
|
||||
if ensureBothBranchesCouldHappen {
|
||||
if z > 0xfff-1 { // ERROR "Disproved Less64$"
|
||||
return 42
|
||||
}
|
||||
} else {
|
||||
if z <= 0xfff-1 { // ERROR "Proved Leq64$"
|
||||
return 1337
|
||||
}
|
||||
}
|
||||
return z
|
||||
}
|
||||
|
||||
func div64u(a, b uint64, ensureAllBranchesCouldHappen func() bool) uint64 {
|
||||
a &= 0xffff
|
||||
a |= 0xfff
|
||||
b &= 0xff
|
||||
b |= 0xf
|
||||
|
||||
z := a / b // ERROR "Proved Neq64$"
|
||||
|
||||
if ensureAllBranchesCouldHappen() && z > 0xffff/0xf { // ERROR "Disproved Less64U$"
|
||||
return 42
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && z <= 0xffff/0xf { // ERROR "Proved Leq64U$"
|
||||
return 1337
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && z < 0xfff/0xff { // ERROR "Disproved Less64U$"
|
||||
return 42
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && z >= 0xfff/0xff { // ERROR "Proved Leq64U$"
|
||||
return 42
|
||||
}
|
||||
return z
|
||||
}
|
||||
func div64s(a, b int64, ensureAllBranchesCouldHappen func() bool) int64 {
|
||||
if a < 0 || b < 0 {
|
||||
return 42
|
||||
}
|
||||
a &= 0xffff
|
||||
a |= 0xfff
|
||||
b &= 0xff
|
||||
b |= 0xf
|
||||
|
||||
z := a / b // ERROR "(Proved Div64 does not need fix-up|Proved Neq64)$"
|
||||
|
||||
if ensureAllBranchesCouldHappen() && z > 0xffff/0xf { // ERROR "Disproved Less64$"
|
||||
return 42
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && z <= 0xffff/0xf { // ERROR "Proved Leq64$"
|
||||
return 1337
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && z < 0xfff/0xff { // ERROR "Disproved Less64$"
|
||||
return 42
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && z >= 0xfff/0xff { // ERROR "Proved Leq64$"
|
||||
return 42
|
||||
}
|
||||
return z
|
||||
}
|
||||
|
||||
func trunc64to16(a uint64, ensureAllBranchesCouldHappen func() bool) uint16 {
|
||||
a &= 0xfff
|
||||
a |= 0xff
|
||||
|
||||
z := uint16(a)
|
||||
if ensureAllBranchesCouldHappen() && z > 0xfff { // ERROR "Disproved Less16U$"
|
||||
return 42
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && z <= 0xfff { // ERROR "Proved Leq16U$"
|
||||
return 1337
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && z < 0xff { // ERROR "Disproved Less16U$"
|
||||
return 42
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && z >= 0xff { // ERROR "Proved Leq16U$"
|
||||
return 1337
|
||||
}
|
||||
return z
|
||||
}
|
||||
|
||||
func com64(a uint64, ensureAllBranchesCouldHappen func() bool) uint64 {
|
||||
a &= 0xffff
|
||||
a |= 0xff
|
||||
|
||||
z := ^a
|
||||
|
||||
if ensureAllBranchesCouldHappen() && z > ^uint64(0xff) { // ERROR "Disproved Less64U$"
|
||||
return 42
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && z <= ^uint64(0xff) { // ERROR "Proved Leq64U$"
|
||||
return 1337
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && z < ^uint64(0xffff) { // ERROR "Disproved Less64U$"
|
||||
return 42
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && z >= ^uint64(0xffff) { // ERROR "Proved Leq64U$"
|
||||
return 1337
|
||||
}
|
||||
return z
|
||||
}
|
||||
|
||||
func neg64(a uint64, ensureAllBranchesCouldHappen func() bool) uint64 {
|
||||
var lo, hi uint64 = 0xff, 0xfff
|
||||
a &= hi
|
||||
a |= lo
|
||||
|
||||
z := -a
|
||||
|
||||
if ensureAllBranchesCouldHappen() && z > -lo { // ERROR "Disproved Less64U$"
|
||||
return 42
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && z <= -lo { // ERROR "Proved Leq64U$"
|
||||
return 1337
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && z < -hi { // ERROR "Disproved Less64U$"
|
||||
return 42
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && z >= -hi { // ERROR "Proved Leq64U$"
|
||||
return 1337
|
||||
}
|
||||
return z
|
||||
}
|
||||
func neg64mightOverflowDuringNeg(a uint64, ensureAllBranchesCouldHappen func() bool) uint64 {
|
||||
var lo, hi uint64 = 0, 0xfff
|
||||
a &= hi
|
||||
a |= lo
|
||||
|
||||
z := -a
|
||||
|
||||
if ensureAllBranchesCouldHappen() && z > -lo {
|
||||
return 42
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && z <= -lo {
|
||||
return 1337
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && z < -hi {
|
||||
return 42
|
||||
}
|
||||
if ensureAllBranchesCouldHappen() && z >= -hi {
|
||||
return 1337
|
||||
}
|
||||
return z
|
||||
}
|
||||
|
||||
func phiMin(a, b []byte) {
|
||||
_ = a[:min(len(a), len(b))] // ERROR "Proved IsSliceInBounds"
|
||||
_ = b[:min(len(a), len(b))] // ERROR "Proved IsSliceInBounds"
|
||||
_ = a[:max(len(a), len(b))]
|
||||
_ = b[:max(len(a), len(b))]
|
||||
x := len(a)
|
||||
if x > len(b) {
|
||||
x = len(b)
|
||||
useInt(0)
|
||||
}
|
||||
_ = a[:x] // ERROR "Proved IsSliceInBounds"
|
||||
y := len(a)
|
||||
if y > len(b) {
|
||||
y = len(b)
|
||||
useInt(0)
|
||||
} else {
|
||||
useInt(1)
|
||||
}
|
||||
_ = b[:y] // ERROR "Proved IsSliceInBounds"
|
||||
}
|
||||
|
||||
func issue16833(a, b []byte) {
|
||||
n := copy(a, b)
|
||||
_ = a[n:] // ERROR "Proved IsSliceInBounds"
|
||||
_ = b[n:] // ERROR "Proved IsSliceInBounds"
|
||||
_ = a[:n] // ERROR "Proved IsSliceInBounds"
|
||||
_ = b[:n] // ERROR "Proved IsSliceInBounds"
|
||||
}
|
||||
|
||||
func clampedIdx1(x []int, i int) int {
|
||||
if len(x) == 0 {
|
||||
return 0
|
||||
}
|
||||
return x[min(max(0, i), len(x)-1)] // ERROR "Proved IsInBounds"
|
||||
}
|
||||
func clampedIdx2(x []int, i int) int {
|
||||
if len(x) == 0 {
|
||||
return 0
|
||||
}
|
||||
return x[max(min(i, len(x)-1), 0)] // TODO: can't get rid of this bounds check yet
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func useInt(a int) {
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ func f0i(x int) int {
|
||||
}
|
||||
|
||||
if (x + 20) == 20 {
|
||||
return x + 5 // ERROR "Proved.+is constant 0$"
|
||||
return x + 5 // ERROR "Proved.+is constant 0$" "Proved.+is constant 5$"
|
||||
}
|
||||
|
||||
return x / 2
|
||||
@@ -26,7 +26,7 @@ func f0u(x uint) uint {
|
||||
}
|
||||
|
||||
if (x + 20) == 20 {
|
||||
return x + 5 // ERROR "Proved.+is constant 0$"
|
||||
return x + 5 // ERROR "Proved.+is constant 0$" "Proved.+is constant 5$"
|
||||
}
|
||||
|
||||
return x / 2
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
// Copyright 2019 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.
|
||||
|
||||
The runtime directory contains tests that specifically need
|
||||
to be compiled as-if in the runtime package. For error-check
|
||||
tests, these require the additional flags -+ and -p=runtime.
|
||||
@@ -25,12 +25,12 @@ func f() {
|
||||
|
||||
switch {
|
||||
case 0: f(); case 0:
|
||||
case 0: f() case 0: // ERROR "unexpected case at end of statement"
|
||||
case 0: f() case 0: // ERROR "unexpected keyword case at end of statement"
|
||||
}
|
||||
|
||||
switch {
|
||||
case 0: f(); default:
|
||||
case 0: f() default: // ERROR "unexpected default at end of statement"
|
||||
case 0: f() default: // ERROR "unexpected keyword default at end of statement"
|
||||
}
|
||||
|
||||
switch {
|
||||
|
||||
@@ -8,7 +8,7 @@ package main
|
||||
|
||||
func main() {
|
||||
if x { } // GCCGO_ERROR "undefined"
|
||||
else { } // ERROR "unexpected semicolon or newline before .?else.?|unexpected else"
|
||||
else { } // ERROR "unexpected semicolon or newline before .?else.?|unexpected keyword else"
|
||||
}
|
||||
|
||||
|
||||
|
||||
29
test/tailcall.go
Normal file
29
test/tailcall.go
Normal file
@@ -0,0 +1,29 @@
|
||||
// errorcheck -0 -d=tailcall=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.
|
||||
|
||||
package p
|
||||
|
||||
// Test that when generating wrappers for methods, we generate a tail call to the pointer version of
|
||||
// the method, if that method is not inlineable. We use go:noinline here to force the non-inlineability
|
||||
// condition.
|
||||
|
||||
//go:noinline
|
||||
func (f *Foo) Get2Vals() [2]int { return [2]int{f.Val, f.Val + 1} }
|
||||
func (f *Foo) Get3Vals() [3]int { return [3]int{f.Val, f.Val + 1, f.Val + 2} }
|
||||
|
||||
type Foo struct{ Val int }
|
||||
|
||||
type Bar struct { // ERROR "tail call emitted for the method \(\*Foo\).Get2Vals wrapper"
|
||||
int64
|
||||
*Foo // needs a method wrapper
|
||||
string
|
||||
}
|
||||
|
||||
var i any
|
||||
|
||||
func init() {
|
||||
i = Bar{1, nil, "first"}
|
||||
}
|
||||
19
test/wasmexport.go
Normal file
19
test/wasmexport.go
Normal file
@@ -0,0 +1,19 @@
|
||||
// errorcheck
|
||||
|
||||
// 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.
|
||||
|
||||
// Verify that misplaced directives are diagnosed.
|
||||
|
||||
//go:build wasm
|
||||
|
||||
package p
|
||||
|
||||
//go:wasmexport F
|
||||
func F() {} // OK
|
||||
|
||||
type S int32
|
||||
|
||||
//go:wasmexport M
|
||||
func (S) M() {} // ERROR "cannot use //go:wasmexport on a method"
|
||||
92
test/wasmexport2.go
Normal file
92
test/wasmexport2.go
Normal file
@@ -0,0 +1,92 @@
|
||||
// errorcheck
|
||||
|
||||
// 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.
|
||||
|
||||
// Verify that wasmexport supports allowed types and rejects
|
||||
// unallowed types.
|
||||
|
||||
//go:build wasm
|
||||
|
||||
package p
|
||||
|
||||
import (
|
||||
"structs"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//go:wasmexport good1
|
||||
func good1(int32, uint32, int64, uint64, float32, float64, unsafe.Pointer) {} // allowed types
|
||||
|
||||
type MyInt32 int32
|
||||
|
||||
//go:wasmexport good2
|
||||
func good2(MyInt32) {} // named type is ok
|
||||
|
||||
//go:wasmexport good3
|
||||
func good3() int32 { return 0 } // one result is ok
|
||||
|
||||
//go:wasmexport good4
|
||||
func good4() unsafe.Pointer { return nil } // one result is ok
|
||||
|
||||
//go:wasmexport good5
|
||||
func good5(string, uintptr) bool { return false } // bool, string, and uintptr are allowed
|
||||
|
||||
//go:wasmexport bad1
|
||||
func bad1(any) {} // ERROR "go:wasmexport: unsupported parameter type"
|
||||
|
||||
//go:wasmexport bad2
|
||||
func bad2(func()) {} // ERROR "go:wasmexport: unsupported parameter type"
|
||||
|
||||
//go:wasmexport bad3
|
||||
func bad3(uint8) {} // ERROR "go:wasmexport: unsupported parameter type"
|
||||
|
||||
//go:wasmexport bad4
|
||||
func bad4(int) {} // ERROR "go:wasmexport: unsupported parameter type"
|
||||
|
||||
// Struct and array types are also not allowed.
|
||||
|
||||
type S struct { x, y int32 }
|
||||
|
||||
type H struct { _ structs.HostLayout; x, y int32 }
|
||||
|
||||
type A = structs.HostLayout
|
||||
|
||||
type AH struct { _ A; x, y int32 }
|
||||
|
||||
//go:wasmexport bad5
|
||||
func bad5(S) {} // ERROR "go:wasmexport: unsupported parameter type"
|
||||
|
||||
//go:wasmexport bad6
|
||||
func bad6(H) {} // ERROR "go:wasmexport: unsupported parameter type"
|
||||
|
||||
//go:wasmexport bad7
|
||||
func bad7([4]int32) {} // ERROR "go:wasmexport: unsupported parameter type"
|
||||
|
||||
// Pointer types are not allowed, with resitrictions on
|
||||
// the element type.
|
||||
|
||||
//go:wasmexport good6
|
||||
func good6(*int32, *uint8, *bool) {}
|
||||
|
||||
//go:wasmexport bad8
|
||||
func bad8(*S) {} // ERROR "go:wasmexport: unsupported parameter type" // without HostLayout, not allowed
|
||||
|
||||
//go:wasmexport bad9
|
||||
func bad9() *S { return nil } // ERROR "go:wasmexport: unsupported result type"
|
||||
|
||||
//go:wasmexport good7
|
||||
func good7(*H, *AH) {} // pointer to struct with HostLayout is allowed
|
||||
|
||||
//go:wasmexport good8
|
||||
func good8(*struct{}) {} // pointer to empty struct is allowed
|
||||
|
||||
//go:wasmexport good9
|
||||
func good9(*[4]int32, *[2]H) {} // pointer to array is allowed, if the element type is okay
|
||||
|
||||
//go:wasmexport toomanyresults
|
||||
func toomanyresults() (int32, int32) { return 0, 0 } // ERROR "go:wasmexport: too many return values"
|
||||
|
||||
//go:wasmexport bad10
|
||||
func bad10() string { return "" } // ERROR "go:wasmexport: unsupported result type" // string cannot be a result
|
||||
11
test/wasmmemsize.dir/asm_wasm.s
Normal file
11
test/wasmmemsize.dir/asm_wasm.s
Normal file
@@ -0,0 +1,11 @@
|
||||
// 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.
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
TEXT ·currentMemory(SB), NOSPLIT, $0
|
||||
Get SP
|
||||
CurrentMemory
|
||||
I32Store ret+0(FP)
|
||||
RET
|
||||
30
test/wasmmemsize.dir/main.go
Normal file
30
test/wasmmemsize.dir/main.go
Normal file
@@ -0,0 +1,30 @@
|
||||
// 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 main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Expect 8 MB of memory usage for a small wasm program.
|
||||
// This reflects the current allocator. We test an exact
|
||||
// value here, but if the allocator changes, we can update
|
||||
// or relax this.
|
||||
const want = 8 << 20
|
||||
|
||||
var w = io.Discard
|
||||
|
||||
func main() {
|
||||
fmt.Fprintln(w, "hello world")
|
||||
|
||||
const pageSize = 64 * 1024
|
||||
sz := uintptr(currentMemory()) * pageSize
|
||||
if sz != want {
|
||||
fmt.Printf("FAIL: unexpected memory size %d, want %d\n", sz, want)
|
||||
}
|
||||
}
|
||||
|
||||
func currentMemory() int32 // implemented in assembly
|
||||
11
test/wasmmemsize.go
Normal file
11
test/wasmmemsize.go
Normal file
@@ -0,0 +1,11 @@
|
||||
// runindir
|
||||
|
||||
// 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.
|
||||
|
||||
// This test checks the memory size of a small wasm program.
|
||||
|
||||
//go:build wasm
|
||||
|
||||
package ignored
|
||||
24
test/weak.go
Normal file
24
test/weak.go
Normal file
@@ -0,0 +1,24 @@
|
||||
// errorcheck
|
||||
|
||||
// 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 weak pointers.
|
||||
|
||||
package p
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"weak"
|
||||
)
|
||||
|
||||
// Adapted from example in https://github.com/golang/go/issues/67552#issuecomment-2639661220
|
||||
func conversion() {
|
||||
p := "hello"
|
||||
a := weak.Make(&p)
|
||||
b := (weak.Pointer[*byte])(a) // ERROR "cannot convert a \(variable of struct type weak\.Pointer\[string\]\) to type weak.Pointer\[\*byte\]"
|
||||
c := b.Value()
|
||||
println(**c)
|
||||
runtime.KeepAlive(p)
|
||||
}
|
||||
Reference in New Issue
Block a user