From c032c8638ae4b8718228d1a08670c1e264fcdf09 Mon Sep 17 00:00:00 2001 From: Benjamin Oldenburg Date: Sat, 21 Mar 2026 19:02:43 +0000 Subject: [PATCH] Add arm64 encoding and error tests --- tests/tests2/138_arm64_encoding.c | 280 ++++++++++++++++++++++++++++++ tests/tests2/139_arm64_errors.c | 63 +++++++ 2 files changed, 343 insertions(+) create mode 100644 tests/tests2/138_arm64_encoding.c create mode 100644 tests/tests2/139_arm64_errors.c diff --git a/tests/tests2/138_arm64_encoding.c b/tests/tests2/138_arm64_encoding.c new file mode 100644 index 00000000..20aeb390 --- /dev/null +++ b/tests/tests2/138_arm64_encoding.c @@ -0,0 +1,280 @@ +/* ARM64 instruction encoding verification test. + Exercises shift-by-immediate, load/store addressing modes, + conditional branches, and system register access. */ + +#include +#include + +/* ---- shift-by-immediate helpers ---- */ + +static uint32_t lsl32(uint32_t x, int n) { return x << n; } +static uint32_t lsr32(uint32_t x, int n) { return x >> n; } +static int32_t asr32(int32_t x, int n) { return x >> n; } +static uint64_t lsl64(uint64_t x, int n) { return x << n; } +static uint64_t lsr64(uint64_t x, int n) { return x >> n; } +static int64_t asr64(int64_t x, int n) { return x >> n; } + +static void test_shifts(void) +{ + printf("shift-imm:\n"); + printf("%x\n", lsl32(1, 0)); + printf("%x\n", lsl32(1, 15)); + printf("%x\n", lsl32(1, 31)); + printf("%x\n", lsr32(0x80000000U, 31)); + printf("%x\n", lsr32(0x80000000U, 16)); + printf("%x\n", asr32(-1, 1)); + printf("%x\n", asr32(-256, 4)); + printf("%llx\n", (unsigned long long)lsl64(1ULL, 0)); + printf("%llx\n", (unsigned long long)lsl64(1ULL, 32)); + printf("%llx\n", (unsigned long long)lsl64(1ULL, 63)); + printf("%llx\n", (unsigned long long)lsr64(0x8000000000000000ULL, 63)); + printf("%llx\n", (unsigned long long)asr64(-1LL, 1)); + printf("%llx\n", (unsigned long long)asr64(-256LL, 4)); +} + +/* ---- load/store with various addressing modes ---- */ + +static void test_ldr_str(void) +{ + int64_t buf[4] = { 0x1122334455667788LL, 0x99AABBCCDDEEFF00LL, + 0x0F1E2D3C4B5A6978LL, 0x0000000000000001LL }; + int64_t val; + int32_t wval; + int64_t *p; + + printf("ldr-str:\n"); + + /* LDR X, [Xn, #offset] */ + val = buf[0]; + printf("%llx\n", (unsigned long long)val); + val = buf[1]; + printf("%llx\n", (unsigned long long)val); + + /* LDR W, [Xn, #offset] (32-bit load) */ + wval = *(int32_t*)&buf[0]; + printf("%x\n", (unsigned)wval); + + /* Pre-indexed: store pointer, modify */ + p = &buf[0]; + val = *(p + 2); + printf("%llx\n", (unsigned long long)val); + + /* Post-indexed simulation via pointer arithmetic */ + p = &buf[0]; + val = *p; + p++; + printf("%llx %llx\n", (unsigned long long)val, + (unsigned long long)*p); +} + +/* ---- STP/LDP (store/load pair) ---- */ + +static void test_ldp_stp(void) +{ + int64_t src[2] = { 0xAAAABBBBCCCCDDDDLL, 0x1111222233334444LL }; + int64_t dst[2]; + + /* The compiler should use stp/ldp for this */ + dst[0] = src[0]; + dst[1] = src[1]; + + printf("ldp-stp:\n"); + printf("%llx %llx\n", + (unsigned long long)dst[0], + (unsigned long long)dst[1]); +} + +/* ---- CBZ / CBNZ via C patterns ---- */ + +static const char *cbz_test(int x) +{ + if (x == 0) + return "zero"; + return "nonzero"; +} + +static const char *cbnz_test(int x) +{ + if (x != 0) + return "nonzero"; + return "zero"; +} + +static void test_cond_branches(void) +{ + printf("cbz-cbnz:\n"); + printf("%s\n", cbz_test(0)); + printf("%s\n", cbz_test(42)); + printf("%s\n", cbnz_test(0)); + printf("%s\n", cbnz_test(42)); +} + +/* ---- conditional compare patterns (CCMP/CCMN) ---- */ + +static int cond_select(int a, int b) +{ + /* TCC should generate csel or equivalent */ + return a > b ? a : b; +} + +static void test_cond_select(void) +{ + printf("csel:\n"); + printf("%d\n", cond_select(5, 10)); + printf("%d\n", cond_select(10, 5)); + printf("%d\n", cond_select(0, 0)); + printf("%d\n", cond_select(-1, 1)); +} + +/* ---- MRS/MSR system registers (FPCR/FPSR) ---- */ + +static void test_sysregs(void) +{ + unsigned int fpcr, fpsr; + + printf("sysregs:\n"); + + /* Read FPCR */ + __asm__ volatile ("mrs %0, fpcr" : "=r"(fpcr)); + printf("%u\n", fpcr & 0x0F); + + /* Read FPSR */ + __asm__ volatile ("mrs %0, fpsr" : "=r"(fpsr)); + printf("%u\n", fpsr); + + /* Write/restore FPCR (should be same value) */ + __asm__ volatile ("msr fpcr, %0" : : "r"(fpcr)); + + /* Read back and verify */ + { + unsigned int check; + __asm__ volatile ("mrs %0, fpcr" : "=r"(check)); + printf("%s\n", check == fpcr ? "ok" : "fail"); + } +} + +/* ---- NOP encoding (should not crash) ---- */ + +static void test_nop(void) +{ + printf("nop:\n"); + __asm__ volatile ("nop"); + __asm__ volatile ("nop"); + __asm__ volatile ("nop"); + printf("ok\n"); +} + +/* ---- barrier instructions ---- */ + +static void test_barriers(void) +{ + printf("barriers:\n"); + __asm__ volatile ("dmb sy"); + __asm__ volatile ("dsb sy"); + __asm__ volatile ("isb"); + printf("ok\n"); +} + +/* ---- MOV (register) patterns ---- */ + +static int64_t mov_x0_x1(int64_t x) +{ + register int64_t r __asm__("x0") = x; + __asm__ volatile ("" : "=r"(r) : "0"(r)); + return r; +} + +static void test_mov_reg(void) +{ + printf("mov-reg:\n"); + printf("%lld\n", (long long)mov_x0_x1(42)); + printf("%lld\n", (long long)mov_x0_x1(-1)); +} + +/* ---- large struct passing (reference semantics) ---- */ + +struct large { int64_t a, b, c, d; }; + +static int64_t sum_large(struct large s) +{ + return s.a + s.b + s.c + s.d; +} + +static struct large make_large(int64_t a, int64_t b, int64_t c, int64_t d) +{ + struct large s = { a, b, c, d }; + return s; +} + +static void test_large_structs(void) +{ + struct large s = { 1, 2, 3, 4 }; + struct large t; + + printf("large-struct:\n"); + printf("%lld\n", (long long)sum_large(s)); + + t = make_large(10, 20, 30, 40); + printf("%lld %lld %lld %lld\n", + (long long)t.a, (long long)t.b, + (long long)t.c, (long long)t.d); +} + +/* ---- boundary-sized structs ---- */ + +struct s18 { char x[18]; }; +struct s24 { char x[24]; }; +struct s32 { char x[32]; }; + +static void print_s18(struct s18 s) { printf("%.18s\n", s.x); } +static void print_s24(struct s24 s) { printf("%.24s\n", s.x); } +static void print_s32(struct s32 s) { printf("%.32s\n", s.x); } + +static struct s18 ret_s18(void) +{ + struct s18 s = { "123456789012345678" }; + return s; +} + +static struct s24 ret_s24(void) +{ + struct s24 s = { "123456789012345678901234" }; + return s; +} + +static struct s32 ret_s32(void) +{ + struct s32 s = { "12345678901234567890123456789012" }; + return s; +} + +static void test_boundary_structs(void) +{ + struct s18 a; + struct s24 b; + struct s32 c; + + printf("boundary-structs:\n"); + a = ret_s18(); + printf("%.18s\n", a.x); + b = ret_s24(); + printf("%.24s\n", b.x); + c = ret_s32(); + printf("%.32s\n", c.x); +} + +int main(void) +{ + test_shifts(); + test_ldr_str(); + test_ldp_stp(); + test_cond_branches(); + test_cond_select(); + test_sysregs(); + test_nop(); + test_barriers(); + test_mov_reg(); + test_large_structs(); + test_boundary_structs(); + return 0; +} diff --git a/tests/tests2/139_arm64_errors.c b/tests/tests2/139_arm64_errors.c new file mode 100644 index 00000000..0c3ba3ca --- /dev/null +++ b/tests/tests2/139_arm64_errors.c @@ -0,0 +1,63 @@ +/* ARM64 inline assembly error tests. + Verify that invalid assembly produces proper error messages. + Run with -dt; skipped on non-arm64 architectures. */ + +#include + +#if defined test_unknown_instruction +int main(void) +{ + __asm__("fubar x0, x1, x2"); + return 0; +} + +#elif defined test_shift_imm_range_32 +int main(void) +{ + /* LSL by 32 is out of range for 32-bit operand */ + __asm__("lsl w0, w1, #32"); + return 0; +} + +#elif defined test_shift_imm_range_64 +int main(void) +{ + /* LSL by 64 is out of range for 64-bit operand */ + __asm__("lsl x0, x1, #64"); + return 0; +} + +#elif defined test_invalid_sysreg +int main(void) +{ + /* Bogus system register name */ + __asm__("mrs x0, bogusreg"); + return 0; +} + +#elif defined test_invalid_barrier_option +int main(void) +{ + /* Invalid barrier scope name */ + __asm__("dmb xyz"); + return 0; +} + +#elif defined test_extended_inline_asm +int main(void) +{ + int x = 1; + /* Extended inline asm with operands is not implemented */ + __asm__("add %0, %0, #1" : "=r"(x) : "0"(x)); + return 0; +} + +#elif defined test_extended_inline_clobber +int main(void) +{ + /* Extended inline asm with clobbers is not implemented */ + __asm__ volatile ("nop" : : : "x0"); + return 0; +} + +#endif