add Int support to amd64 and fix issue with structs not being copied (#288)
Closes #289
- commit
- abe9f9ad3f22fff9704968151e692b015fa97a6f
- author
- TotallyGamerJet · · 2024-10-19 14:18 UTC
- committer
- GitHub · · 2024-10-19 14:18 UTC
- parent
- 450319b
- signature
- GPG Unverified
B5690EEEBB952194The key is unknown
3 files · +50 -16
M struct_amd64.go +4 -16
| @@ -111,7 +111,7 @@ func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFl | |||
| 111 | 111 | return keepAlive | |
| 112 | 112 | } | |
| 113 | 113 | ||
| 114 | - | func postMerger(t reflect.Type) bool { | |
| 114 | + | func postMerger(t reflect.Type) (passInMemory bool) { | |
| 115 | 115 | // (c) If the size of the aggregate exceeds two eightbytes and the first eight- byte isn’t SSE or any other | |
| 116 | 116 | // eightbyte isn’t SSEUP, the whole argument is passed in memory. | |
| 117 | 117 | if t.Kind() != reflect.Struct { | |
| @@ -120,19 +120,7 @@ func postMerger(t reflect.Type) bool { | |||
| 120 | 120 | if t.Size() <= 2*8 { | |
| 121 | 121 | return false | |
| 122 | 122 | } | |
| 123 | - | first := getFirst(t).Kind() | |
| 124 | - | if first != reflect.Float32 && first != reflect.Float64 { | |
| 125 | - | return false | |
| 126 | - | } | |
| 127 | - | return true | |
| 128 | - | } | |
| 129 | - | ||
| 130 | - | func getFirst(t reflect.Type) reflect.Type { | |
| 131 | - | first := t.Field(0).Type | |
| 132 | - | if first.Kind() == reflect.Struct { | |
| 133 | - | return getFirst(first) | |
| 134 | - | } | |
| 135 | - | return first | |
| 123 | + | return true // Go does not have an SSE/SEEUP type so this is always true | |
| 136 | 124 | } | |
| 137 | 125 | ||
| 138 | 126 | func tryPlaceRegister(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) (ok bool) { | |
| @@ -196,7 +184,7 @@ func tryPlaceRegister(v reflect.Value, addFloat func(uintptr), addInt func(uintp | |||
| 196 | 184 | val |= uint64(f.Int()&0xFFFF_FFFF) << shift | |
| 197 | 185 | shift += 32 | |
| 198 | 186 | class |= _INTEGER | |
| 199 | - | case reflect.Int64: | |
| 187 | + | case reflect.Int64, reflect.Int: | |
| 200 | 188 | val = uint64(f.Int()) | |
| 201 | 189 | shift = 64 | |
| 202 | 190 | class = _INTEGER | |
| @@ -212,7 +200,7 @@ func tryPlaceRegister(v reflect.Value, addFloat func(uintptr), addInt func(uintp | |||
| 212 | 200 | val |= f.Uint() << shift | |
| 213 | 201 | shift += 32 | |
| 214 | 202 | class |= _INTEGER | |
| 215 | - | case reflect.Uint64: | |
| 203 | + | case reflect.Uint64, reflect.Uint: | |
| 216 | 204 | val = f.Uint() | |
| 217 | 205 | shift = 64 | |
| 218 | 206 | class = _INTEGER | |
| @@ -111,7 +111,7 @@ func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFl | |||||
| 111 | return keepAlive | 111 | return keepAlive | ||
| 112 | } | 112 | } | ||
| 113 | 113 | ||||
| 114 | - | func postMerger(t reflect.Type) bool { | 114 | + | func postMerger(t reflect.Type) (passInMemory bool) { |
| 115 | // (c) If the size of the aggregate exceeds two eightbytes and the first eight- byte isn’t SSE or any other | 115 | // (c) If the size of the aggregate exceeds two eightbytes and the first eight- byte isn’t SSE or any other | ||
| 116 | // eightbyte isn’t SSEUP, the whole argument is passed in memory. | 116 | // eightbyte isn’t SSEUP, the whole argument is passed in memory. | ||
| 117 | if t.Kind() != reflect.Struct { | 117 | if t.Kind() != reflect.Struct { | ||
| @@ -120,19 +120,7 @@ func postMerger(t reflect.Type) bool { | |||||
| 120 | if t.Size() <= 2*8 { | 120 | if t.Size() <= 2*8 { | ||
| 121 | return false | 121 | return false | ||
| 122 | } | 122 | } | ||
| 123 | - | first := getFirst(t).Kind() | 123 | + | return true // Go does not have an SSE/SEEUP type so this is always true |
| 124 | - | if first != reflect.Float32 && first != reflect.Float64 { | |||
| 125 | - | return false | |||
| 126 | - | } | |||
| 127 | - | return true | |||
| 128 | - | } | |||
| 129 | - | ||||
| 130 | - | func getFirst(t reflect.Type) reflect.Type { | |||
| 131 | - | first := t.Field(0).Type | |||
| 132 | - | if first.Kind() == reflect.Struct { | |||
| 133 | - | return getFirst(first) | |||
| 134 | - | } | |||
| 135 | - | return first | |||
| 136 | } | 124 | } | ||
| 137 | 125 | ||||
| 138 | func tryPlaceRegister(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) (ok bool) { | 126 | func tryPlaceRegister(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) (ok bool) { | ||
| @@ -196,7 +184,7 @@ func tryPlaceRegister(v reflect.Value, addFloat func(uintptr), addInt func(uintp | |||||
| 196 | val |= uint64(f.Int()&0xFFFF_FFFF) << shift | 184 | val |= uint64(f.Int()&0xFFFF_FFFF) << shift | ||
| 197 | shift += 32 | 185 | shift += 32 | ||
| 198 | class |= _INTEGER | 186 | class |= _INTEGER | ||
| 199 | - | case reflect.Int64: | 187 | + | case reflect.Int64, reflect.Int: |
| 200 | val = uint64(f.Int()) | 188 | val = uint64(f.Int()) | ||
| 201 | shift = 64 | 189 | shift = 64 | ||
| 202 | class = _INTEGER | 190 | class = _INTEGER | ||
| @@ -212,7 +200,7 @@ func tryPlaceRegister(v reflect.Value, addFloat func(uintptr), addInt func(uintp | |||||
| 212 | val |= f.Uint() << shift | 200 | val |= f.Uint() << shift | ||
| 213 | shift += 32 | 201 | shift += 32 | ||
| 214 | class |= _INTEGER | 202 | class |= _INTEGER | ||
| 215 | - | case reflect.Uint64: | 203 | + | case reflect.Uint64, reflect.Uint: |
| 216 | val = f.Uint() | 204 | val = f.Uint() | ||
| 217 | shift = 64 | 205 | shift = 64 | ||
| 218 | class = _INTEGER | 206 | class = _INTEGER | ||
M struct_test.go +23 -0
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | package purego_test | |
| 7 | 7 | ||
| 8 | 8 | import ( | |
| 9 | + | "math" | |
| 9 | 10 | "os" | |
| 10 | 11 | "path/filepath" | |
| 11 | 12 | "runtime" | |
| @@ -440,6 +441,28 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||
| 440 | 441 | t.Fatalf("InitWithContentRect returned %d wanted %#x", ret, expectedUnsigned) | |
| 441 | 442 | } | |
| 442 | 443 | } | |
| 444 | + | { | |
| 445 | + | type GoInt4 struct { | |
| 446 | + | A, B, C, D int | |
| 447 | + | } | |
| 448 | + | var GoInt4Fn func(GoInt4) int | |
| 449 | + | purego.RegisterLibFunc(&GoInt4Fn, lib, "GoInt4") | |
| 450 | + | const expected = math.MaxInt - 52 - 3 + 4 | |
| 451 | + | if ret := GoInt4Fn(GoInt4{math.MaxInt, -52, 3, 4}); ret != expected { | |
| 452 | + | t.Fatalf("GoInt4Fn returned %d wanted %#x", ret, expected) | |
| 453 | + | } | |
| 454 | + | } | |
| 455 | + | { | |
| 456 | + | type GoUint4 struct { | |
| 457 | + | A, B, C, D uint | |
| 458 | + | } | |
| 459 | + | var GoUint4Fn func(GoUint4) uint | |
| 460 | + | purego.RegisterLibFunc(&GoUint4Fn, lib, "GoUint4") | |
| 461 | + | const expected = 1_000_000 + 53 + 71 + 8 | |
| 462 | + | if ret := GoUint4Fn(GoUint4{1_000_000, 53, 71, 8}); ret != expected { | |
| 463 | + | t.Fatalf("GoUint4Fn returned %d wanted %#x", ret, expected) | |
| 464 | + | } | |
| 465 | + | } | |
| 443 | 466 | } | |
| 444 | 467 | ||
| 445 | 468 | func TestRegisterFunc_structReturns(t *testing.T) { | |
| @@ -6,6 +6,7 @@ | |||||
| 6 | package purego_test | 6 | package purego_test | ||
| 7 | 7 | ||||
| 8 | import ( | 8 | import ( | ||
| 9 | + | "math" | |||
| 9 | "os" | 10 | "os" | ||
| 10 | "path/filepath" | 11 | "path/filepath" | ||
| 11 | "runtime" | 12 | "runtime" | ||
| @@ -440,6 +441,28 @@ func TestRegisterFunc_structArgs(t *testing.T) { | |||||
| 440 | t.Fatalf("InitWithContentRect returned %d wanted %#x", ret, expectedUnsigned) | 441 | t.Fatalf("InitWithContentRect returned %d wanted %#x", ret, expectedUnsigned) | ||
| 441 | } | 442 | } | ||
| 442 | } | 443 | } | ||
| 444 | + | { | |||
| 445 | + | type GoInt4 struct { | |||
| 446 | + | A, B, C, D int | |||
| 447 | + | } | |||
| 448 | + | var GoInt4Fn func(GoInt4) int | |||
| 449 | + | purego.RegisterLibFunc(&GoInt4Fn, lib, "GoInt4") | |||
| 450 | + | const expected = math.MaxInt - 52 - 3 + 4 | |||
| 451 | + | if ret := GoInt4Fn(GoInt4{math.MaxInt, -52, 3, 4}); ret != expected { | |||
| 452 | + | t.Fatalf("GoInt4Fn returned %d wanted %#x", ret, expected) | |||
| 453 | + | } | |||
| 454 | + | } | |||
| 455 | + | { | |||
| 456 | + | type GoUint4 struct { | |||
| 457 | + | A, B, C, D uint | |||
| 458 | + | } | |||
| 459 | + | var GoUint4Fn func(GoUint4) uint | |||
| 460 | + | purego.RegisterLibFunc(&GoUint4Fn, lib, "GoUint4") | |||
| 461 | + | const expected = 1_000_000 + 53 + 71 + 8 | |||
| 462 | + | if ret := GoUint4Fn(GoUint4{1_000_000, 53, 71, 8}); ret != expected { | |||
| 463 | + | t.Fatalf("GoUint4Fn returned %d wanted %#x", ret, expected) | |||
| 464 | + | } | |||
| 465 | + | } | |||
| 443 | } | 466 | } | ||
| 444 | 467 | ||||
| 445 | func TestRegisterFunc_structReturns(t *testing.T) { | 468 | func TestRegisterFunc_structReturns(t *testing.T) { | ||
M testdata/structtest/struct_test.c +23 -0
| @@ -1,6 +1,13 @@ | |||
| 1 | 1 | // SPDX-License-Identifier: Apache-2.0 | |
| 2 | 2 | // SPDX-FileCopyrightText: 2024 The Ebitengine Authors | |
| 3 | 3 | ||
| 4 | + | #include "stdint.h" | |
| 5 | + | ||
| 6 | + | #if defined(__x86_64__) || defined(__aarch64__) | |
| 7 | + | typedef int64_t GoInt; | |
| 8 | + | typedef uint64_t GoUint; | |
| 9 | + | #endif | |
| 10 | + | ||
| 4 | 11 | // Empty is empty | |
| 5 | 12 | struct Empty {}; | |
| 6 | 13 | ||
| @@ -325,3 +332,19 @@ unsigned long InitWithContentRect(int *win, struct Content c, int style, int bac | |||
| 325 | 332 | return 0xF1A6; // FLAG | |
| 326 | 333 | return (unsigned long)(c.point.x + c.point.y + c.size.width + c.size.height) / (style - backing); | |
| 327 | 334 | } | |
| 335 | + | ||
| 336 | + | struct GoInt4 { | |
| 337 | + | GoInt a, b, c, d; | |
| 338 | + | }; | |
| 339 | + | ||
| 340 | + | GoInt GoInt4(struct GoInt4 g) { | |
| 341 | + | return g.a + g.b - g.c + g.d; | |
| 342 | + | } | |
| 343 | + | ||
| 344 | + | struct GoUint4 { | |
| 345 | + | GoUint a, b, c, d; | |
| 346 | + | }; | |
| 347 | + | ||
| 348 | + | GoUint GoUint4(struct GoUint4 g) { | |
| 349 | + | return g.a + g.b + g.c + g.d; | |
| 350 | + | } | |
| @@ -1,6 +1,13 @@ | |||||
| 1 | // SPDX-License-Identifier: Apache-2.0 | 1 | // SPDX-License-Identifier: Apache-2.0 | ||
| 2 | // SPDX-FileCopyrightText: 2024 The Ebitengine Authors | 2 | // SPDX-FileCopyrightText: 2024 The Ebitengine Authors | ||
| 3 | 3 | ||||
| 4 | + | #include "stdint.h" | |||
| 5 | + | ||||
| 6 | + | #if defined(__x86_64__) || defined(__aarch64__) | |||
| 7 | + | typedef int64_t GoInt; | |||
| 8 | + | typedef uint64_t GoUint; | |||
| 9 | + | #endif | |||
| 10 | + | ||||
| 4 | // Empty is empty | 11 | // Empty is empty | ||
| 5 | struct Empty {}; | 12 | struct Empty {}; | ||
| 6 | 13 | ||||
| @@ -325,3 +332,19 @@ unsigned long InitWithContentRect(int *win, struct Content c, int style, int bac | |||||
| 325 | return 0xF1A6; // FLAG | 332 | return 0xF1A6; // FLAG | ||
| 326 | return (unsigned long)(c.point.x + c.point.y + c.size.width + c.size.height) / (style - backing); | 333 | return (unsigned long)(c.point.x + c.point.y + c.size.width + c.size.height) / (style - backing); | ||
| 327 | } | 334 | } | ||
| 335 | + | ||||
| 336 | + | struct GoInt4 { | |||
| 337 | + | GoInt a, b, c, d; | |||
| 338 | + | }; | |||
| 339 | + | ||||
| 340 | + | GoInt GoInt4(struct GoInt4 g) { | |||
| 341 | + | return g.a + g.b - g.c + g.d; | |||
| 342 | + | } | |||
| 343 | + | ||||
| 344 | + | struct GoUint4 { | |||
| 345 | + | GoUint a, b, c, d; | |||
| 346 | + | }; | |||
| 347 | + | ||||
| 348 | + | GoUint GoUint4(struct GoUint4 g) { | |||
| 349 | + | return g.a + g.b + g.c + g.d; | |||
| 350 | + | } | |||