inline_public_test.h (8919B)
1 #ifndef KIT_TEST_ARCH_INLINE_PUBLIC_TEST_H 2 #define KIT_TEST_ARCH_INLINE_PUBLIC_TEST_H 3 4 #include <kit/cg.h> 5 #include <kit/frontend.h> 6 #include <kit/object.h> 7 8 #include "lib/kit_unit.h" 9 10 /* Inline-asm backend tests build on the shared unit scaffolding: the test env 11 * is a KitUnit (host heap + diag sink that captures last_diag + ctx + 12 * fail/check counters). Only the inline-asm-specific emit/panic/operand 13 * helpers live here; the heap/diag/check/target boilerplate comes from 14 * kit_unit.h. */ 15 typedef KitUnit InlineTestEnv; 16 17 /* Like kit_unit_init but with now=-1, the value this harness has always 18 * used (inert for these byte-level assertions). */ 19 #define it_env_init(env) (kit_unit_init(env), (void)((env)->ctx.now = -1)) 20 21 /* IT_EXPECT / it_contains map onto the shared check + byte-search helpers so 22 * existing call sites read unchanged. */ 23 #define IT_EXPECT(env, cond, ...) CU_EXPECT(env, cond, __VA_ARGS__) 24 #define it_contains kit_unit_contains 25 26 typedef struct InlineText { 27 KitWriter* writer; 28 KitObjFile* file; 29 const uint8_t* data; 30 size_t len; 31 } InlineText; 32 33 typedef void (*InlineBodyFn)(KitCompiler*, KitCg*, KitCgTypeId); 34 35 typedef struct InlineEmit { 36 InlineTestEnv* env; 37 KitObjBuilder* ob; 38 InlineBodyFn body; 39 const char* name; 40 int opt_level; 41 } InlineEmit; 42 43 static inline KitTargetSpec it_target(KitArchKind arch) { 44 KitTargetSpec t; 45 if (arch != KIT_ARCH_ARM_32) return kit_unit_target(arch, KIT_OS_LINUX, KIT_OBJ_ELF); 46 t = kit_unit_target(arch, KIT_OS_FREESTANDING, KIT_OBJ_ELF); 47 t.ptr_size = 4; 48 t.ptr_align = 4; 49 return t; 50 } 51 52 static inline KitStatus it_emit_func(KitCompiler* c, void* user) { 53 InlineEmit* emit = (InlineEmit*)user; 54 KitCg* cg = NULL; 55 KitCgTypeId i64 = kit_cg_type_builtin(c, KIT_CG_BUILTIN_I64); 56 KitCgFuncSig sig; 57 KitCgFuncResult result; 58 KitCgDecl decl; 59 KitCgSym sym; 60 KitCodeOptions opts; 61 62 if (kit_obj_builder_new(c, &emit->ob) != KIT_OK) return KIT_ERR; 63 if (kit_cg_new(c, &cg) != KIT_OK || !cg) return KIT_ERR; 64 memset(&opts, 0, sizeof opts); 65 opts.opt_level = emit->opt_level; 66 if (kit_cg_begin(cg, emit->ob, &opts) != KIT_OK) return KIT_ERR; 67 68 memset(&sig, 0, sizeof sig); 69 memset(&result, 0, sizeof result); 70 result.type = kit_cg_type_builtin(c, KIT_CG_BUILTIN_VOID); 71 sig.result = result; 72 sig.call_conv = KIT_CG_CC_TARGET_C; 73 74 memset(&decl, 0, sizeof decl); 75 decl.kind = KIT_CG_DECL_FUNC; 76 decl.linkage_name = kit_sym_intern(c, kit_slice_cstr(emit->name)); 77 decl.display_name = decl.linkage_name; 78 decl.type = kit_cg_type_func(c, sig); 79 decl.sym.bind = KIT_SB_GLOBAL; 80 decl.sym.visibility = KIT_CG_VIS_DEFAULT; 81 sym = kit_cg_decl(cg, decl); 82 if (sym == KIT_CG_SYM_NONE) return KIT_ERR; 83 84 kit_cg_func_begin(cg, sym); 85 emit->body(c, cg, i64); 86 kit_cg_ret(cg); 87 kit_cg_func_end(cg); 88 if (kit_cg_finish(cg, NULL) != KIT_OK) return KIT_ERR; 89 if (kit_cg_detach(cg) != KIT_OK) return KIT_ERR; 90 kit_cg_free(cg); 91 return KIT_OK; 92 } 93 94 static inline int it_emit_text_opt(InlineTestEnv* env, KitArchKind arch, 95 const char* name, InlineBodyFn body, 96 int opt_level, InlineText* text) { 97 KitCompiler* c = NULL; 98 KitTarget* target = NULL; 99 KitTargetOptions target_opts; 100 InlineEmit emit; 101 KitSlice bytes; 102 size_t len = 0; 103 KitObjSection text_sec; 104 int ok = 0; 105 106 memset(text, 0, sizeof *text); 107 memset(&emit, 0, sizeof emit); 108 emit.env = env; 109 emit.body = body; 110 emit.name = name; 111 emit.opt_level = opt_level; 112 113 memset(&target_opts, 0, sizeof target_opts); 114 target_opts.spec = it_target(arch); 115 if (kit_target_new(&env->ctx, &target_opts, &target) != KIT_OK || !target) { 116 snprintf(env->last_diag, sizeof env->last_diag, "kit_target_new failed"); 117 return 0; 118 } 119 if (kit_compiler_new(target, &env->ctx, &c) != KIT_OK || !c) { 120 snprintf(env->last_diag, sizeof env->last_diag, "kit_compiler_new failed"); 121 kit_target_free(target); 122 return 0; 123 } 124 if (kit_frontend_run(c, it_emit_func, &emit) != KIT_OK) { 125 if (!env->last_diag[0]) 126 snprintf(env->last_diag, sizeof env->last_diag, "kit_frontend_run failed"); 127 goto done; 128 } 129 if (kit_writer_mem(&env->heap, &text->writer) != KIT_OK || !text->writer) { 130 snprintf(env->last_diag, sizeof env->last_diag, "kit_writer_mem failed"); 131 goto done; 132 } 133 if (kit_obj_builder_emit(emit.ob, text->writer) != KIT_OK) { 134 if (!env->last_diag[0]) 135 snprintf(env->last_diag, sizeof env->last_diag, 136 "kit_obj_builder_emit failed"); 137 goto done; 138 } 139 bytes.data = kit_writer_mem_bytes(text->writer, &len); 140 bytes.len = len; 141 if (kit_obj_open(&env->ctx, KIT_SLICE_LIT("<inline-test>"), &bytes, 142 &text->file) != KIT_OK) { 143 if (!env->last_diag[0]) 144 snprintf(env->last_diag, sizeof env->last_diag, "kit_obj_open failed"); 145 goto done; 146 } 147 if (kit_obj_section_by_name(text->file, KIT_SLICE_LIT(".text"), &text_sec) != 148 KIT_OK) { 149 uint32_t nsec = kit_obj_nsections(text->file); 150 uint32_t i; 151 text_sec = KIT_SECTION_NONE; 152 for (i = 0; i < nsec; ++i) { 153 KitObjSecInfo si; 154 if (kit_obj_section(text->file, i, &si) == KIT_OK && 155 si.kind == KIT_SEC_TEXT) { 156 text_sec = i; 157 break; 158 } 159 } 160 if (text_sec == KIT_SECTION_NONE) { 161 snprintf(env->last_diag, sizeof env->last_diag, "text section not found"); 162 goto done; 163 } 164 } 165 if (kit_obj_section_data(text->file, text_sec, &text->data, &text->len) != 166 KIT_OK) { 167 snprintf(env->last_diag, sizeof env->last_diag, 168 "kit_obj_section_data failed"); 169 goto done; 170 } 171 ok = 1; 172 173 done: 174 if (emit.ob) kit_obj_builder_free(emit.ob); 175 kit_compiler_free(c); 176 kit_target_free(target); 177 if (!ok) { 178 if (text->file) kit_obj_free(text->file); 179 if (text->writer) kit_writer_close(text->writer); 180 memset(text, 0, sizeof *text); 181 } 182 return ok; 183 } 184 185 static inline int it_emit_text(InlineTestEnv* env, KitArchKind arch, 186 const char* name, InlineBodyFn body, 187 InlineText* text) { 188 return it_emit_text_opt(env, arch, name, body, 0, text); 189 } 190 191 static inline void it_text_close(InlineText* text) { 192 if (text->file) kit_obj_free(text->file); 193 if (text->writer) kit_writer_close(text->writer); 194 memset(text, 0, sizeof *text); 195 } 196 197 typedef struct InlinePanic { 198 InlineBodyFn body; 199 const char* name; 200 } InlinePanic; 201 202 static inline KitStatus it_run_panic_body(KitCompiler* c, void* user) { 203 InlinePanic* panic = (InlinePanic*)user; 204 InlineEmit emit; 205 KitStatus st; 206 memset(&emit, 0, sizeof emit); 207 emit.body = panic->body; 208 emit.name = panic->name; 209 st = it_emit_func(c, &emit); 210 if (emit.ob) kit_obj_builder_free(emit.ob); 211 return st; 212 } 213 214 static inline int it_expect_panic(InlineTestEnv* env, KitArchKind arch, 215 const char* name, InlineBodyFn body, 216 const char* expected) { 217 KitCompiler* c = NULL; 218 KitTarget* target = NULL; 219 KitTargetOptions target_opts; 220 InlinePanic panic; 221 KitStatus st; 222 int ok; 223 memset(&target_opts, 0, sizeof target_opts); 224 target_opts.spec = it_target(arch); 225 if (kit_target_new(&env->ctx, &target_opts, &target) != KIT_OK || !target) 226 return 0; 227 if (kit_compiler_new(target, &env->ctx, &c) != KIT_OK || !c) { 228 kit_target_free(target); 229 return 0; 230 } 231 panic.body = body; 232 panic.name = name; 233 env->last_diag[0] = '\0'; 234 env->suppress_fatal++; 235 st = kit_frontend_run(c, it_run_panic_body, &panic); 236 env->suppress_fatal--; 237 ok = st == KIT_ERR && (!expected || strstr(env->last_diag, expected) != NULL); 238 kit_compiler_free(c); 239 kit_target_free(target); 240 return ok; 241 } 242 243 static inline KitCgAsmOperand it_asm_op(KitCompiler* c, const char* constraint, 244 const char* name, KitCgTypeId type, 245 KitCgAsmDir dir) { 246 KitCgAsmOperand op; 247 memset(&op, 0, sizeof op); 248 op.constraint = kit_sym_intern(c, kit_slice_cstr(constraint)); 249 op.name = name ? kit_sym_intern(c, kit_slice_cstr(name)) : 0; 250 op.type = type; 251 op.dir = (uint8_t)dir; 252 return op; 253 } 254 255 static inline void it_inline_asm(KitCompiler* c, KitCg* cg, const char* tmpl, 256 const KitCgAsmOperand* outs, uint32_t nouts, 257 const KitCgAsmOperand* ins, uint32_t nins, 258 const char* const* clobber_names, 259 uint32_t nclobbers) { 260 KitCgInlineAsm a; 261 KitSym clobbers[8]; 262 uint32_t i; 263 memset(&a, 0, sizeof a); 264 a.tmpl = kit_sym_intern(c, kit_slice_cstr(tmpl)); 265 a.outputs = outs; 266 a.noutputs = nouts; 267 a.inputs = ins; 268 a.ninputs = nins; 269 if (nclobbers) { 270 for (i = 0; i < nclobbers && i < 8u; ++i) 271 clobbers[i] = kit_sym_intern(c, kit_slice_cstr(clobber_names[i])); 272 a.clobbers = clobbers; 273 a.nclobbers = nclobbers; 274 } 275 kit_cg_inline_asm(cg, a); 276 } 277 278 #endif