mirror of
git://repo.or.cz/tinycc.git
synced 2026-06-17 15:44:18 +08:00
Add arm64 encoding and error tests
This commit is contained in:
parent
0414fdddbd
commit
c032c8638a
280
tests/tests2/138_arm64_encoding.c
Normal file
280
tests/tests2/138_arm64_encoding.c
Normal file
@ -0,0 +1,280 @@
|
||||
/* ARM64 instruction encoding verification test.
|
||||
Exercises shift-by-immediate, load/store addressing modes,
|
||||
conditional branches, and system register access. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* ---- 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;
|
||||
}
|
||||
63
tests/tests2/139_arm64_errors.c
Normal file
63
tests/tests2/139_arm64_errors.c
Normal file
@ -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 <stdio.h>
|
||||
|
||||
#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
|
||||
Loading…
Reference in New Issue
Block a user