History

arm64-win32 support : tests

Benjamin Oldenburg committed 7 months ago

Commit ea823181 parent 03d58b09 files · +972 −0Browse files

Unified · Split

9 files
  1. tests/libtcc_test_mt.c +13 −0
  2. tests/tests2/138_arm64_encoding.c +280 −0
  3. tests/tests2/138_arm64_encoding.expect +50 −0
  4. tests/tests2/139_arm64_errors.c +91 −0
  5. tests/tests2/139_arm64_errors.expect +32 −0
  6. tests/tests2/140_arm64_extasm.c +451 −0
  7. tests/tests2/140_arm64_extasm.expect +36 −0
  8. tests/tests2/73_arm64.c +15 −0
  9. tests/tests2/73_arm64.expect +4 −0
tests/libtcc_test_mt.c+13−0
@@ -338,7 +338,16 @@ int main(int argc, char **argv) · 337 unmodified lines
338338 #else
339339 #include <tcclib.h>
340340
341+#ifdef _WIN32
342+# ifdef __i386__
343+# define LIBTCC_TEST_WINAPI __attribute__((__stdcall__))
344+# else
345+# define LIBTCC_TEST_WINAPI
346+# endif
347+void LIBTCC_TEST_WINAPI Sleep(unsigned int milliseconds);
348+#else
341349 unsigned int sleep(unsigned int seconds);
350+#endif
342351
343352 int fib(n)
344353 {
@@ -347,7 +356,11 @@ int fib(n) · 2 unmodified lines
347356
348357 int main(int argc, char **argv)
349358 {
359+#ifdef _WIN32
360+ Sleep(1000);
361+#else
350362 sleep(1);
363+#endif
351364 printf(" %d", fib(atoi(argv[1])));
352365 return 0;
353366 }
tests/tests2/138_arm64_encoding.c+280−0
@@ -0,0 +1,280 @@
1+/* ARM64 instruction encoding verification test.
2+ Exercises shift-by-immediate, load/store addressing modes,
3+ conditional branches, and system register access. */
4+
5+#include <stdio.h>
6+#include <stdint.h>
7+
8+/* ---- shift-by-immediate helpers ---- */
9+
10+static uint32_t lsl32(uint32_t x, int n) { return x << n; }
11+static uint32_t lsr32(uint32_t x, int n) { return x >> n; }
12+static int32_t asr32(int32_t x, int n) { return x >> n; }
13+static uint64_t lsl64(uint64_t x, int n) { return x << n; }
14+static uint64_t lsr64(uint64_t x, int n) { return x >> n; }
15+static int64_t asr64(int64_t x, int n) { return x >> n; }
16+
17+static void test_shifts(void)
18+{
19+ printf("shift-imm:\n");
20+ printf("%x\n", lsl32(1, 0));
21+ printf("%x\n", lsl32(1, 15));
22+ printf("%x\n", lsl32(1, 31));
23+ printf("%x\n", lsr32(0x80000000U, 31));
24+ printf("%x\n", lsr32(0x80000000U, 16));
25+ printf("%x\n", asr32(-1, 1));
26+ printf("%x\n", asr32(-256, 4));
27+ printf("%llx\n", (unsigned long long)lsl64(1ULL, 0));
28+ printf("%llx\n", (unsigned long long)lsl64(1ULL, 32));
29+ printf("%llx\n", (unsigned long long)lsl64(1ULL, 63));
30+ printf("%llx\n", (unsigned long long)lsr64(0x8000000000000000ULL, 63));
31+ printf("%llx\n", (unsigned long long)asr64(-1LL, 1));
32+ printf("%llx\n", (unsigned long long)asr64(-256LL, 4));
33+}
34+
35+/* ---- load/store with various addressing modes ---- */
36+
37+static void test_ldr_str(void)
38+{
39+ int64_t buf[4] = { 0x1122334455667788LL, 0x99AABBCCDDEEFF00LL,
40+ 0x0F1E2D3C4B5A6978LL, 0x0000000000000001LL };
41+ int64_t val;
42+ int32_t wval;
43+ int64_t *p;
44+
45+ printf("ldr-str:\n");
46+
47+ /* LDR X, [Xn, #offset] */
48+ val = buf[0];
49+ printf("%llx\n", (unsigned long long)val);
50+ val = buf[1];
51+ printf("%llx\n", (unsigned long long)val);
52+
53+ /* LDR W, [Xn, #offset] (32-bit load) */
54+ wval = *(int32_t*)&buf[0];
55+ printf("%x\n", (unsigned)wval);
56+
57+ /* Pre-indexed: store pointer, modify */
58+ p = &buf[0];
59+ val = *(p + 2);
60+ printf("%llx\n", (unsigned long long)val);
61+
62+ /* Post-indexed simulation via pointer arithmetic */
63+ p = &buf[0];
64+ val = *p;
65+ p++;
66+ printf("%llx %llx\n", (unsigned long long)val,
67+ (unsigned long long)*p);
68+}
69+
70+/* ---- STP/LDP (store/load pair) ---- */
71+
72+static void test_ldp_stp(void)
73+{
74+ int64_t src[2] = { 0xAAAABBBBCCCCDDDDLL, 0x1111222233334444LL };
75+ int64_t dst[2];
76+
77+ /* The compiler should use stp/ldp for this */
78+ dst[0] = src[0];
79+ dst[1] = src[1];
80+
81+ printf("ldp-stp:\n");
82+ printf("%llx %llx\n",
83+ (unsigned long long)dst[0],
84+ (unsigned long long)dst[1]);
85+}
86+
87+/* ---- CBZ / CBNZ via C patterns ---- */
88+
89+static const char *cbz_test(int x)
90+{
91+ if (x == 0)
92+ return "zero";
93+ return "nonzero";
94+}
95+
96+static const char *cbnz_test(int x)
97+{
98+ if (x != 0)
99+ return "nonzero";
100+ return "zero";
101+}
102+
103+static void test_cond_branches(void)
104+{
105+ printf("cbz-cbnz:\n");
106+ printf("%s\n", cbz_test(0));
107+ printf("%s\n", cbz_test(42));
108+ printf("%s\n", cbnz_test(0));
109+ printf("%s\n", cbnz_test(42));
110+}
111+
112+/* ---- conditional compare patterns (CCMP/CCMN) ---- */
113+
114+static int cond_select(int a, int b)
115+{
116+ /* TCC should generate csel or equivalent */
117+ return a > b ? a : b;
118+}
119+
120+static void test_cond_select(void)
121+{
122+ printf("csel:\n");
123+ printf("%d\n", cond_select(5, 10));
124+ printf("%d\n", cond_select(10, 5));
125+ printf("%d\n", cond_select(0, 0));
126+ printf("%d\n", cond_select(-1, 1));
127+}
128+
129+/* ---- MRS/MSR system registers (FPCR/FPSR) ---- */
130+
131+static void test_sysregs(void)
132+{
133+ unsigned int fpcr, fpsr;
134+
135+ printf("sysregs:\n");
136+
137+ /* Read FPCR */
138+ __asm__ volatile ("mrs %0, fpcr" : "=r"(fpcr));
139+ printf("%u\n", fpcr & 0x0F);
140+
141+ /* Read FPSR */
142+ __asm__ volatile ("mrs %0, fpsr" : "=r"(fpsr));
143+ printf("%u\n", fpsr);
144+
145+ /* Write/restore FPCR (should be same value) */
146+ __asm__ volatile ("msr fpcr, %0" : : "r"(fpcr));
147+
148+ /* Read back and verify */
149+ {
150+ unsigned int check;
151+ __asm__ volatile ("mrs %0, fpcr" : "=r"(check));
152+ printf("%s\n", check == fpcr ? "ok" : "fail");
153+ }
154+}
155+
156+/* ---- NOP encoding (should not crash) ---- */
157+
158+static void test_nop(void)
159+{
160+ printf("nop:\n");
161+ __asm__ volatile ("nop");
162+ __asm__ volatile ("nop");
163+ __asm__ volatile ("nop");
164+ printf("ok\n");
165+}
166+
167+/* ---- barrier instructions ---- */
168+
169+static void test_barriers(void)
170+{
171+ printf("barriers:\n");
172+ __asm__ volatile ("dmb sy");
173+ __asm__ volatile ("dsb sy");
174+ __asm__ volatile ("isb");
175+ printf("ok\n");
176+}
177+
178+/* ---- MOV (register) patterns ---- */
179+
180+static int64_t mov_x0_x1(int64_t x)
181+{
182+ register int64_t r __asm__("x0") = x;
183+ __asm__ volatile ("" : "=r"(r) : "0"(r));
184+ return r;
185+}
186+
187+static void test_mov_reg(void)
188+{
189+ printf("mov-reg:\n");
190+ printf("%lld\n", (long long)mov_x0_x1(42));
191+ printf("%lld\n", (long long)mov_x0_x1(-1));
192+}
193+
194+/* ---- large struct passing (reference semantics) ---- */
195+
196+struct large { int64_t a, b, c, d; };
197+
198+static int64_t sum_large(struct large s)
199+{
200+ return s.a + s.b + s.c + s.d;
201+}
202+
203+static struct large make_large(int64_t a, int64_t b, int64_t c, int64_t d)
204+{
205+ struct large s = { a, b, c, d };
206+ return s;
207+}
208+
209+static void test_large_structs(void)
210+{
211+ struct large s = { 1, 2, 3, 4 };
212+ struct large t;
213+
214+ printf("large-struct:\n");
215+ printf("%lld\n", (long long)sum_large(s));
216+
217+ t = make_large(10, 20, 30, 40);
218+ printf("%lld %lld %lld %lld\n",
219+ (long long)t.a, (long long)t.b,
220+ (long long)t.c, (long long)t.d);
221+}
222+
223+/* ---- boundary-sized structs ---- */
224+
225+struct s18 { char x[18]; };
226+struct s24 { char x[24]; };
227+struct s32 { char x[32]; };
228+
229+static void print_s18(struct s18 s) { printf("%.18s\n", s.x); }
230+static void print_s24(struct s24 s) { printf("%.24s\n", s.x); }
231+static void print_s32(struct s32 s) { printf("%.32s\n", s.x); }
232+
233+static struct s18 ret_s18(void)
234+{
235+ struct s18 s = { "123456789012345678" };
236+ return s;
237+}
238+
239+static struct s24 ret_s24(void)
240+{
241+ struct s24 s = { "123456789012345678901234" };
242+ return s;
243+}
244+
245+static struct s32 ret_s32(void)
246+{
247+ struct s32 s = { "12345678901234567890123456789012" };
248+ return s;
249+}
250+
251+static void test_boundary_structs(void)
252+{
253+ struct s18 a;
254+ struct s24 b;
255+ struct s32 c;
256+
257+ printf("boundary-structs:\n");
258+ a = ret_s18();
259+ printf("%.18s\n", a.x);
260+ b = ret_s24();
261+ printf("%.24s\n", b.x);
262+ c = ret_s32();
263+ printf("%.32s\n", c.x);
264+}
265+
266+int main(void)
267+{
268+ test_shifts();
269+ test_ldr_str();
270+ test_ldp_stp();
271+ test_cond_branches();
272+ test_cond_select();
273+ test_sysregs();
274+ test_nop();
275+ test_barriers();
276+ test_mov_reg();
277+ test_large_structs();
278+ test_boundary_structs();
279+ return 0;
280+}
tests/tests2/138_arm64_encoding.expect+50−0
@@ -0,0 +1,50 @@
1+shift-imm:
2+1
3+8000
4+80000000
5+1
6+8000
7+ffffffff
8+fffffff0
9+1
10+100000000
11+8000000000000000
12+1
13+ffffffffffffffff
14+fffffffffffffff0
15+ldr-str:
16+1122334455667788
17+99aabbccddeeff00
18+55667788
19+f1e2d3c4b5a6978
20+1122334455667788 99aabbccddeeff00
21+ldp-stp:
22+aaaabbbbccccdddd 1111222233334444
23+cbz-cbnz:
24+zero
25+nonzero
26+zero
27+nonzero
28+csel:
29+10
30+10
31+0
32+1
33+sysregs:
34+0
35+0
36+ok
37+nop:
38+ok
39+barriers:
40+ok
41+mov-reg:
42+42
43+-1
44+large-struct:
45+10
46+10 20 30 40
47+boundary-structs:
48+123456789012345678
49+123456789012345678901234
50+12345678901234567890123456789012
tests/tests2/139_arm64_errors.c+91−0
@@ -0,0 +1,91 @@
1+/* ARM64 inline assembly error tests.
2+ Verify that invalid assembly produces proper error messages.
3+ Run with -dt; skipped on non-arm64 architectures. */
4+
5+#include <stdio.h>
6+
7+#if defined test_unknown_instruction
8+int main(void)
9+{
10+ __asm__("fubar x0, x1, x2");
11+ return 0;
12+}
13+
14+#elif defined test_shift_imm_range_32
15+int main(void)
16+{
17+ /* LSL by 32 is out of range for 32-bit operand */
18+ __asm__("lsl w0, w1, #32");
19+ return 0;
20+}
21+
22+#elif defined test_shift_imm_range_64
23+int main(void)
24+{
25+ /* LSL by 64 is out of range for 64-bit operand */
26+ __asm__("lsl x0, x1, #64");
27+ return 0;
28+}
29+
30+#elif defined test_invalid_sysreg
31+int main(void)
32+{
33+ /* Bogus system register name */
34+ __asm__("mrs x0, bogusreg");
35+ return 0;
36+}
37+
38+#elif defined test_invalid_barrier_option
39+int main(void)
40+{
41+ /* Invalid barrier scope name */
42+ __asm__("dmb xyz");
43+ return 0;
44+}
45+
46+#elif defined test_missing_third_operand
47+int main(void)
48+{
49+ __asm__("add x0, x1");
50+ return 0;
51+}
52+
53+#elif defined test_movz_imm_range
54+int main(void)
55+{
56+ __asm__("movz x0, #0x10000");
57+ return 0;
58+}
59+
60+#elif defined test_movz_shift_range
61+int main(void)
62+{
63+ __asm__("movz x0, #1, lsl #8");
64+ return 0;
65+}
66+
67+#elif defined test_invalid_muls
68+int main(void)
69+{
70+ __asm__("muls x0, x1, x2");
71+ return 0;
72+}
73+
74+#elif defined test_extended_inline_asm
75+int main(void)
76+{
77+ int x = 1;
78+ /* Invalid operand reference in extended inline asm */
79+ __asm__("add %0, %1, #1" : "=r"(x) : "2"(x));
80+ return 0;
81+}
82+
83+#elif defined test_extended_inline_clobber
84+int main(void)
85+{
86+ /* Invalid clobber register name */
87+ __asm__ volatile ("nop" : : : "bogus");
88+ return 0;
89+}
90+
91+#endif
tests/tests2/139_arm64_errors.expect+32−0
@@ -0,0 +1,32 @@
1+[test_unknown_instruction]
2+139_arm64_errors.c:10: error: ARM64 instruction 'fubar' not implemented
3+
4+[test_shift_imm_range_32]
5+139_arm64_errors.c:17: error: shift immediate out of range
6+
7+[test_shift_imm_range_64]
8+139_arm64_errors.c:25: error: shift immediate out of range
9+
10+[test_invalid_sysreg]
11+139_arm64_errors.c:34: error: unsupported system register
12+
13+[test_invalid_barrier_option]
14+139_arm64_errors.c:42: error: invalid operand 'xyz'
15+
16+[test_missing_third_operand]
17+139_arm64_errors.c:48: error: missing third operand
18+
19+[test_movz_imm_range]
20+139_arm64_errors.c:55: error: move wide immediate out of range
21+
22+[test_movz_shift_range]
23+139_arm64_errors.c:62: error: move wide shift out of range
24+
25+[test_invalid_muls]
26+139_arm64_errors.c:70: error: ARM64 instruction 'muls' not implemented
27+
28+[test_extended_inline_asm]
29+139_arm64_errors.c:79: error: invalid reference in constraint 1 ('2')
30+
31+[test_extended_inline_clobber]
32+139_arm64_errors.c:87: error: invalid clobber register 'bogus'
tests/tests2/140_arm64_extasm.c+451−0
@@ -0,0 +1,451 @@
1+/*
2+ * ARM64 Extended Inline Assembly Tests
3+ * Tests for GCC-style extended inline assembly with operands, constraints, and clobbers
4+ */
5+
6+#include <stdio.h>
7+#include <stdint.h>
8+#include <assert.h>
9+
10+struct pair64 {
11+ uint64_t a;
12+ uint64_t b;
13+};
14+
15+static int arm64_symbol_target(void)
16+{
17+ return 7;
18+}
19+
20+static void test_symbolic_address_constraint_compile_only(void)
21+{
22+ asm volatile("" : : "S"(arm64_symbol_target));
23+}
24+
25+/* Test 1: Basic output operand */
26+void test_basic_output(void)
27+{
28+ int x;
29+ asm("mov %0, #42" : "=r"(x));
30+ assert(x == 42);
31+ printf("Test 1 (basic output): PASSED\n");
32+}
33+
34+/* Test 2: Input operand */
35+void test_input_operand(void)
36+{
37+ int x = 10;
38+ int y;
39+ asm("add %0, %1, #5" : "=r"(y) : "r"(x));
40+ assert(y == 15);
41+ printf("Test 2 (input operand): PASSED\n");
42+}
43+
44+/* Test 3: Read-write operand */
45+void test_read_write_operand(void)
46+{
47+ int x = 10;
48+ asm("add %0, %0, #1" : "+r"(x));
49+ assert(x == 11);
50+ printf("Test 3 (read-write operand): PASSED\n");
51+}
52+
53+/* Test 4: Memory operand - load */
54+void test_memory_load(void)
55+{
56+ int x = 42;
57+ int y;
58+ asm("ldr %w0, [%1]" : "=r"(y) : "r"(&x));
59+ assert(y == 42);
60+ printf("Test 4 (memory load): PASSED\n");
61+}
62+
63+/* Test 5: Memory operand - store */
64+void test_memory_store(void)
65+{
66+ int x;
67+ int val = 123;
68+ asm("str %w1, [%0]" : : "r"(&x), "r"(val));
69+ assert(x == 123);
70+ printf("Test 5 (memory store): PASSED\n");
71+}
72+
73+/* Test 5a: Stack memory operand with frame-relative offset */
74+void test_stack_memory_operand(void)
75+{
76+ long x = 0;
77+ long val = 321;
78+
79+ asm volatile("str %0, %1" : : "r"(val), "m"(x));
80+ assert(x == 321);
81+ printf("Test 5a (stack memory operand): PASSED\n");
82+}
83+
84+/* Test 5b: Symbol memory operand */
85+static long arm64_symbol_mem;
86+
87+void test_symbol_memory_operand(void)
88+{
89+ long val = 654;
90+
91+ arm64_symbol_mem = 0;
92+ asm volatile("str %0, %1" : : "r"(val), "m"(arm64_symbol_mem));
93+ assert(arm64_symbol_mem == 654);
94+ printf("Test 5b (symbol memory operand): PASSED\n");
95+}
96+
97+/* Test 6: Clobber list */
98+void test_clobber_list(void)
99+{
100+ int x = 10;
101+ int y = 20;
102+ int result;
103+ asm("add %0, %1, %2"
104+ : "=r"(result)
105+ : "r"(x), "r"(y)
106+ : "cc");
107+ assert(result == 30);
108+ printf("Test 6 (clobber list): PASSED\n");
109+}
110+
111+/* Test 7: Multiple outputs */
112+void test_multiple_outputs(void)
113+{
114+ int a, b;
115+ asm("mov %0, #1; mov %1, #2"
116+ : "=r"(a), "=r"(b));
117+ assert(a == 1 && b == 2);
118+ printf("Test 7 (multiple outputs): PASSED\n");
119+}
120+
121+/* Test 8: Constraint reference */
122+void test_constraint_reference(void)
123+{
124+ int x = 10;
125+ int y;
126+ asm("add %0, %1, #5" : "=r"(y) : "0"(x));
127+ assert(y == 15);
128+ printf("Test 8 (constraint reference): PASSED\n");
129+}
130+
131+/* Test 9: Early clobber */
132+void test_early_clobber(void)
133+{
134+ int x = 10;
135+ int y;
136+ asm("mov %0, #42" : "=&r"(y) : "r"(x));
137+ assert(y == 42);
138+ printf("Test 9 (early clobber): PASSED\n");
139+}
140+
141+/* Test 10: 32-bit register modifier */
142+void test_w_register(void)
143+{
144+ uint32_t x = 100;
145+ uint32_t y;
146+ asm("add %w0, %w1, #50" : "=r"(y) : "r"(x));
147+ assert(y == 150);
148+ printf("Test 10 (w register modifier): PASSED\n");
149+}
150+
151+/* Test 11: Immediate constraint 'I' (12-bit immediate) */
152+void test_immediate_i_constraint(void)
153+{
154+ int x = 100;
155+ int y;
156+ asm("add %0, %1, #200" : "=r"(y) : "r"(x), "I"(200));
157+ assert(y == 300);
158+ printf("Test 11 (immediate I constraint): PASSED\n");
159+}
160+
161+/* Test 12: Register constraint */
162+void test_general_operand_constraint(void)
163+{
164+ int x = 50;
165+ int y;
166+ asm("add %0, %1, #10" : "=r"(y) : "r"(x));
167+ assert(y == 60);
168+ printf("Test 12 (general operand constraint): PASSED\n");
169+}
170+
171+/* Test 13: Multiple inputs and outputs */
172+void test_multiple_io(void)
173+{
174+ int a = 10, b = 20;
175+ int sum, diff;
176+ asm("add %0, %1, %2" : "=r"(sum) : "r"(a), "r"(b));
177+ asm("sub %0, %1, %2" : "=r"(diff) : "r"(a), "r"(b));
178+ assert(sum == 30 && diff == -10);
179+ printf("Test 13 (multiple IO): PASSED\n");
180+}
181+
182+/* Test 14: Register variable preservation */
183+void test_regvar_preservation(void)
184+{
185+ register uint64_t keep asm("x19") = 0x123456789abcdef0ULL;
186+ uint64_t out;
187+
188+ asm volatile("mov x19, #7; add %0, x19, #1"
189+ : "=r"(out)
190+ :
191+ : "x19");
192+ assert(keep == 0x123456789abcdef0ULL);
193+ assert(out == 8);
194+ printf("Test 14 (regvar preservation): PASSED\n");
195+}
196+
197+/* Test 15: Complex arithmetic */
198+void test_complex_arithmetic(void)
199+{
200+ int a = 100, b = 50, c = 25;
201+ int result;
202+ asm("add %0, %1, %2; sub %0, %0, %3"
203+ : "=&r"(result)
204+ : "r"(a), "r"(b), "r"(c));
205+ assert(result == 125);
206+ printf("Test 15 (complex arithmetic): PASSED\n");
207+}
208+
209+/* Test 16: Named operand (GCC extension) */
210+void test_named_operand(void)
211+{
212+ int input = 10;
213+ int output;
214+ asm("add %[out], %[in], #5"
215+ : [out] "=r"(output)
216+ : [in] "r"(input));
217+ assert(output == 15);
218+ printf("Test 16 (named operand): PASSED\n");
219+}
220+
221+/* Test 17: Memory clobber */
222+void test_memory_clobber(void)
223+{
224+ int x = 10;
225+ asm volatile("" : : : "memory");
226+ assert(x == 10);
227+ printf("Test 17 (memory clobber): PASSED\n");
228+}
229+
230+/* Test 18: Condition flags clobber */
231+void test_cc_clobber(void)
232+{
233+ int x = 100;
234+ int y;
235+ asm("adds %0, %1, #0" : "=r"(y) : "r"(x) : "cc");
236+ assert(y == 100);
237+ printf("Test 18 (cc clobber): PASSED\n");
238+}
239+
240+/* Test 19: Large immediate with movz/movk */
241+void test_large_immediate(void)
242+{
243+ uint64_t val;
244+ asm("movz %0, #0x1234, lsl #16; movk %0, #0x5678" : "=r"(val));
245+ assert(val == 0x12345678ULL);
246+ printf("Test 19 (large immediate): PASSED\n");
247+}
248+
249+/* Test 20: Bitwise operations */
250+void test_bitwise_ops(void)
251+{
252+ uint64_t a = 0xf0f0f0f00f0f0f0fULL;
253+ uint64_t b = 0x3333ffff0000ccccULL;
254+ uint64_t andv;
255+ uint64_t orv;
256+ uint64_t xorv;
257+ uint64_t imm_and;
258+
259+ asm("and %0, %1, %2" : "=r"(andv) : "r"(a), "r"(b));
260+ asm("orr %0, %1, %2" : "=r"(orv) : "r"(a), "r"(b));
261+ asm("eor %0, %1, %2" : "=r"(xorv) : "r"(a), "r"(b));
262+ asm("and %0, %1, %2" : "=r"(imm_and)
263+ : "r"(~0ULL), "L"(0xff00ff00ff00ff00ULL));
264+
265+ assert(andv == (a & b));
266+ assert(orv == (a | b));
267+ assert(xorv == (a ^ b));
268+ assert(imm_and == 0xff00ff00ff00ff00ULL);
269+ printf("Test 20 (bitwise ops): PASSED\n");
270+}
271+
272+/* Test 21: Register shift operands */
273+void test_register_shift_operands(void)
274+{
275+ uint64_t val = 3;
276+ uint64_t amount = 4;
277+ uint64_t shifted;
278+ uint64_t rotated;
279+
280+ asm("lsl %0, %1, %2" : "=r"(shifted) : "r"(val), "r"(amount));
281+ asm("ror %0, %1, %2" : "=r"(rotated)
282+ : "r"(0x0123456789abcdefULL), "r"(8ULL));
283+ assert(shifted == 48);
284+ assert(rotated == 0xef0123456789abcdULL);
285+ printf("Test 21 (register shifts): PASSED\n");
286+}
287+
288+/* Test 22: ROR immediate alias of EXTR */
289+void test_ror_immediate(void)
290+{
291+ uint64_t rotated;
292+
293+ asm("ror %0, %1, #8" : "=r"(rotated) : "r"(0x0123456789abcdefULL));
294+ assert(rotated == 0xef0123456789abcdULL);
295+ printf("Test 22 (ror immediate): PASSED\n");
296+}
297+
298+/* Test 23: FP/SIMD register constraint and modifier */
299+void test_fp_register_operand(void)
300+{
301+ double x = 3.5;
302+ double y;
303+
304+ asm("ldr %d0, [%1]" : "=w"(y) : "r"(&x));
305+ assert(y == x);
306+ printf("Test 23 (fp register operand): PASSED\n");
307+}
308+
309+/* Test 24: Zero constraint */
310+void test_zero_constraint(void)
311+{
312+ uint64_t x = 41;
313+ uint64_t y;
314+
315+ asm("add %0, %1, %x2" : "=r"(y) : "r"(x), "Z"(0));
316+ assert(y == x);
317+ printf("Test 24 (Z constraint): PASSED\n");
318+}
319+
320+/* Test 25: 32-bit logical immediate constraint */
321+void test_logical_imm32_constraint(void)
322+{
323+ uint32_t y;
324+
325+ asm("orr %w0, wzr, %1" : "=r"(y) : "K"(0xff));
326+ assert(y == 0xff);
327+ printf("Test 25 (K constraint): PASSED\n");
328+}
329+
330+/* Test 26: 64-bit logical immediate constraint */
331+void test_logical_imm64_constraint(void)
332+{
333+ uint64_t y;
334+
335+ asm("orr %0, xzr, %1" : "=r"(y) : "L"(0xff00ff00ff00ff00ULL));
336+ assert(y == 0xff00ff00ff00ff00ULL);
337+ printf("Test 26 (L constraint): PASSED\n");
338+}
339+
340+/* Test 27: 32-bit MOV pseudo immediate constraint */
341+void test_mov_imm32_constraint(void)
342+{
343+ uint32_t y;
344+
345+ asm("mov %w0, %1" : "=r"(y) : "M"(0x1234));
346+ assert(y == 0x1234);
347+ printf("Test 27 (M constraint): PASSED\n");
348+}
349+
350+/* Test 28: 64-bit MOV pseudo immediate constraint */
351+void test_mov_imm64_constraint(void)
352+{
353+ uint64_t y;
354+
355+ asm("mov %0, %1" : "=r"(y) : "N"(0x12340000ULL));
356+ assert(y == 0x12340000ULL);
357+ printf("Test 28 (N constraint): PASSED\n");
358+}
359+
360+/* Test 29: x FP/SIMD register constraint */
361+void test_x_constraint_fp(void)
362+{
363+ double x = 6.25;
364+ double y;
365+
366+ asm("ldr %d0, [%1]" : "=x"(y) : "r"(&x));
367+ assert(y == x);
368+ printf("Test 29 (x constraint): PASSED\n");
369+}
370+
371+/* Test 30: y FP/SIMD register constraint */
372+void test_y_constraint_fp(void)
373+{
374+ double x = 7.25;
375+ double y;
376+
377+ asm("ldr %d0, [%1]" : "=y"(y) : "r"(&x));
378+ assert(y == x);
379+ printf("Test 30 (y constraint): PASSED\n");
380+}
381+
382+/* Test 31: Q memory constraint */
383+static int arm64_q_load(int *ptr)
384+{
385+ int y;
386+
387+ asm("ldr %w0, %1" : "=r"(y) : "Q"(*ptr));
388+ return y;
389+}
390+
391+void test_q_memory_constraint(void)
392+{
393+ int x = 91;
394+ assert(arm64_q_load(&x) == 91);
395+ printf("Test 31 (Q constraint): PASSED\n");
396+}
397+
398+/* Test 32: Ump pair-memory constraint */
399+void test_ump_memory_constraint(void)
400+{
401+ struct pair64 pair = { 0x1122334455667788ULL, 0x99aabbccddeeff00ULL };
402+ uint64_t a;
403+ uint64_t b;
404+
405+ asm("ldp %0, %1, %2" : "=r"(a), "=r"(b) : "Ump"(pair));
406+ assert(a == pair.a);
407+ assert(b == pair.b);
408+ printf("Test 32 (Ump constraint): PASSED\n");
409+}
410+
411+int main(void)
412+{
413+ printf("ARM64 Extended Inline Assembly Tests\n");
414+ test_basic_output();
415+ test_input_operand();
416+ test_read_write_operand();
417+ test_memory_load();
418+ test_memory_store();
419+ test_stack_memory_operand();
420+ test_symbol_memory_operand();
421+ test_clobber_list();
422+ test_multiple_outputs();
423+ test_constraint_reference();
424+ test_early_clobber();
425+ test_w_register();
426+ test_immediate_i_constraint();
427+ test_general_operand_constraint();
428+ test_multiple_io();
429+ test_regvar_preservation();
430+ test_complex_arithmetic();
431+ test_named_operand();
432+ test_memory_clobber();
433+ test_cc_clobber();
434+ test_large_immediate();
435+ test_bitwise_ops();
436+ test_register_shift_operands();
437+ test_ror_immediate();
438+ test_fp_register_operand();
439+ test_zero_constraint();
440+ test_logical_imm32_constraint();
441+ test_logical_imm64_constraint();
442+ test_mov_imm32_constraint();
443+ test_mov_imm64_constraint();
444+ test_x_constraint_fp();
445+ test_y_constraint_fp();
446+ test_q_memory_constraint();
447+ test_ump_memory_constraint();
448+ test_symbolic_address_constraint_compile_only();
449+ printf("ARM64 Extended Inline Assembly Tests PASSED!\n");
450+ return 0;
451+}
tests/tests2/140_arm64_extasm.expect+36−0
@@ -0,0 +1,36 @@
1+ARM64 Extended Inline Assembly Tests
2+Test 1 (basic output): PASSED
3+Test 2 (input operand): PASSED
4+Test 3 (read-write operand): PASSED
5+Test 4 (memory load): PASSED
6+Test 5 (memory store): PASSED
7+Test 5a (stack memory operand): PASSED
8+Test 5b (symbol memory operand): PASSED
9+Test 6 (clobber list): PASSED
10+Test 7 (multiple outputs): PASSED
11+Test 8 (constraint reference): PASSED
12+Test 9 (early clobber): PASSED
13+Test 10 (w register modifier): PASSED
14+Test 11 (immediate I constraint): PASSED
15+Test 12 (general operand constraint): PASSED
16+Test 13 (multiple IO): PASSED
17+Test 14 (regvar preservation): PASSED
18+Test 15 (complex arithmetic): PASSED
19+Test 16 (named operand): PASSED
20+Test 17 (memory clobber): PASSED
21+Test 18 (cc clobber): PASSED
22+Test 19 (large immediate): PASSED
23+Test 20 (bitwise ops): PASSED
24+Test 21 (register shifts): PASSED
25+Test 22 (ror immediate): PASSED
26+Test 23 (fp register operand): PASSED
27+Test 24 (Z constraint): PASSED
28+Test 25 (K constraint): PASSED
29+Test 26 (L constraint): PASSED
30+Test 27 (M constraint): PASSED
31+Test 28 (N constraint): PASSED
32+Test 29 (x constraint): PASSED
33+Test 30 (y constraint): PASSED
34+Test 31 (Q constraint): PASSED
35+Test 32 (Ump constraint): PASSED
36+ARM64 Extended Inline Assembly Tests PASSED!
tests/tests2/73_arm64.c+15−0
@@ -38,6 +38,11 @@ struct hfa32 { long double a, b; } hfa32 = { 32.1, 32.2 }; · 37 unmodified lines
3838 struct hfa33 { long double a, b, c; } hfa33 = { 33.1, 33.2, 33.3 };
3939 struct hfa34 { long double a, b, c, d; } hfa34 = { 34.1, 34.2, 34.3, 34.4 };
4040
41+struct empty { };
42+/* Keep the top-level offsets at zero without changing the type into a union. */
43+struct hfae12 { struct empty e; struct hfa12 h; } hfae12 = { { }, { 112.1, 112.2 } };
44+struct hfae22 { struct empty e; struct hfa22 h; } hfae22 = { { }, { 122.1, 122.2 } };
45+
4146 void fa_s1(struct s1 a) { printf("%.1s\n", a.x); }
4247 void fa_s2(struct s2 a) { printf("%.2s\n", a.x); }
4348 void fa_s3(struct s3 a) { printf("%.3s\n", a.x); }
@@ -82,6 +87,10 @@ void fa_hfa33(struct hfa33 a) · 38 unmodified lines
8287 { printf("%.1Lf %.1Lf %.1Lf\n", a.a, a.b, a.c); }
8388 void fa_hfa34(struct hfa34 a)
8489 { printf("%.1Lf %.1Lf %.1Lf %.1Lf\n", a.a, a.b, a.c, a.d); }
90+void fa_hfae12(struct hfae12 a)
91+{ printf("%.1f %.1f\n", a.h.a, a.h.b); }
92+void fa_hfae22(struct hfae22 a)
93+{ printf("%.1f %.1f\n", a.h.a, a.h.b); }
8594
8695 void fa1(struct s8 a, struct s9 b, struct s10 c, struct s11 d,
8796 struct s12 e, struct s13 f)
@@ -140,6 +149,8 @@ void arg(void) · 52 unmodified lines
140149 fa_hfa32(hfa32);
141150 fa_hfa33(hfa33);
142151 fa_hfa34(hfa34);
152+ fa_hfae12(hfae12);
153+ fa_hfae22(hfae22);
143154 fa1(s8, s9, s10, s11, s12, s13);
144155 fa2(s9, s10, s11, s12, s13, s14);
145156 fa3(hfa14, hfa23, hfa32);
@@ -178,6 +189,8 @@ struct hfa31 fr_hfa31(void) { return hfa31; } · 32 unmodified lines
178189 struct hfa32 fr_hfa32(void) { return hfa32; }
179190 struct hfa33 fr_hfa33(void) { return hfa33; }
180191 struct hfa34 fr_hfa34(void) { return hfa34; }
192+struct hfae12 fr_hfae12(void) { return hfae12; }
193+struct hfae22 fr_hfae22(void) { return hfae22; }
181194
182195 void ret(void)
183196 {
@@ -228,6 +241,8 @@ void ret(void) · 44 unmodified lines
228241 printf("%.1Lf %.1Lf\n", fr_hfa32().a, fr_hfa32().b);
229242 printf("%.1Lf %.1Lf\n", fr_hfa33().a, fr_hfa33().c);
230243 printf("%.1Lf %.1Lf\n", fr_hfa34().a, fr_hfa34().d);
244+ printf("%.1f %.1f\n", fr_hfae12().h.a, fr_hfae12().h.b);
245+ printf("%.1f %.1f\n", fr_hfae22().h.a, fr_hfae22().h.b);
231246 }
232247
233248 void*
tests/tests2/73_arm64.expect+4−0
@@ -28,6 +28,8 @@ cdefghijklmnopqrs · 27 unmodified lines
2828 32.1 32.1
2929 33.1 33.2 33.3
3030 34.1 34.2 34.3 34.4
31+112.1 112.2
32+122.1 122.2
3133 stu ABC JKL TUV 456 ghi
3234 ABC JKL TUV 456 ghi tuv
3335 14.1 14.4 23.1 23.3 32.1 32.2
@@ -62,6 +64,8 @@ cdefghijklmnopqrs · 28 unmodified lines
6264 32.1 32.2
6365 33.1 33.3
6466 34.1 34.4
67+112.1 112.2
68+122.1 122.2
6569 stdarg:
6670 ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI
6771 lmnopqr ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t