File: callback_packing_test.c

package info (click to toggle)
golang-github-ebitengine-purego 0.10.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,452 kB
  • sloc: asm: 31,862; ansic: 1,001; cpp: 8; makefile: 3
file content (71 lines) | stat: -rw-r--r-- 3,383 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2026 The Ebitengine Authors

#include <stdint.h>
#include <stdbool.h>

// Test: 12 int32 arguments - fills 8 int registers, then 4 go to stack
// With tight packing, the 4 stack args pack into 16 bytes (4x4)
// Without tight packing, they would use 32 bytes (4x8)
typedef int32_t (*callback_12_int32)(int32_t, int32_t, int32_t, int32_t,
                                      int32_t, int32_t, int32_t, int32_t,
                                      int32_t, int32_t, int32_t, int32_t);

int32_t callCallback12Int32(const void *fp) {
    // Using prime numbers to detect argument misalignment
    return ((callback_12_int32)(fp))(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37);
}

// Test: mixed int64 and int32 arguments with stack spillover
// 8 int64s fill registers, then int32/int64/int32 go to stack
// Tests alignment handling when mixing sizes on stack
typedef int64_t (*callback_mixed_stack)(int64_t, int64_t, int64_t, int64_t,
                                         int64_t, int64_t, int64_t, int64_t,
                                         int32_t, int64_t, int32_t);

int64_t callCallbackMixedStack(const void *fp) {
    return ((callback_mixed_stack)(fp))(1, 2, 3, 4, 5, 6, 7, 8, 100, 200, 300);
}

// Test: various small types on stack
// 8 int64s fill registers, then bool/int8/uint8/int16/uint16/int32 go to stack
// Tests byte-level packing of different small types
typedef int64_t (*callback_small_types)(int64_t, int64_t, int64_t, int64_t,
                                         int64_t, int64_t, int64_t, int64_t,
                                         bool, int8_t, uint8_t, int16_t, uint16_t, int32_t);

int64_t callCallbackSmallTypes(const void *fp) {
    return ((callback_small_types)(fp))(1, 2, 3, 4, 5, 6, 7, 8,
                                        true, -42, 200, -1000, 50000, 123456);
}

// Test: 10 int32 arguments - simpler case
// 8 fill registers, 2 go to stack (8 bytes packed vs 16 unpacked)
typedef int32_t (*callback_10_int32)(int32_t, int32_t, int32_t, int32_t,
                                      int32_t, int32_t, int32_t, int32_t,
                                      int32_t, int32_t);

int32_t callCallback10Int32(const void *fp) {
    return ((callback_10_int32)(fp))(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
}

// Test: 10 float64 arguments - fills 8 float registers, then 2 go to stack
// Callback returns int64 since purego callbacks don't support float returns
typedef int64_t (*callback_10_float64)(double, double, double, double,
                                        double, double, double, double,
                                        double, double);

int64_t callCallback10Float64(const void *fp) {
    return ((callback_10_float64)(fp))(1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5, 10.5);
}

// Test: 12 float32 arguments - fills 8 float registers, then 4 go to stack
// Callback returns int64 since purego callbacks don't support float returns
typedef int64_t (*callback_12_float32)(float, float, float, float,
                                        float, float, float, float,
                                        float, float, float, float);

int64_t callCallback12Float32(const void *fp) {
    return ((callback_12_float32)(fp))(1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f,
                                        7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f);
}