mirror of
git://repo.or.cz/tinycc.git
synced 2026-06-17 15:44:18 +08:00
arm64-win32 support : tests
This commit is contained in:
parent
03d58b0746
commit
ea823189d6
@ -338,7 +338,16 @@ int main(int argc, char **argv)
|
||||
#else
|
||||
#include <tcclib.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifdef __i386__
|
||||
# define LIBTCC_TEST_WINAPI __attribute__((__stdcall__))
|
||||
# else
|
||||
# define LIBTCC_TEST_WINAPI
|
||||
# endif
|
||||
void LIBTCC_TEST_WINAPI Sleep(unsigned int milliseconds);
|
||||
#else
|
||||
unsigned int sleep(unsigned int seconds);
|
||||
#endif
|
||||
|
||||
int fib(n)
|
||||
{
|
||||
@ -347,7 +356,11 @@ int fib(n)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
Sleep(1000);
|
||||
#else
|
||||
sleep(1);
|
||||
#endif
|
||||
printf(" %d", fib(atoi(argv[1])));
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
50
tests/tests2/138_arm64_encoding.expect
Normal file
50
tests/tests2/138_arm64_encoding.expect
Normal file
@ -0,0 +1,50 @@
|
||||
shift-imm:
|
||||
1
|
||||
8000
|
||||
80000000
|
||||
1
|
||||
8000
|
||||
ffffffff
|
||||
fffffff0
|
||||
1
|
||||
100000000
|
||||
8000000000000000
|
||||
1
|
||||
ffffffffffffffff
|
||||
fffffffffffffff0
|
||||
ldr-str:
|
||||
1122334455667788
|
||||
99aabbccddeeff00
|
||||
55667788
|
||||
f1e2d3c4b5a6978
|
||||
1122334455667788 99aabbccddeeff00
|
||||
ldp-stp:
|
||||
aaaabbbbccccdddd 1111222233334444
|
||||
cbz-cbnz:
|
||||
zero
|
||||
nonzero
|
||||
zero
|
||||
nonzero
|
||||
csel:
|
||||
10
|
||||
10
|
||||
0
|
||||
1
|
||||
sysregs:
|
||||
0
|
||||
0
|
||||
ok
|
||||
nop:
|
||||
ok
|
||||
barriers:
|
||||
ok
|
||||
mov-reg:
|
||||
42
|
||||
-1
|
||||
large-struct:
|
||||
10
|
||||
10 20 30 40
|
||||
boundary-structs:
|
||||
123456789012345678
|
||||
123456789012345678901234
|
||||
12345678901234567890123456789012
|
||||
91
tests/tests2/139_arm64_errors.c
Normal file
91
tests/tests2/139_arm64_errors.c
Normal file
@ -0,0 +1,91 @@
|
||||
/* 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_missing_third_operand
|
||||
int main(void)
|
||||
{
|
||||
__asm__("add x0, x1");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined test_movz_imm_range
|
||||
int main(void)
|
||||
{
|
||||
__asm__("movz x0, #0x10000");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined test_movz_shift_range
|
||||
int main(void)
|
||||
{
|
||||
__asm__("movz x0, #1, lsl #8");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined test_invalid_muls
|
||||
int main(void)
|
||||
{
|
||||
__asm__("muls x0, x1, x2");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined test_extended_inline_asm
|
||||
int main(void)
|
||||
{
|
||||
int x = 1;
|
||||
/* Invalid operand reference in extended inline asm */
|
||||
__asm__("add %0, %1, #1" : "=r"(x) : "2"(x));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined test_extended_inline_clobber
|
||||
int main(void)
|
||||
{
|
||||
/* Invalid clobber register name */
|
||||
__asm__ volatile ("nop" : : : "bogus");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
32
tests/tests2/139_arm64_errors.expect
Normal file
32
tests/tests2/139_arm64_errors.expect
Normal file
@ -0,0 +1,32 @@
|
||||
[test_unknown_instruction]
|
||||
139_arm64_errors.c:10: error: ARM64 instruction 'fubar' not implemented
|
||||
|
||||
[test_shift_imm_range_32]
|
||||
139_arm64_errors.c:17: error: shift immediate out of range
|
||||
|
||||
[test_shift_imm_range_64]
|
||||
139_arm64_errors.c:25: error: shift immediate out of range
|
||||
|
||||
[test_invalid_sysreg]
|
||||
139_arm64_errors.c:34: error: unsupported system register
|
||||
|
||||
[test_invalid_barrier_option]
|
||||
139_arm64_errors.c:42: error: invalid operand 'xyz'
|
||||
|
||||
[test_missing_third_operand]
|
||||
139_arm64_errors.c:48: error: missing third operand
|
||||
|
||||
[test_movz_imm_range]
|
||||
139_arm64_errors.c:55: error: move wide immediate out of range
|
||||
|
||||
[test_movz_shift_range]
|
||||
139_arm64_errors.c:62: error: move wide shift out of range
|
||||
|
||||
[test_invalid_muls]
|
||||
139_arm64_errors.c:70: error: ARM64 instruction 'muls' not implemented
|
||||
|
||||
[test_extended_inline_asm]
|
||||
139_arm64_errors.c:79: error: invalid reference in constraint 1 ('2')
|
||||
|
||||
[test_extended_inline_clobber]
|
||||
139_arm64_errors.c:87: error: invalid clobber register 'bogus'
|
||||
451
tests/tests2/140_arm64_extasm.c
Normal file
451
tests/tests2/140_arm64_extasm.c
Normal file
@ -0,0 +1,451 @@
|
||||
/*
|
||||
* ARM64 Extended Inline Assembly Tests
|
||||
* Tests for GCC-style extended inline assembly with operands, constraints, and clobbers
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
struct pair64 {
|
||||
uint64_t a;
|
||||
uint64_t b;
|
||||
};
|
||||
|
||||
static int arm64_symbol_target(void)
|
||||
{
|
||||
return 7;
|
||||
}
|
||||
|
||||
static void test_symbolic_address_constraint_compile_only(void)
|
||||
{
|
||||
asm volatile("" : : "S"(arm64_symbol_target));
|
||||
}
|
||||
|
||||
/* Test 1: Basic output operand */
|
||||
void test_basic_output(void)
|
||||
{
|
||||
int x;
|
||||
asm("mov %0, #42" : "=r"(x));
|
||||
assert(x == 42);
|
||||
printf("Test 1 (basic output): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 2: Input operand */
|
||||
void test_input_operand(void)
|
||||
{
|
||||
int x = 10;
|
||||
int y;
|
||||
asm("add %0, %1, #5" : "=r"(y) : "r"(x));
|
||||
assert(y == 15);
|
||||
printf("Test 2 (input operand): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 3: Read-write operand */
|
||||
void test_read_write_operand(void)
|
||||
{
|
||||
int x = 10;
|
||||
asm("add %0, %0, #1" : "+r"(x));
|
||||
assert(x == 11);
|
||||
printf("Test 3 (read-write operand): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 4: Memory operand - load */
|
||||
void test_memory_load(void)
|
||||
{
|
||||
int x = 42;
|
||||
int y;
|
||||
asm("ldr %w0, [%1]" : "=r"(y) : "r"(&x));
|
||||
assert(y == 42);
|
||||
printf("Test 4 (memory load): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 5: Memory operand - store */
|
||||
void test_memory_store(void)
|
||||
{
|
||||
int x;
|
||||
int val = 123;
|
||||
asm("str %w1, [%0]" : : "r"(&x), "r"(val));
|
||||
assert(x == 123);
|
||||
printf("Test 5 (memory store): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 5a: Stack memory operand with frame-relative offset */
|
||||
void test_stack_memory_operand(void)
|
||||
{
|
||||
long x = 0;
|
||||
long val = 321;
|
||||
|
||||
asm volatile("str %0, %1" : : "r"(val), "m"(x));
|
||||
assert(x == 321);
|
||||
printf("Test 5a (stack memory operand): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 5b: Symbol memory operand */
|
||||
static long arm64_symbol_mem;
|
||||
|
||||
void test_symbol_memory_operand(void)
|
||||
{
|
||||
long val = 654;
|
||||
|
||||
arm64_symbol_mem = 0;
|
||||
asm volatile("str %0, %1" : : "r"(val), "m"(arm64_symbol_mem));
|
||||
assert(arm64_symbol_mem == 654);
|
||||
printf("Test 5b (symbol memory operand): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 6: Clobber list */
|
||||
void test_clobber_list(void)
|
||||
{
|
||||
int x = 10;
|
||||
int y = 20;
|
||||
int result;
|
||||
asm("add %0, %1, %2"
|
||||
: "=r"(result)
|
||||
: "r"(x), "r"(y)
|
||||
: "cc");
|
||||
assert(result == 30);
|
||||
printf("Test 6 (clobber list): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 7: Multiple outputs */
|
||||
void test_multiple_outputs(void)
|
||||
{
|
||||
int a, b;
|
||||
asm("mov %0, #1; mov %1, #2"
|
||||
: "=r"(a), "=r"(b));
|
||||
assert(a == 1 && b == 2);
|
||||
printf("Test 7 (multiple outputs): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 8: Constraint reference */
|
||||
void test_constraint_reference(void)
|
||||
{
|
||||
int x = 10;
|
||||
int y;
|
||||
asm("add %0, %1, #5" : "=r"(y) : "0"(x));
|
||||
assert(y == 15);
|
||||
printf("Test 8 (constraint reference): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 9: Early clobber */
|
||||
void test_early_clobber(void)
|
||||
{
|
||||
int x = 10;
|
||||
int y;
|
||||
asm("mov %0, #42" : "=&r"(y) : "r"(x));
|
||||
assert(y == 42);
|
||||
printf("Test 9 (early clobber): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 10: 32-bit register modifier */
|
||||
void test_w_register(void)
|
||||
{
|
||||
uint32_t x = 100;
|
||||
uint32_t y;
|
||||
asm("add %w0, %w1, #50" : "=r"(y) : "r"(x));
|
||||
assert(y == 150);
|
||||
printf("Test 10 (w register modifier): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 11: Immediate constraint 'I' (12-bit immediate) */
|
||||
void test_immediate_i_constraint(void)
|
||||
{
|
||||
int x = 100;
|
||||
int y;
|
||||
asm("add %0, %1, #200" : "=r"(y) : "r"(x), "I"(200));
|
||||
assert(y == 300);
|
||||
printf("Test 11 (immediate I constraint): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 12: Register constraint */
|
||||
void test_general_operand_constraint(void)
|
||||
{
|
||||
int x = 50;
|
||||
int y;
|
||||
asm("add %0, %1, #10" : "=r"(y) : "r"(x));
|
||||
assert(y == 60);
|
||||
printf("Test 12 (general operand constraint): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 13: Multiple inputs and outputs */
|
||||
void test_multiple_io(void)
|
||||
{
|
||||
int a = 10, b = 20;
|
||||
int sum, diff;
|
||||
asm("add %0, %1, %2" : "=r"(sum) : "r"(a), "r"(b));
|
||||
asm("sub %0, %1, %2" : "=r"(diff) : "r"(a), "r"(b));
|
||||
assert(sum == 30 && diff == -10);
|
||||
printf("Test 13 (multiple IO): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 14: Register variable preservation */
|
||||
void test_regvar_preservation(void)
|
||||
{
|
||||
register uint64_t keep asm("x19") = 0x123456789abcdef0ULL;
|
||||
uint64_t out;
|
||||
|
||||
asm volatile("mov x19, #7; add %0, x19, #1"
|
||||
: "=r"(out)
|
||||
:
|
||||
: "x19");
|
||||
assert(keep == 0x123456789abcdef0ULL);
|
||||
assert(out == 8);
|
||||
printf("Test 14 (regvar preservation): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 15: Complex arithmetic */
|
||||
void test_complex_arithmetic(void)
|
||||
{
|
||||
int a = 100, b = 50, c = 25;
|
||||
int result;
|
||||
asm("add %0, %1, %2; sub %0, %0, %3"
|
||||
: "=&r"(result)
|
||||
: "r"(a), "r"(b), "r"(c));
|
||||
assert(result == 125);
|
||||
printf("Test 15 (complex arithmetic): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 16: Named operand (GCC extension) */
|
||||
void test_named_operand(void)
|
||||
{
|
||||
int input = 10;
|
||||
int output;
|
||||
asm("add %[out], %[in], #5"
|
||||
: [out] "=r"(output)
|
||||
: [in] "r"(input));
|
||||
assert(output == 15);
|
||||
printf("Test 16 (named operand): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 17: Memory clobber */
|
||||
void test_memory_clobber(void)
|
||||
{
|
||||
int x = 10;
|
||||
asm volatile("" : : : "memory");
|
||||
assert(x == 10);
|
||||
printf("Test 17 (memory clobber): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 18: Condition flags clobber */
|
||||
void test_cc_clobber(void)
|
||||
{
|
||||
int x = 100;
|
||||
int y;
|
||||
asm("adds %0, %1, #0" : "=r"(y) : "r"(x) : "cc");
|
||||
assert(y == 100);
|
||||
printf("Test 18 (cc clobber): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 19: Large immediate with movz/movk */
|
||||
void test_large_immediate(void)
|
||||
{
|
||||
uint64_t val;
|
||||
asm("movz %0, #0x1234, lsl #16; movk %0, #0x5678" : "=r"(val));
|
||||
assert(val == 0x12345678ULL);
|
||||
printf("Test 19 (large immediate): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 20: Bitwise operations */
|
||||
void test_bitwise_ops(void)
|
||||
{
|
||||
uint64_t a = 0xf0f0f0f00f0f0f0fULL;
|
||||
uint64_t b = 0x3333ffff0000ccccULL;
|
||||
uint64_t andv;
|
||||
uint64_t orv;
|
||||
uint64_t xorv;
|
||||
uint64_t imm_and;
|
||||
|
||||
asm("and %0, %1, %2" : "=r"(andv) : "r"(a), "r"(b));
|
||||
asm("orr %0, %1, %2" : "=r"(orv) : "r"(a), "r"(b));
|
||||
asm("eor %0, %1, %2" : "=r"(xorv) : "r"(a), "r"(b));
|
||||
asm("and %0, %1, %2" : "=r"(imm_and)
|
||||
: "r"(~0ULL), "L"(0xff00ff00ff00ff00ULL));
|
||||
|
||||
assert(andv == (a & b));
|
||||
assert(orv == (a | b));
|
||||
assert(xorv == (a ^ b));
|
||||
assert(imm_and == 0xff00ff00ff00ff00ULL);
|
||||
printf("Test 20 (bitwise ops): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 21: Register shift operands */
|
||||
void test_register_shift_operands(void)
|
||||
{
|
||||
uint64_t val = 3;
|
||||
uint64_t amount = 4;
|
||||
uint64_t shifted;
|
||||
uint64_t rotated;
|
||||
|
||||
asm("lsl %0, %1, %2" : "=r"(shifted) : "r"(val), "r"(amount));
|
||||
asm("ror %0, %1, %2" : "=r"(rotated)
|
||||
: "r"(0x0123456789abcdefULL), "r"(8ULL));
|
||||
assert(shifted == 48);
|
||||
assert(rotated == 0xef0123456789abcdULL);
|
||||
printf("Test 21 (register shifts): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 22: ROR immediate alias of EXTR */
|
||||
void test_ror_immediate(void)
|
||||
{
|
||||
uint64_t rotated;
|
||||
|
||||
asm("ror %0, %1, #8" : "=r"(rotated) : "r"(0x0123456789abcdefULL));
|
||||
assert(rotated == 0xef0123456789abcdULL);
|
||||
printf("Test 22 (ror immediate): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 23: FP/SIMD register constraint and modifier */
|
||||
void test_fp_register_operand(void)
|
||||
{
|
||||
double x = 3.5;
|
||||
double y;
|
||||
|
||||
asm("ldr %d0, [%1]" : "=w"(y) : "r"(&x));
|
||||
assert(y == x);
|
||||
printf("Test 23 (fp register operand): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 24: Zero constraint */
|
||||
void test_zero_constraint(void)
|
||||
{
|
||||
uint64_t x = 41;
|
||||
uint64_t y;
|
||||
|
||||
asm("add %0, %1, %x2" : "=r"(y) : "r"(x), "Z"(0));
|
||||
assert(y == x);
|
||||
printf("Test 24 (Z constraint): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 25: 32-bit logical immediate constraint */
|
||||
void test_logical_imm32_constraint(void)
|
||||
{
|
||||
uint32_t y;
|
||||
|
||||
asm("orr %w0, wzr, %1" : "=r"(y) : "K"(0xff));
|
||||
assert(y == 0xff);
|
||||
printf("Test 25 (K constraint): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 26: 64-bit logical immediate constraint */
|
||||
void test_logical_imm64_constraint(void)
|
||||
{
|
||||
uint64_t y;
|
||||
|
||||
asm("orr %0, xzr, %1" : "=r"(y) : "L"(0xff00ff00ff00ff00ULL));
|
||||
assert(y == 0xff00ff00ff00ff00ULL);
|
||||
printf("Test 26 (L constraint): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 27: 32-bit MOV pseudo immediate constraint */
|
||||
void test_mov_imm32_constraint(void)
|
||||
{
|
||||
uint32_t y;
|
||||
|
||||
asm("mov %w0, %1" : "=r"(y) : "M"(0x1234));
|
||||
assert(y == 0x1234);
|
||||
printf("Test 27 (M constraint): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 28: 64-bit MOV pseudo immediate constraint */
|
||||
void test_mov_imm64_constraint(void)
|
||||
{
|
||||
uint64_t y;
|
||||
|
||||
asm("mov %0, %1" : "=r"(y) : "N"(0x12340000ULL));
|
||||
assert(y == 0x12340000ULL);
|
||||
printf("Test 28 (N constraint): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 29: x FP/SIMD register constraint */
|
||||
void test_x_constraint_fp(void)
|
||||
{
|
||||
double x = 6.25;
|
||||
double y;
|
||||
|
||||
asm("ldr %d0, [%1]" : "=x"(y) : "r"(&x));
|
||||
assert(y == x);
|
||||
printf("Test 29 (x constraint): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 30: y FP/SIMD register constraint */
|
||||
void test_y_constraint_fp(void)
|
||||
{
|
||||
double x = 7.25;
|
||||
double y;
|
||||
|
||||
asm("ldr %d0, [%1]" : "=y"(y) : "r"(&x));
|
||||
assert(y == x);
|
||||
printf("Test 30 (y constraint): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 31: Q memory constraint */
|
||||
static int arm64_q_load(int *ptr)
|
||||
{
|
||||
int y;
|
||||
|
||||
asm("ldr %w0, %1" : "=r"(y) : "Q"(*ptr));
|
||||
return y;
|
||||
}
|
||||
|
||||
void test_q_memory_constraint(void)
|
||||
{
|
||||
int x = 91;
|
||||
assert(arm64_q_load(&x) == 91);
|
||||
printf("Test 31 (Q constraint): PASSED\n");
|
||||
}
|
||||
|
||||
/* Test 32: Ump pair-memory constraint */
|
||||
void test_ump_memory_constraint(void)
|
||||
{
|
||||
struct pair64 pair = { 0x1122334455667788ULL, 0x99aabbccddeeff00ULL };
|
||||
uint64_t a;
|
||||
uint64_t b;
|
||||
|
||||
asm("ldp %0, %1, %2" : "=r"(a), "=r"(b) : "Ump"(pair));
|
||||
assert(a == pair.a);
|
||||
assert(b == pair.b);
|
||||
printf("Test 32 (Ump constraint): PASSED\n");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("ARM64 Extended Inline Assembly Tests\n");
|
||||
test_basic_output();
|
||||
test_input_operand();
|
||||
test_read_write_operand();
|
||||
test_memory_load();
|
||||
test_memory_store();
|
||||
test_stack_memory_operand();
|
||||
test_symbol_memory_operand();
|
||||
test_clobber_list();
|
||||
test_multiple_outputs();
|
||||
test_constraint_reference();
|
||||
test_early_clobber();
|
||||
test_w_register();
|
||||
test_immediate_i_constraint();
|
||||
test_general_operand_constraint();
|
||||
test_multiple_io();
|
||||
test_regvar_preservation();
|
||||
test_complex_arithmetic();
|
||||
test_named_operand();
|
||||
test_memory_clobber();
|
||||
test_cc_clobber();
|
||||
test_large_immediate();
|
||||
test_bitwise_ops();
|
||||
test_register_shift_operands();
|
||||
test_ror_immediate();
|
||||
test_fp_register_operand();
|
||||
test_zero_constraint();
|
||||
test_logical_imm32_constraint();
|
||||
test_logical_imm64_constraint();
|
||||
test_mov_imm32_constraint();
|
||||
test_mov_imm64_constraint();
|
||||
test_x_constraint_fp();
|
||||
test_y_constraint_fp();
|
||||
test_q_memory_constraint();
|
||||
test_ump_memory_constraint();
|
||||
test_symbolic_address_constraint_compile_only();
|
||||
printf("ARM64 Extended Inline Assembly Tests PASSED!\n");
|
||||
return 0;
|
||||
}
|
||||
36
tests/tests2/140_arm64_extasm.expect
Normal file
36
tests/tests2/140_arm64_extasm.expect
Normal file
@ -0,0 +1,36 @@
|
||||
ARM64 Extended Inline Assembly Tests
|
||||
Test 1 (basic output): PASSED
|
||||
Test 2 (input operand): PASSED
|
||||
Test 3 (read-write operand): PASSED
|
||||
Test 4 (memory load): PASSED
|
||||
Test 5 (memory store): PASSED
|
||||
Test 5a (stack memory operand): PASSED
|
||||
Test 5b (symbol memory operand): PASSED
|
||||
Test 6 (clobber list): PASSED
|
||||
Test 7 (multiple outputs): PASSED
|
||||
Test 8 (constraint reference): PASSED
|
||||
Test 9 (early clobber): PASSED
|
||||
Test 10 (w register modifier): PASSED
|
||||
Test 11 (immediate I constraint): PASSED
|
||||
Test 12 (general operand constraint): PASSED
|
||||
Test 13 (multiple IO): PASSED
|
||||
Test 14 (regvar preservation): PASSED
|
||||
Test 15 (complex arithmetic): PASSED
|
||||
Test 16 (named operand): PASSED
|
||||
Test 17 (memory clobber): PASSED
|
||||
Test 18 (cc clobber): PASSED
|
||||
Test 19 (large immediate): PASSED
|
||||
Test 20 (bitwise ops): PASSED
|
||||
Test 21 (register shifts): PASSED
|
||||
Test 22 (ror immediate): PASSED
|
||||
Test 23 (fp register operand): PASSED
|
||||
Test 24 (Z constraint): PASSED
|
||||
Test 25 (K constraint): PASSED
|
||||
Test 26 (L constraint): PASSED
|
||||
Test 27 (M constraint): PASSED
|
||||
Test 28 (N constraint): PASSED
|
||||
Test 29 (x constraint): PASSED
|
||||
Test 30 (y constraint): PASSED
|
||||
Test 31 (Q constraint): PASSED
|
||||
Test 32 (Ump constraint): PASSED
|
||||
ARM64 Extended Inline Assembly Tests PASSED!
|
||||
@ -38,6 +38,11 @@ struct hfa32 { long double a, b; } hfa32 = { 32.1, 32.2 };
|
||||
struct hfa33 { long double a, b, c; } hfa33 = { 33.1, 33.2, 33.3 };
|
||||
struct hfa34 { long double a, b, c, d; } hfa34 = { 34.1, 34.2, 34.3, 34.4 };
|
||||
|
||||
struct empty { };
|
||||
/* Keep the top-level offsets at zero without changing the type into a union. */
|
||||
struct hfae12 { struct empty e; struct hfa12 h; } hfae12 = { { }, { 112.1, 112.2 } };
|
||||
struct hfae22 { struct empty e; struct hfa22 h; } hfae22 = { { }, { 122.1, 122.2 } };
|
||||
|
||||
void fa_s1(struct s1 a) { printf("%.1s\n", a.x); }
|
||||
void fa_s2(struct s2 a) { printf("%.2s\n", a.x); }
|
||||
void fa_s3(struct s3 a) { printf("%.3s\n", a.x); }
|
||||
@ -82,6 +87,10 @@ void fa_hfa33(struct hfa33 a)
|
||||
{ printf("%.1Lf %.1Lf %.1Lf\n", a.a, a.b, a.c); }
|
||||
void fa_hfa34(struct hfa34 a)
|
||||
{ printf("%.1Lf %.1Lf %.1Lf %.1Lf\n", a.a, a.b, a.c, a.d); }
|
||||
void fa_hfae12(struct hfae12 a)
|
||||
{ printf("%.1f %.1f\n", a.h.a, a.h.b); }
|
||||
void fa_hfae22(struct hfae22 a)
|
||||
{ printf("%.1f %.1f\n", a.h.a, a.h.b); }
|
||||
|
||||
void fa1(struct s8 a, struct s9 b, struct s10 c, struct s11 d,
|
||||
struct s12 e, struct s13 f)
|
||||
@ -140,6 +149,8 @@ void arg(void)
|
||||
fa_hfa32(hfa32);
|
||||
fa_hfa33(hfa33);
|
||||
fa_hfa34(hfa34);
|
||||
fa_hfae12(hfae12);
|
||||
fa_hfae22(hfae22);
|
||||
fa1(s8, s9, s10, s11, s12, s13);
|
||||
fa2(s9, s10, s11, s12, s13, s14);
|
||||
fa3(hfa14, hfa23, hfa32);
|
||||
@ -178,6 +189,8 @@ struct hfa31 fr_hfa31(void) { return hfa31; }
|
||||
struct hfa32 fr_hfa32(void) { return hfa32; }
|
||||
struct hfa33 fr_hfa33(void) { return hfa33; }
|
||||
struct hfa34 fr_hfa34(void) { return hfa34; }
|
||||
struct hfae12 fr_hfae12(void) { return hfae12; }
|
||||
struct hfae22 fr_hfae22(void) { return hfae22; }
|
||||
|
||||
void ret(void)
|
||||
{
|
||||
@ -228,6 +241,8 @@ void ret(void)
|
||||
printf("%.1Lf %.1Lf\n", fr_hfa32().a, fr_hfa32().b);
|
||||
printf("%.1Lf %.1Lf\n", fr_hfa33().a, fr_hfa33().c);
|
||||
printf("%.1Lf %.1Lf\n", fr_hfa34().a, fr_hfa34().d);
|
||||
printf("%.1f %.1f\n", fr_hfae12().h.a, fr_hfae12().h.b);
|
||||
printf("%.1f %.1f\n", fr_hfae22().h.a, fr_hfae22().h.b);
|
||||
}
|
||||
|
||||
void*
|
||||
|
||||
@ -28,6 +28,8 @@ cdefghijklmnopqrs
|
||||
32.1 32.1
|
||||
33.1 33.2 33.3
|
||||
34.1 34.2 34.3 34.4
|
||||
112.1 112.2
|
||||
122.1 122.2
|
||||
stu ABC JKL TUV 456 ghi
|
||||
ABC JKL TUV 456 ghi tuv
|
||||
14.1 14.4 23.1 23.3 32.1 32.2
|
||||
@ -62,6 +64,8 @@ cdefghijklmnopqrs
|
||||
32.1 32.2
|
||||
33.1 33.3
|
||||
34.1 34.4
|
||||
112.1 112.2
|
||||
122.1 122.2
|
||||
stdarg:
|
||||
ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI
|
||||
lmnopqr ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI
|
||||
|
||||
Loading…
Reference in New Issue
Block a user