Test libc.

This commit is contained in:
Nuno Cruces
2025-04-24 23:59:53 +01:00
parent 9ea7099c24
commit e580f080b9
4 changed files with 301 additions and 154 deletions

View File

@@ -23,6 +23,7 @@ EOF
-mbulk-memory -mreference-types \
-mnontrapping-fptoint -msign-ext \
-fno-stack-protector -fno-stack-clash-protection \
-Wl,-z,stack-size=1024 \
-Wl,--stack-first \
-Wl,--import-undefined \
-Wl,--initial-memory=16777216 \

Binary file not shown.

View File

@@ -4,7 +4,7 @@
(type $2 (func (param i32) (result i32)))
(type $3 (func (param i32 i32 i32 i32)))
(memory $0 256)
(data $0 (i32.const 65536) "\01")
(data $0 (i32.const 1024) "\01")
(table $0 1 1 funcref)
(export "memory" (memory $0))
(export "memset" (func $memset))
@@ -996,67 +996,67 @@
)
)
(v128.store
(i32.const 65792)
(i32.const 1280)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 65776)
(i32.const 1264)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 65760)
(i32.const 1248)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 65744)
(i32.const 1232)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 65728)
(i32.const 1216)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 65712)
(i32.const 1200)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 65696)
(i32.const 1184)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 65680)
(i32.const 1168)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 65664)
(i32.const 1152)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 65648)
(i32.const 1136)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 65632)
(i32.const 1120)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 65616)
(i32.const 1104)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 65600)
(i32.const 1088)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 65584)
(i32.const 1072)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 65568)
(i32.const 1056)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 65552)
(i32.const 1040)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(local.set $1
@@ -1072,7 +1072,7 @@
(local.get $2)
(i32.const 255)
)
(i32.const 65552)
(i32.const 1040)
)
(i32.const 1)
)
@@ -1105,7 +1105,7 @@
(i32.load8_u
(local.get $2)
)
(i32.const 65552)
(i32.const 1040)
)
)
)
@@ -1117,7 +1117,7 @@
(i32.load8_u offset=1
(local.get $2)
)
(i32.const 65552)
(i32.const 1040)
)
)
)
@@ -1129,7 +1129,7 @@
(i32.load8_u offset=2
(local.get $2)
)
(i32.const 65552)
(i32.const 1040)
)
)
)
@@ -1151,7 +1151,7 @@
)
(local.get $scratch)
)
(i32.const 65552)
(i32.const 1040)
)
)
)
@@ -1214,67 +1214,67 @@
)
)
(v128.store
(i32.const 66048)
(i32.const 1536)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 66032)
(i32.const 1520)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 66016)
(i32.const 1504)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 66000)
(i32.const 1488)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 65984)
(i32.const 1472)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 65968)
(i32.const 1456)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 65952)
(i32.const 1440)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 65936)
(i32.const 1424)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 65920)
(i32.const 1408)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 65904)
(i32.const 1392)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 65888)
(i32.const 1376)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 65872)
(i32.const 1360)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 65856)
(i32.const 1344)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 65840)
(i32.const 1328)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 65824)
(i32.const 1312)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(v128.store
(i32.const 65808)
(i32.const 1296)
(v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
)
(loop $label
@@ -1285,7 +1285,7 @@
(local.get $1)
)
)
(i32.const 65808)
(i32.const 1296)
)
(i32.const 1)
)
@@ -1309,7 +1309,7 @@
(i32.load8_u
(local.get $1)
)
(i32.const 65808)
(i32.const 1296)
)
)
)
@@ -1319,7 +1319,7 @@
(i32.load8_u offset=1
(local.get $1)
)
(i32.const 65808)
(i32.const 1296)
)
)
)
@@ -1329,7 +1329,7 @@
(i32.load8_u offset=2
(local.get $1)
)
(i32.const 65808)
(i32.const 1296)
)
)
)
@@ -1351,7 +1351,7 @@
)
(local.get $scratch)
)
(i32.const 65808)
(i32.const 1296)
)
)
)

View File

@@ -14,6 +14,7 @@ import (
var binary []byte
const (
page = 64 * 1024
size = 1024 * 1024 * 4
ptr1 = 1024 * 1024
ptr2 = ptr1 + size
@@ -35,10 +36,13 @@ var (
stack [8]uint64
)
func call(fn api.Function, arg ...uint64) uint32 {
func call(fn api.Function, arg ...uint64) uint64 {
copy(stack[:], arg)
fn.CallWithStack(context.Background(), stack[:])
return uint32(stack[0])
err := fn.CallWithStack(context.Background(), stack[:])
if err != nil {
panic(err)
}
return stack[0]
}
func TestMain(m *testing.M) {
@@ -74,170 +78,97 @@ func Benchmark_memset(b *testing.B) {
for range b.N {
call(memset, ptr1, 3, size)
}
b.StopTimer()
for i, got := range memory[ptr1 : ptr1+size] {
if got != 3 {
b.Fatal(i, got)
}
}
}
func Benchmark_memcpy(b *testing.B) {
clear(memory)
call(memset, ptr2, 5, size)
fill(memory[ptr2:ptr2+size], 5)
b.SetBytes(size)
b.ResetTimer()
for range b.N {
call(memcpy, ptr1, ptr2, size)
}
b.StopTimer()
for i, got := range memory[ptr1 : ptr1+size] {
if got != 5 {
b.Fatal(i, got)
}
}
}
func Benchmark_memchr(b *testing.B) {
clear(memory)
call(memset, ptr1, 7, size)
call(memset, ptr1+size/2, 5, size/2)
fill(memory[ptr1:ptr1+size/2], 7)
fill(memory[ptr1+size/2:ptr1+size], 5)
b.SetBytes(size/2 + 1)
b.ResetTimer()
for range b.N {
call(memchr, ptr1, 5, size)
}
b.StopTimer()
if got := call(memchr, ptr1, 5, size); got != ptr1+size/2 {
b.Fatal(got)
}
if got := call(memchr, ptr1, 5, size/2); got != 0 {
b.Fatal(got, ptr1+size/2)
}
}
func Benchmark_memcmp(b *testing.B) {
clear(memory)
call(memset, ptr1, 7, size)
call(memset, ptr2, 7, size)
call(memset, ptr2+size/2, 5, size/2)
fill(memory[ptr1:ptr1+size], 7)
fill(memory[ptr2:ptr2+size/2], 7)
fill(memory[ptr2+size/2:ptr2+size], 5)
b.SetBytes(size/2 + 1)
b.ResetTimer()
for range b.N {
call(memcmp, ptr1, ptr2, size)
}
b.StopTimer()
// ptr1 > ptr2
if got := int32(call(memcmp, ptr1, ptr2, size)); got <= 0 {
b.Fatal(got)
}
// ptr1[:size/2] == ptr2[:size/2]
if got := int32(call(memcmp, ptr1, ptr2, size/2)); got != 0 {
b.Fatal(got)
}
}
func Benchmark_strlen(b *testing.B) {
clear(memory)
call(memset, ptr1, 5, size-1)
fill(memory[ptr1:ptr1+size-1], 5)
b.SetBytes(size)
b.ResetTimer()
for range b.N {
call(strlen, ptr1)
}
b.StopTimer()
if got := int32(call(strlen, ptr1)); got != size-1 {
b.Fatal(got)
}
}
func Benchmark_strchr(b *testing.B) {
clear(memory)
call(memset, ptr1, 7, size-1)
call(memset, ptr1+size/2, 5, size/2-1)
fill(memory[ptr1:ptr1+size/2], 7)
fill(memory[ptr1+size/2:ptr1+size-1], 5)
b.SetBytes(size/2 + 1)
b.ResetTimer()
for range b.N {
call(strchr, ptr1, 5)
}
b.StopTimer()
if got := call(strchr, ptr1, 5); got != ptr1+size/2 {
b.Fatal(got)
}
}
func Benchmark_strcmp(b *testing.B) {
clear(memory)
call(memset, ptr1, 7, size-1)
call(memset, ptr2, 7, size-1)
call(memset, ptr2+size/2, 5, size/2-1)
fill(memory[ptr1:ptr1+size-1], 7)
fill(memory[ptr2:ptr2+size/2], 7)
fill(memory[ptr2+size/2:ptr2+size-1], 5)
b.SetBytes(size/2 + 1)
b.ResetTimer()
for range b.N {
call(strcmp, ptr1, ptr2, size)
}
b.StopTimer()
// ptr1 > ptr2
if got := int32(call(strcmp, ptr1, ptr2)); got <= 0 {
b.Fatal(got)
}
// make ptr1 < ptr2
memory[ptr1+size/2] = 0
if got := int32(call(strcmp, ptr1, ptr2)); got >= 0 {
b.Fatal(got)
}
memory[ptr2+size/2] = 0
// make ptr1 == ptr2
if got := int32(call(strcmp, ptr1, ptr2)); got != 0 {
b.Fatal(got)
}
}
func Benchmark_strncmp(b *testing.B) {
clear(memory)
call(memset, ptr1, 7, size-1)
call(memset, ptr2, 7, size-1)
call(memset, ptr2+size/2, 5, size/2-1)
fill(memory[ptr1:ptr1+size-1], 7)
fill(memory[ptr2:ptr2+size/2], 7)
fill(memory[ptr2+size/2:ptr2+size-1], 5)
b.SetBytes(size/2 + 1)
b.ResetTimer()
for range b.N {
call(strncmp, ptr1, ptr2, size-1)
}
b.StopTimer()
// ptr1 > ptr2
if got := int32(call(strncmp, ptr1, ptr2, size-1)); got <= 0 {
b.Fatal(got)
}
// make ptr1 < ptr2
memory[ptr1+size/2] = 0
if got := int32(call(strncmp, ptr1, ptr2, size-1)); got >= 0 {
b.Fatal(got)
}
// ptr1[:size/2] == ptr2[:size/2]
if got := int32(call(strncmp, ptr1, ptr2, size/2-1)); got != 0 {
b.Fatal(got)
}
}
func Benchmark_strspn(b *testing.B) {
clear(memory)
call(memset, ptr1, 7, size-1)
call(memset, ptr1+size/2, 5, size/2-1)
fill(memory[ptr1:ptr1+size/2], 7)
fill(memory[ptr1+size/2:ptr1+size-1], 5)
memory[ptr2+0] = 3
memory[ptr2+1] = 5
memory[ptr2+2] = 7
@@ -248,21 +179,12 @@ func Benchmark_strspn(b *testing.B) {
for range b.N {
call(strspn, ptr1, ptr2)
}
b.StopTimer()
if got := int32(call(strspn, ptr1, ptr2)); got != size-1 {
b.Fatal(got)
}
memory[ptr1+size/2] = 11
if got := int32(call(strspn, ptr1, ptr2)); got != size/2 {
b.Fatal(got)
}
}
func Benchmark_strcspn(b *testing.B) {
clear(memory)
call(memset, ptr1, 7, size-1)
call(memset, ptr1+size/2, 5, size/2-1)
fill(memory[ptr1:ptr1+size/2], 7)
fill(memory[ptr1+size/2:ptr1+size-1], 5)
memory[ptr2+0] = 3
memory[ptr2+1] = 9
@@ -271,13 +193,237 @@ func Benchmark_strcspn(b *testing.B) {
for range b.N {
call(strcspn, ptr1, ptr2)
}
b.StopTimer()
}
if got := int32(call(strcspn, ptr1, ptr2)); got != size-1 {
b.Fatal(got)
}
memory[ptr1+size/2] = 3
if got := int32(call(strcspn, ptr1, ptr2)); got != size/2 {
b.Fatal(got)
func Test_memchr(t *testing.T) {
for length := range 64 {
for pos := range length + 2 {
for alignment := range 24 {
clear(memory[:2*page])
ptr := (page - 8) + alignment
fill(memory[ptr:ptr+max(pos, length)], 5)
memory[ptr+pos] = 7
want := 0
if pos < length {
want = ptr + pos
}
got := call(memchr, uint64(ptr), 7, uint64(length))
if uint32(got) != uint32(want) {
t.Errorf("memchr(%d, %d, %d) = %d, want %d",
ptr, 7, uint64(length), uint32(got), uint32(want))
}
}
}
clear(memory)
ptr := len(memory) - length
fill(memory[ptr:ptr+length], 5)
memory[len(memory)-1] = 7
want := len(memory) - 1
if length == 0 {
want = 0
}
got := call(memchr, uint64(ptr), 7, uint64(length))
if uint32(got) != uint32(want) {
t.Errorf("memchr(%d, %d, %d) = %d, want %d",
ptr, 7, uint64(length), uint32(got), uint32(want))
}
}
}
func Test_strlen(t *testing.T) {
for length := range 64 {
for alignment := range 24 {
clear(memory[:2*page])
ptr := (page - 8) + alignment
fill(memory[ptr:ptr+length], 5)
got := call(strlen, uint64(ptr))
if uint32(got) != uint32(length) {
t.Errorf("strlen(%d) = %d, want %d",
ptr, uint32(got), uint32(length))
}
memory[ptr-1] = 5
got = call(strlen, uint64(ptr))
if uint32(got) != uint32(length) {
t.Errorf("strlen(%d) = %d, want %d",
ptr, uint32(got), uint32(length))
}
}
clear(memory)
ptr := len(memory) - length - 1
fill(memory[ptr:ptr+length], 5)
got := call(strlen, uint64(ptr))
if uint32(got) != uint32(length) {
t.Errorf("strlen(%d) = %d, want %d",
ptr, uint32(got), uint32(length))
}
}
}
func Test_strchr(t *testing.T) {
for length := range 64 {
for pos := range length + 2 {
for alignment := range 24 {
clear(memory[:2*page])
ptr := (page - 8) + alignment
fill(memory[ptr:ptr+max(pos, length)], 5)
memory[ptr+pos] = 7
memory[ptr+length] = 0
want := 0
if pos < length {
want = ptr + pos
}
got := call(strchr, uint64(ptr), 7)
if uint32(got) != uint32(want) {
t.Errorf("strchr(%d, %d) = %d, want %d",
ptr, 7, uint32(got), uint32(want))
}
}
}
clear(memory)
ptr := len(memory) - length
fill(memory[ptr:ptr+length], 5)
memory[len(memory)-1] = 7
want := len(memory) - 1
if length == 0 {
continue
}
got := call(strchr, uint64(ptr), 7)
if uint32(got) != uint32(want) {
t.Errorf("strchr(%d, %d) = %d, want %d",
ptr, 7, uint32(got), uint32(want))
}
}
}
func Test_strspn(t *testing.T) {
for length := range 64 {
for pos := range length + 2 {
for alignment := range 24 {
clear(memory[:2*page])
ptr := (page - 8) + alignment
fill(memory[ptr:ptr+max(pos, length)], 5)
memory[ptr+pos] = 7
memory[ptr+length] = 0
memory[128] = 3
memory[129] = 5
want := min(pos, length)
got := call(strspn, uint64(ptr), 129)
if uint32(got) != uint32(want) {
t.Errorf("strspn(%d, %d) = %d, want %d",
ptr, 129, uint32(got), uint32(want))
}
got = call(strspn, uint64(ptr), 128)
if uint32(got) != uint32(want) {
t.Errorf("strspn(%d, %d) = %d, want %d",
ptr, 128, uint32(got), uint32(want))
}
}
}
clear(memory)
ptr := len(memory) - length
fill(memory[ptr:ptr+length], 5)
memory[len(memory)-1] = 7
memory[128] = 3
memory[129] = 5
want := length - 1
if length == 0 {
continue
}
got := call(strspn, uint64(ptr), 129)
if uint32(got) != uint32(want) {
t.Errorf("strspn(%d, %d) = %d, want %d",
ptr, 129, uint32(got), uint32(want))
}
got = call(strspn, uint64(ptr), 128)
if uint32(got) != uint32(want) {
t.Errorf("strspn(%d, %d) = %d, want %d",
ptr, 128, uint32(got), uint32(want))
}
}
}
func Test_strcspn(t *testing.T) {
for length := range 64 {
for pos := range length + 2 {
for alignment := range 24 {
clear(memory[:2*page])
ptr := (page - 8) + alignment
fill(memory[ptr:ptr+max(pos, length)], 5)
memory[ptr+pos] = 7
memory[ptr+length] = 0
memory[128] = 3
memory[129] = 7
want := min(pos, length)
got := call(strcspn, uint64(ptr), 129)
if uint32(got) != uint32(want) {
t.Errorf("strcspn(%d, %d) = %d, want %d",
ptr, 129, uint32(got), uint32(want))
}
got = call(strcspn, uint64(ptr), 128)
if uint32(got) != uint32(want) {
t.Errorf("strcspn(%d, %d) = %d, want %d",
ptr, 128, uint32(got), uint32(want))
}
}
}
clear(memory)
ptr := len(memory) - length
fill(memory[ptr:ptr+length], 5)
memory[len(memory)-1] = 7
memory[128] = 3
memory[129] = 7
want := length - 1
if length == 0 {
continue
}
got := call(strcspn, uint64(ptr), 129)
if uint32(got) != uint32(want) {
t.Errorf("strcspn(%d, %d) = %d, want %d",
ptr, 129, uint32(got), uint32(want))
}
got = call(strcspn, uint64(ptr), 128)
if uint32(got) != uint32(want) {
t.Errorf("strcspn(%d, %d) = %d, want %d",
ptr, 128, uint32(got), uint32(want))
}
}
}
func fill(s []byte, v byte) {
for i := range s {
s[i] = v
}
}