kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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