1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
3
4#include <assert.h>
5#include <inttypes.h>
6#include <stdbool.h>
7#include <stdint.h>
8#include <stdio.h>
9#include <string.h>
10
11uint32_t stack_uint8_t(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t e, uint32_t f, uint32_t g, uint32_t h, uint8_t i, uint8_t j, uint32_t k ) {
12 assert(i == 1);
13 assert(j == 2);
14 assert(k == 1024);
15 return a | b | c | d | e | f | g | h | (uint32_t)i | (uint32_t)j | k;
16}
17
18uint32_t reg_uint8_t(uint8_t a, uint8_t b, uint32_t c) {
19 assert(a == 1);
20 assert(b == 2);
21 assert(c == 1024);
22 return a | b | c;
23}
24
25uint32_t stack_string(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t e, uint32_t f, uint32_t g, uint32_t h, const char * i) {
26 assert(i != 0);
27 assert(strcmp(i, "test") == 0);
28 return a | b | c | d | e | f | g | h;
29}
30
31void stack_8i32_3strings(char* result, size_t size, int32_t a1, int32_t a2, int32_t a3, int32_t a4, int32_t a5, int32_t a6, int32_t a7, int32_t a8, const char* s1, const char* s2, const char* s3) {
32 snprintf(result, size, "%d:%d:%d:%d:%d:%d:%d:%d:%s:%s:%s", a1, a2, a3, a4, a5, a6, a7, a8, s1, s2, s3);
33}
34
35// HFA (Homogeneous Float Aggregate) struct with 2 floats
36typedef struct {
37 float x;
38 float y;
39} Float2;
40
41// HFA struct with 4 floats
42typedef struct {
43 float x;
44 float y;
45 float z;
46 float w;
47} Float4;
48
49// Non-HFA struct (mixed types)
50typedef struct {
51 int32_t a;
52 float b;
53} MixedStruct;
54
55// Small struct that fits in one register
56typedef struct {
57 int32_t x;
58 int32_t y;
59} IntPair;
60
61// Test: 8 int registers exhausted, then HFA struct on stack
62void stack_8int_hfa2_stack(char *buf, size_t bufsize, int32_t a1, int32_t a2, int32_t a3, int32_t a4, int32_t a5, int32_t a6, int32_t a7, int32_t a8, Float2 f) {
63 snprintf(buf, bufsize, "%d:%d:%d:%d:%d:%d:%d:%d:%.1f:%.1f",
64 a1, a2, a3, a4, a5, a6, a7, a8, f.x, f.y);
65}
66
67// Test: 8 int registers exhausted, then multiple structs on stack
68void stack_8int_2structs_stack(char *buf, size_t bufsize, int32_t a1, int32_t a2, int32_t a3, int32_t a4, int32_t a5, int32_t a6, int32_t a7, int32_t a8, IntPair p1, IntPair p2) {
69 snprintf(buf, bufsize, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
70 a1, a2, a3, a4, a5, a6, a7, a8, p1.x, p1.y, p2.x, p2.y);
71}
72
73// Test: 8 float registers exhausted, then HFA on stack
74void stack_8float_hfa2_stack(char *buf, size_t bufsize, float f1, float f2, float f3, float f4, float f5, float f6, float f7, float f8, Float2 f) {
75 snprintf(buf, bufsize, "%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f",
76 f1, f2, f3, f4, f5, f6, f7, f8, f.x, f.y);
77}
78
79// Test: mixed - int regs exhausted, float struct can still use float regs
80void stack_8int_hfa2_floatregs(char *buf, size_t bufsize, int32_t a1, int32_t a2, int32_t a3, int32_t a4, int32_t a5, int32_t a6, int32_t a7, int32_t a8, Float2 f) {
81 snprintf(buf, bufsize, "%d:%d:%d:%d:%d:%d:%d:%d:%.1f:%.1f",
82 a1, a2, a3, a4, a5, a6, a7, a8, f.x, f.y);
83}
84
85// Test: primitives and struct interleaved on stack
86void stack_8int_int_struct_int(char *buf, size_t bufsize, int32_t a1, int32_t a2, int32_t a3, int32_t a4, int32_t a5, int32_t a6, int32_t a7, int32_t a8, int32_t a9, IntPair p, int32_t a10) {
87 snprintf(buf, bufsize, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
88 a1, a2, a3, a4, a5, a6, a7, a8, a9, p.x, p.y, a10);
89}
90
91// Test: HFA4 struct on stack (4 floats)
92void stack_8int_hfa4_stack(char *buf, size_t bufsize, int32_t a1, int32_t a2, int32_t a3, int32_t a4, int32_t a5, int32_t a6, int32_t a7, int32_t a8, Float4 f) {
93 snprintf(buf, bufsize, "%d:%d:%d:%d:%d:%d:%d:%d:%.1f:%.1f:%.1f:%.1f",
94 a1, a2, a3, a4, a5, a6, a7, a8, f.x, f.y, f.z, f.w);
95}
96
97// Test: mixed type struct on stack
98void stack_8int_mixed_struct(char *buf, size_t bufsize, int32_t a1, int32_t a2, int32_t a3, int32_t a4, int32_t a5, int32_t a6, int32_t a7, int32_t a8, MixedStruct m) {
99 snprintf(buf, bufsize, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%.1f",
100 a1, a2, a3, a4, a5, a6, a7, a8, m.a, m.b);
101}
102
103void stack_10_int32(char *buf, size_t bufsize, int32_t a1, int32_t a2, int32_t a3, int32_t a4, int32_t a5, int32_t a6, int32_t a7, int32_t a8, int32_t a9, int32_t a10) {
104 snprintf(buf, bufsize, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
105 a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
106}
107
108void stack_11_int32(char *buf, size_t bufsize, int32_t a1, int32_t a2, int32_t a3, int32_t a4, int32_t a5, int32_t a6, int32_t a7, int32_t a8, int32_t a9, int32_t a10, int32_t a11) {
109 snprintf(buf, bufsize, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
110 a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11);
111}
112
113void stack_10_float32(char *buf, size_t bufsize, float f1, float f2, float f3, float f4, float f5, float f6, float f7, float f8, float f9, float f10) {
114 snprintf(buf, bufsize, "%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f",
115 f1, f2, f3, f4, f5, f6, f7, f8, f9, f10);
116}
117
118void stack_mixed_stack_4args(char *buf, size_t bufsize, int32_t a1, int32_t a2, int32_t a3, int32_t a4, int32_t a5, int32_t a6, int32_t a7, int32_t a8, const char *s1, bool b1, int32_t a9, const char *s2) {
119 snprintf(buf, bufsize, "%d:%d:%d:%d:%d:%d:%d:%d:%s:%d:%d:%s",
120 a1, a2, a3, a4, a5, a6, a7, a8, s1, b1, a9, s2);
121}
122
123void stack_20_int32(char *buf, size_t bufsize, int32_t a1, int32_t a2, int32_t a3, int32_t a4, int32_t a5, int32_t a6, int32_t a7, int32_t a8, int32_t a9, int32_t a10, int32_t a11, int32_t a12, int32_t a13, int32_t a14, int32_t a15, int32_t a16, int32_t a17, int32_t a18, int32_t a19, int32_t a20) {
124 snprintf(buf, bufsize, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
125 a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
126}
127
128void stack_25_int64_exceeds(char *buf, size_t bufsize, int64_t a1, int64_t a2, int64_t a3, int64_t a4, int64_t a5, int64_t a6, int64_t a7, int64_t a8, int64_t a9, int64_t a10, int64_t a11, int64_t a12, int64_t a13, int64_t a14, int64_t a15, int64_t a16, int64_t a17, int64_t a18, int64_t a19, int64_t a20, int64_t a21, int64_t a22, int64_t a23, int64_t a24, int64_t a25) {
129 snprintf(buf, bufsize, "%" PRId64 ":%" PRId64 ":%" PRId64 ":%" PRId64 ":%" PRId64 ":%" PRId64 ":%" PRId64 ":%" PRId64 ":%" PRId64 ":%" PRId64 ":%" PRId64 ":%" PRId64 ":%" PRId64 ":%" PRId64 ":%" PRId64 ":%" PRId64 ":%" PRId64 ":%" PRId64 ":%" PRId64 ":%" PRId64 ":%" PRId64 ":%" PRId64 ":%" PRId64 ":%" PRId64 ":%" PRId64,
130 a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25);
131}
132
133uintptr_t stack_20_uintptr(
134 uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5,
135 uintptr_t a6, uintptr_t a7, uintptr_t a8, uintptr_t a9, uintptr_t a10,
136 uintptr_t a11, uintptr_t a12, uintptr_t a13, uintptr_t a14, uintptr_t a15,
137 uintptr_t a16, uintptr_t a17, uintptr_t a18, uintptr_t a19, uintptr_t a20
138) {
139 return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 +
140 a11 + a12 + a13 + a14 + a15 + a16 + a17 + a18 + a19 + a20;
141}
142
143uintptr_t stack_32_uintptr(
144 uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8,
145 uintptr_t a9, uintptr_t a10, uintptr_t a11, uintptr_t a12, uintptr_t a13, uintptr_t a14, uintptr_t a15, uintptr_t a16,
146 uintptr_t a17, uintptr_t a18, uintptr_t a19, uintptr_t a20, uintptr_t a21, uintptr_t a22, uintptr_t a23, uintptr_t a24,
147 uintptr_t a25, uintptr_t a26, uintptr_t a27, uintptr_t a28, uintptr_t a29, uintptr_t a30, uintptr_t a31, uintptr_t a32
148) {
149 return a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 +
150 a9 + a10 + a11 + a12 + a13 + a14 + a15 + a16 +
151 a17 + a18 + a19 + a20 + a21 + a22 + a23 + a24 +
152 a25 + a26 + a27 + a28 + a29 + a30 + a31 + a32;
153}
154
155double stack_32_mixed_int_float(
156 uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8,
157 uintptr_t a9, uintptr_t a10, uintptr_t a11, uintptr_t a12, uintptr_t a13, uintptr_t a14, uintptr_t a15, uintptr_t a16,
158 double f1, double f2, double f3, double f4, double f5, double f6, double f7, double f8,
159 double f9, double f10, double f11, double f12, double f13, double f14, double f15, double f16
160) {
161 return (double)a1 * 1 + (double)a2 * 2 + (double)a3 * 3 + (double)a4 * 4 +
162 (double)a5 * 5 + (double)a6 * 6 + (double)a7 * 7 + (double)a8 * 8 +
163 (double)a9 * 9 + (double)a10 * 10 + (double)a11 * 11 + (double)a12 * 12 +
164 (double)a13 * 13 + (double)a14 * 14 + (double)a15 * 15 + (double)a16 * 16 +
165 f1 * 17 + f2 * 18 + f3 * 19 + f4 * 20 +
166 f5 * 21 + f6 * 22 + f7 * 23 + f8 * 24 +
167 f9 * 25 + f10 * 26 + f11 * 27 + f12 * 28 +
168 f13 * 29 + f14 * 30 + f15 * 31 + f16 * 32;
169}
170
171int64_t arm_int64_unaligned_in_registers(uintptr_t a1, int64_t a2) {
172 return (int64_t)a1 * 123 + a2;
173}
174
175int64_t arm_int64_unaligned_on_stack(uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, int64_t a6) {
176 return (int64_t)a1 * 1 + (int64_t)a2 * 2 + (int64_t)a3 * 3 + (int64_t)a4 * 4 +
177 (int64_t)a5 * 5 + a6;
178}
179
180int64_t arm_int64_unaligned_on_stack_after_floats(
181 uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, /* these args are going to integer registers */
182 float f1, float f2, float f3, float f4, /* these args are going to float registers */
183 float f5, float f6, float f7, float f8,
184 float f9, float f10, float f11, float f12,
185 float f13, float f14, float f15, float f16,
186 float f17, /* this is a first arg on stack */
187 int64_t a5 /* this arg must be padded */
188) {
189 return (int64_t)a1 * 1 + (int64_t)a2 * 2 + (int64_t)a3 * 3 + (int64_t)a4 * 4 + a5;
190}
191
192double arm_float64_unaligned_in_registers(uintptr_t a1, double a2) {
193 return (double)a1 * 123.5 + a2;
194}
195
196double arm_float64_unaligned_on_stack(uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, double a6) {
197 return (double)a1 * 1 + (double)a2 * 2 + (double)a3 * 3 + (double)a4 * 4 +
198 (double)a5 * 5 + a6;
199}
200
201typedef int32_t (*AddFunc)(int32_t, int32_t);
202
203int32_t returned_add(int32_t a, int32_t b) {
204 return a + b;
205}
206
207AddFunc return_func_ptr(void) {
208 return returned_add;
209}
210
211AddFunc return_null_func_ptr(void) {
212 return NULL;
213}