inline_public_test.h (7105B)
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 } InlineEmit; 41 42 static inline KitTargetSpec it_target(KitArchKind arch) { 43 return kit_unit_target(arch, KIT_OS_LINUX, KIT_OBJ_ELF); 44 } 45 46 static inline KitStatus it_emit_func(KitCompiler* c, void* user) { 47 InlineEmit* emit = (InlineEmit*)user; 48 KitCg* cg = NULL; 49 KitCgBuiltinTypes bi; 50 KitCgFuncSig sig; 51 KitCgDecl decl; 52 KitCgSym sym; 53 KitCodeOptions opts; 54 55 if (kit_obj_builder_new(c, &emit->ob) != KIT_OK) return KIT_ERR; 56 if (kit_cg_new(c, &cg) != KIT_OK || !cg) return KIT_ERR; 57 memset(&opts, 0, sizeof opts); 58 if (kit_cg_begin(cg, emit->ob, &opts) != KIT_OK) return KIT_ERR; 59 60 bi = kit_cg_builtin_types(c); 61 memset(&sig, 0, sizeof sig); 62 sig.call_conv = KIT_CG_CC_TARGET_C; 63 64 memset(&decl, 0, sizeof decl); 65 decl.kind = KIT_CG_DECL_FUNC; 66 decl.linkage_name = kit_sym_intern(c, kit_slice_cstr(emit->name)); 67 decl.display_name = decl.linkage_name; 68 decl.type = kit_cg_type_func(c, sig); 69 decl.sym.bind = KIT_SB_GLOBAL; 70 decl.sym.visibility = KIT_CG_VIS_DEFAULT; 71 sym = kit_cg_decl(cg, decl); 72 if (sym == KIT_CG_SYM_NONE) return KIT_ERR; 73 74 kit_cg_func_begin(cg, sym); 75 emit->body(c, cg, bi.id[KIT_CG_BUILTIN_I64]); 76 kit_cg_ret(cg); 77 kit_cg_func_end(cg); 78 if (kit_cg_finish(cg, NULL) != KIT_OK) return KIT_ERR; 79 if (kit_cg_detach(cg) != KIT_OK) return KIT_ERR; 80 kit_cg_free(cg); 81 return KIT_OK; 82 } 83 84 static inline int it_emit_text(InlineTestEnv* env, KitArchKind arch, 85 const char* name, InlineBodyFn body, 86 InlineText* text) { 87 KitCompiler* c = NULL; 88 KitTarget* target = NULL; 89 KitTargetOptions target_opts; 90 InlineEmit emit; 91 KitSlice bytes; 92 size_t len = 0; 93 KitObjSection text_sec; 94 int ok = 0; 95 96 memset(text, 0, sizeof *text); 97 memset(&emit, 0, sizeof emit); 98 emit.env = env; 99 emit.body = body; 100 emit.name = name; 101 102 memset(&target_opts, 0, sizeof target_opts); 103 target_opts.spec = it_target(arch); 104 if (kit_target_new(&env->ctx, &target_opts, &target) != KIT_OK || !target) 105 return 0; 106 if (kit_compiler_new(target, &env->ctx, &c) != KIT_OK || !c) { 107 kit_target_free(target); 108 return 0; 109 } 110 if (kit_frontend_run(c, it_emit_func, &emit) != KIT_OK) goto done; 111 if (kit_writer_mem(&env->heap, &text->writer) != KIT_OK || !text->writer) 112 goto done; 113 if (kit_obj_builder_emit(emit.ob, text->writer) != KIT_OK) goto done; 114 bytes.data = kit_writer_mem_bytes(text->writer, &len); 115 bytes.len = len; 116 if (kit_obj_open(&env->ctx, KIT_SLICE_LIT("<inline-test>"), &bytes, 117 &text->file) != KIT_OK) 118 goto done; 119 if (kit_obj_section_by_name(text->file, KIT_SLICE_LIT(".text"), &text_sec) != 120 KIT_OK) 121 goto done; 122 if (kit_obj_section_data(text->file, text_sec, &text->data, &text->len) != 123 KIT_OK) 124 goto done; 125 ok = 1; 126 127 done: 128 if (emit.ob) kit_obj_builder_free(emit.ob); 129 kit_compiler_free(c); 130 kit_target_free(target); 131 if (!ok) { 132 if (text->file) kit_obj_free(text->file); 133 if (text->writer) kit_writer_close(text->writer); 134 memset(text, 0, sizeof *text); 135 } 136 return ok; 137 } 138 139 static inline void it_text_close(InlineText* text) { 140 if (text->file) kit_obj_free(text->file); 141 if (text->writer) kit_writer_close(text->writer); 142 memset(text, 0, sizeof *text); 143 } 144 145 typedef struct InlinePanic { 146 InlineBodyFn body; 147 const char* name; 148 } InlinePanic; 149 150 static inline KitStatus it_run_panic_body(KitCompiler* c, void* user) { 151 InlinePanic* panic = (InlinePanic*)user; 152 InlineEmit emit; 153 KitStatus st; 154 memset(&emit, 0, sizeof emit); 155 emit.body = panic->body; 156 emit.name = panic->name; 157 st = it_emit_func(c, &emit); 158 if (emit.ob) kit_obj_builder_free(emit.ob); 159 return st; 160 } 161 162 static inline int it_expect_panic(InlineTestEnv* env, KitArchKind arch, 163 const char* name, InlineBodyFn body, 164 const char* expected) { 165 KitCompiler* c = NULL; 166 KitTarget* target = NULL; 167 KitTargetOptions target_opts; 168 InlinePanic panic; 169 KitStatus st; 170 int ok; 171 memset(&target_opts, 0, sizeof target_opts); 172 target_opts.spec = it_target(arch); 173 if (kit_target_new(&env->ctx, &target_opts, &target) != KIT_OK || !target) 174 return 0; 175 if (kit_compiler_new(target, &env->ctx, &c) != KIT_OK || !c) { 176 kit_target_free(target); 177 return 0; 178 } 179 panic.body = body; 180 panic.name = name; 181 env->last_diag[0] = '\0'; 182 env->suppress_fatal++; 183 st = kit_frontend_run(c, it_run_panic_body, &panic); 184 env->suppress_fatal--; 185 ok = st == KIT_ERR && (!expected || strstr(env->last_diag, expected) != NULL); 186 kit_compiler_free(c); 187 kit_target_free(target); 188 return ok; 189 } 190 191 static inline KitCgAsmOperand it_asm_op(KitCompiler* c, const char* constraint, 192 const char* name, KitCgTypeId type, 193 KitCgAsmDir dir) { 194 KitCgAsmOperand op; 195 memset(&op, 0, sizeof op); 196 op.constraint = kit_sym_intern(c, kit_slice_cstr(constraint)); 197 op.name = name ? kit_sym_intern(c, kit_slice_cstr(name)) : 0; 198 op.type = type; 199 op.dir = (uint8_t)dir; 200 return op; 201 } 202 203 static inline void it_inline_asm(KitCompiler* c, KitCg* cg, const char* tmpl, 204 const KitCgAsmOperand* outs, uint32_t nouts, 205 const KitCgAsmOperand* ins, uint32_t nins, 206 const char* const* clobber_names, 207 uint32_t nclobbers) { 208 KitCgInlineAsm a; 209 KitSym clobbers[8]; 210 uint32_t i; 211 memset(&a, 0, sizeof a); 212 a.tmpl = kit_sym_intern(c, kit_slice_cstr(tmpl)); 213 a.outputs = outs; 214 a.noutputs = nouts; 215 a.inputs = ins; 216 a.ninputs = nins; 217 if (nclobbers) { 218 for (i = 0; i < nclobbers && i < 8u; ++i) 219 clobbers[i] = kit_sym_intern(c, kit_slice_cstr(clobber_names[i])); 220 a.clobbers = clobbers; 221 a.nclobbers = nclobbers; 222 } 223 kit_cg_inline_asm(cg, a); 224 } 225 226 #endif