kit

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

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