aa64_inline_test.c (5313B)
1 /* Public-API unit test for the aarch64 inline-asm backend. */ 2 3 #include <stdint.h> 4 #include <string.h> 5 6 #include "inline_public_test.h" 7 8 #define EXPECTED_MOV_X1_X5 0xaa0503e1u 9 #define EXPECTED_NOP 0xd503201fu 10 #define EXPECTED_ADD_W0_WSP_7 0x11001fe0u 11 /* System-register move (MRS/MSR register form). TPIDR_EL0 is S3_3_C13_C0_2. 12 * MSR TPIDR_EL0, X0 : 0xd51bd040 | Rt (write, L=0) 13 * MRS X1, TPIDR_EL0 : 0xd53bd040 | Rt (read, L=1) */ 14 #define EXPECTED_MSR_TPIDR_X0 0xd51bd040u 15 #define EXPECTED_MRS_X1_TPIDR 0xd53bd041u 16 17 static void put32le(uint8_t out[4], uint32_t v) { 18 out[0] = (uint8_t)v; 19 out[1] = (uint8_t)(v >> 8); 20 out[2] = (uint8_t)(v >> 16); 21 out[3] = (uint8_t)(v >> 24); 22 } 23 24 static void aa64_body(KitCompiler* c, KitCg* cg, KitCgTypeId i64_ty) { 25 KitCgAsmOperand imm; 26 const char* memory_clobber = "memory"; 27 (void)i64_ty; 28 29 it_inline_asm(c, cg, "mov x1, x5", NULL, 0, NULL, 0, NULL, 0); 30 it_inline_asm(c, cg, "nop ; nop", NULL, 0, NULL, 0, NULL, 0); 31 /* System-register thread-pointer access (used by the freestanding cross 32 * startup stub to seed TPIDR_EL0). */ 33 it_inline_asm(c, cg, "msr tpidr_el0, x0", NULL, 0, NULL, 0, NULL, 0); 34 it_inline_asm(c, cg, "mrs x1, tpidr_el0", NULL, 0, NULL, 0, NULL, 0); 35 36 kit_cg_push_int(cg, 7, i64_ty); 37 imm = it_asm_op(c, "i", "imm", i64_ty, KIT_CG_ASM_IN); 38 it_inline_asm(c, cg, "add w0, wsp, %[imm]", NULL, 0, &imm, 1, &memory_clobber, 39 1); 40 } 41 42 static void aa64_bad_add_zr(KitCompiler* c, KitCg* cg, KitCgTypeId i64_ty) { 43 (void)i64_ty; 44 it_inline_asm(c, cg, "add w0, wzr, #7", NULL, 0, NULL, 0, NULL, 0); 45 } 46 47 static void aa64_bad_ldr_zr(KitCompiler* c, KitCg* cg, KitCgTypeId i64_ty) { 48 (void)i64_ty; 49 it_inline_asm(c, cg, "ldr w0, [xzr]", NULL, 0, NULL, 0, NULL, 0); 50 } 51 52 static void aa64_push_local_inputs(KitCompiler* c, KitCg* cg, KitCgTypeId ty, 53 const char* constraint, 54 KitCgAsmOperand* ins, uint32_t n) { 55 KitCgLocal locals[24]; 56 KitCgLocalAttrs attrs; 57 KitCgMemAccess mem; 58 memset(&attrs, 0, sizeof attrs); 59 memset(&mem, 0, sizeof mem); 60 mem.type = ty; 61 mem.align = kit_cg_type_align(c, ty); 62 for (uint32_t i = 0; i < n; ++i) { 63 locals[i] = kit_cg_local(cg, ty, attrs); 64 if (ty == kit_cg_type_builtin(c, KIT_CG_BUILTIN_F64)) 65 kit_cg_push_float(cg, (double)i + 0.5, ty); 66 else 67 kit_cg_push_int(cg, i + 1u, ty); 68 kit_cg_local_write(cg, locals[i], mem); 69 } 70 for (uint32_t i = 0; i < n; ++i) { 71 kit_cg_local_read(cg, locals[i], mem); 72 ins[i] = it_asm_op(c, constraint, NULL, ty, KIT_CG_ASM_IN); 73 } 74 } 75 76 static void aa64_optimized_stage(KitCompiler* c, KitCg* cg, 77 KitCgTypeId i64_ty) { 78 KitCgTypeId f64_ty = kit_cg_type_builtin(c, KIT_CG_BUILTIN_F64); 79 KitCgAsmOperand ins[24]; 80 KitCgAsmOperand outs[6]; 81 82 aa64_push_local_inputs(c, cg, i64_ty, "r", ins, 20); 83 it_inline_asm(c, cg, "", NULL, 0, ins, 20, NULL, 0); 84 85 aa64_push_local_inputs(c, cg, f64_ty, "w", ins, 24); 86 it_inline_asm(c, cg, "", NULL, 0, ins, 24, NULL, 0); 87 88 for (uint32_t i = 0; i < 6u; ++i) 89 outs[i] = it_asm_op(c, i & 1u ? "=w" : "=r", NULL, 90 i & 1u ? f64_ty : i64_ty, KIT_CG_ASM_OUT); 91 it_inline_asm(c, cg, "", outs, 6, NULL, 0, NULL, 0); 92 for (uint32_t i = 0; i < 6u; ++i) kit_cg_drop(cg); 93 } 94 95 int main(void) { 96 InlineTestEnv env; 97 InlineText text; 98 uint8_t pat[12]; 99 100 it_env_init(&env); 101 IT_EXPECT(&env, 102 it_emit_text(&env, KIT_ARCH_ARM_64, "aa64_inline_public", aa64_body, 103 &text), 104 "failed to emit aa64 inline-asm object"); 105 if (text.data) { 106 put32le(pat, EXPECTED_MOV_X1_X5); 107 IT_EXPECT(&env, it_contains(text.data, text.len, pat, 4), 108 "missing mov x1, x5 encoding"); 109 110 put32le(pat, EXPECTED_NOP); 111 put32le(pat + 4, EXPECTED_NOP); 112 IT_EXPECT(&env, it_contains(text.data, text.len, pat, 8), 113 "missing two-nop inline asm encoding"); 114 115 put32le(pat, EXPECTED_ADD_W0_WSP_7); 116 IT_EXPECT(&env, it_contains(text.data, text.len, pat, 4), 117 "missing add w0, wsp, #7 immediate-substitution encoding"); 118 119 put32le(pat, EXPECTED_MSR_TPIDR_X0); 120 IT_EXPECT(&env, it_contains(text.data, text.len, pat, 4), 121 "missing msr tpidr_el0, x0 encoding"); 122 123 put32le(pat, EXPECTED_MRS_X1_TPIDR); 124 IT_EXPECT(&env, it_contains(text.data, text.len, pat, 4), 125 "missing mrs x1, tpidr_el0 encoding"); 126 } 127 it_text_close(&text); 128 129 IT_EXPECT(&env, 130 it_expect_panic(&env, KIT_ARCH_ARM_64, "aa64_bad_add_zr", 131 aa64_bad_add_zr, "zero register"), 132 "expected add w0, wzr, #7 to panic"); 133 IT_EXPECT(&env, 134 it_expect_panic(&env, KIT_ARCH_ARM_64, "aa64_bad_ldr_zr", 135 aa64_bad_ldr_zr, "zero register"), 136 "expected ldr w0, [xzr] to panic"); 137 138 { 139 InlineText opt; 140 IT_EXPECT(&env, 141 it_emit_text_opt(&env, KIT_ARCH_ARM_64, "aa64_optimized_stage", 142 aa64_optimized_stage, 1, &opt), 143 "failed to emit optimized aa64 inline-asm staging case"); 144 it_text_close(&opt); 145 } 146 147 if (env.fails) { 148 fprintf(stderr, "%d failure(s)\n", env.fails); 149 return 1; 150 } 151 printf("aa64_inline_test: ok\n"); 152 return 0; 153 }