commit f136952600e679611fe15d4b1b35fa01c05ad0ef
parent 7cdfa2286fcf7310e20656c9873ad62f59661971
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Wed, 3 Jun 2026 11:13:57 -0700
Introduce target feature model
Diffstat:
100 files changed, 1801 insertions(+), 368 deletions(-)
diff --git a/driver/cmd/as.c b/driver/cmd/as.c
@@ -18,7 +18,7 @@ typedef struct AsOptions {
int debug_info; /* -g */
const char* output_path; /* -o */
const char* source; /* single positional input */
- KitTarget target; /* -target TRIPLE; host default */
+ KitTargetSpec target; /* -target TRIPLE; host default */
} AsOptions;
static void as_usage(void) {
@@ -71,7 +71,7 @@ void driver_help_as(void) {
/* Returns 0 on success; non-zero on bad args (already reported). */
static int as_parse(int argc, char** argv, AsOptions* o, DriverEnv* env,
- DriverCflags* cf) {
+ DriverCflags* cf, DriverTargetFeatures* tf) {
int i;
o->target = driver_host_target();
@@ -111,6 +111,13 @@ static int as_parse(int argc, char** argv, AsOptions* o, DriverEnv* env,
continue;
}
+ {
+ int tr =
+ driver_target_features_try_consume(tf, env, AS_TOOL, argc, argv, &i);
+ if (tr < 0) return 1;
+ if (tr > 0) continue;
+ }
+
if (a[0] == '-' && a[1] != '\0') {
driver_errf(AS_TOOL, "unknown flag: %.*s",
KIT_SLICE_ARG(kit_slice_cstr(a)));
@@ -140,8 +147,10 @@ int driver_as(int argc, char** argv) {
DriverEnv env;
AsOptions o = {0};
DriverCflags cf = {0};
+ DriverTargetFeatures tf = {0};
KitContext ctx;
KitPreprocessOptions pp;
+ KitTarget* target = NULL;
KitCompiler* compiler = NULL;
KitWriter* writer = NULL;
KitWriter* pp_writer = NULL;
@@ -162,13 +171,17 @@ int driver_as(int argc, char** argv) {
driver_env_init(&env);
- if (driver_cflags_init(&cf, &env, argc) != 0) {
+ if (driver_cflags_init(&cf, &env, argc) != 0 ||
+ driver_target_features_init(&tf, &env, argc) != 0) {
driver_errf(AS_TOOL, "out of memory");
+ driver_target_features_fini(&tf, &env);
+ driver_cflags_fini(&cf, &env);
driver_env_fini(&env);
return 2;
}
- if (as_parse(argc, argv, &o, &env, &cf) != 0) {
+ if (as_parse(argc, argv, &o, &env, &cf, &tf) != 0) {
+ driver_target_features_fini(&tf, &env);
driver_cflags_fini(&cf, &env);
driver_env_fini(&env);
return 2;
@@ -191,7 +204,8 @@ int driver_as(int argc, char** argv) {
goto out;
}
- if (driver_compiler_new(o.target, &ctx, &compiler) != KIT_OK) {
+ if (driver_target_new(&ctx, o.target, &tf, AS_TOOL, &target) != KIT_OK ||
+ driver_compiler_new(target, &ctx, &compiler) != KIT_OK) {
driver_errf(AS_TOOL, "failed to initialize compiler");
goto out;
}
@@ -246,9 +260,11 @@ int driver_as(int argc, char** argv) {
out:
if (compiler) driver_compiler_free(compiler);
+ kit_target_free(target);
if (pp_writer) kit_writer_close(pp_writer);
if (writer) kit_writer_close(writer);
if (loaded) ctx.file_io->release(ctx.file_io->user, &src);
+ driver_target_features_fini(&tf, &env);
driver_cflags_fini(&cf, &env);
driver_env_fini(&env);
return rc;
diff --git a/driver/cmd/cc.c b/driver/cmd/cc.c
@@ -126,7 +126,7 @@ typedef struct CcOptions {
int data_sections; /* -fdata-sections */
int warnings_are_errors; /* -Werror */
uint32_t max_errors; /* -fmax-errors=N */
- KitTarget target; /* -target / host */
+ KitTargetSpec target; /* -target / host */
int target_set; /* did -target appear */
const char* output_path; /* -o */
int output_path_set;
@@ -161,6 +161,7 @@ typedef struct CcOptions {
/* Cflags via shared helper. */
DriverCflags cf;
+ DriverTargetFeatures target_features;
/* Positional inputs split by suffix. */
const char** source_files; /* .c paths */
@@ -317,7 +318,8 @@ static int cc_alloc_arrays(CcOptions* o, int argc) {
o->cur_link_mode = KIT_LM_DEFAULT;
if (driver_cflags_init(&o->cf, o->env,
(int)(bound + DRIVER_HOSTED_MAX_DEFINES +
- DRIVER_HOSTED_MAX_INCLUDES)) != 0) {
+ DRIVER_HOSTED_MAX_INCLUDES)) != 0 ||
+ driver_target_features_init(&o->target_features, o->env, argc) != 0) {
driver_errf(CC_TOOL, "out of memory");
return 1;
}
@@ -353,6 +355,7 @@ static void cc_options_release(CcOptions* o) {
driver_free(o->env, o->owned_sysroot_lib_dir,
o->owned_sysroot_lib_dir_size);
driver_hosted_plan_fini(o->env, &o->hosted);
+ driver_target_features_fini(&o->target_features, o->env);
driver_cflags_fini(&o->cf, o->env);
driver_free(o->env, o->source_files, bound * sizeof(*o->source_files));
driver_free(o->env, o->source_langs, bound * sizeof(*o->source_langs));
@@ -1515,6 +1518,12 @@ static int cc_parse(int argc, char** argv, CcOptions* o) {
if (cc_record_mcmodel(o, a + 9) != 0) return 1;
continue;
}
+ {
+ int tr = driver_target_features_try_consume(&o->target_features, o->env,
+ CC_TOOL, argc, argv, &i);
+ if (tr < 0) return 1;
+ if (tr > 0) continue;
+ }
if (driver_strneq(a, "--build-id=", 11)) {
if (cc_record_build_id(o, a + 11) != 0) return 1;
continue;
@@ -1870,9 +1879,28 @@ static int cc_load_single_source(const KitContext* ctx, const CcOptions* o,
return 0;
}
+static KitStatus cc_compiler_new(const CcOptions* o, const KitContext* ctx,
+ KitTarget** target_out,
+ KitCompiler** compiler_out) {
+ KitStatus st;
+ if (target_out) *target_out = NULL;
+ if (compiler_out) *compiler_out = NULL;
+ if (!o || !ctx || !target_out || !compiler_out) return KIT_INVALID;
+ st = driver_target_new(ctx, o->target, &o->target_features, CC_TOOL,
+ target_out);
+ if (st != KIT_OK) return st;
+ st = driver_compiler_new(*target_out, ctx, compiler_out);
+ if (st != KIT_OK) {
+ kit_target_free(*target_out);
+ *target_out = NULL;
+ }
+ return st;
+}
+
static int cc_preprocess(DriverEnv* env, const CcOptions* o,
const KitPreprocessOptions* pp_opts) {
KitContext ctx = driver_env_to_context(env);
+ KitTarget* target = NULL;
KitCompiler* compiler = NULL;
KitWriter* writer = NULL;
KitFileData fd = {0};
@@ -1897,7 +1925,7 @@ static int cc_preprocess(DriverEnv* env, const CcOptions* o,
}
}
- if (driver_compiler_new(o->target, &ctx, &compiler) != KIT_OK) {
+ if (cc_compiler_new(o, &ctx, &target, &compiler) != KIT_OK) {
driver_errf(CC_TOOL, "failed to initialize compiler");
goto out;
}
@@ -1910,6 +1938,7 @@ static int cc_preprocess(DriverEnv* env, const CcOptions* o,
out:
if (compiler) driver_compiler_free(compiler);
+ kit_target_free(target);
if (writer) kit_writer_close(writer);
if (loaded) ctx.file_io->release(ctx.file_io->user, &fd);
return rc;
@@ -2285,6 +2314,7 @@ static void cc_fill_c_opts(const CcOptions* o, KitCCompileOptions* copts) {
static int cc_run_deps_only(DriverEnv* env, const CcOptions* o,
const KitPreprocessOptions* pp) {
KitContext ctx = driver_env_to_context(env);
+ KitTarget* target = NULL;
KitCompiler* compiler = NULL;
KitWriter* discard = NULL;
KitFileData fd = {0};
@@ -2300,7 +2330,7 @@ static int cc_run_deps_only(DriverEnv* env, const CcOptions* o,
goto out;
}
- if (driver_compiler_new(o->target, &ctx, &compiler) != KIT_OK) {
+ if (cc_compiler_new(o, &ctx, &target, &compiler) != KIT_OK) {
driver_errf(CC_TOOL, "failed to initialize compiler");
goto out;
}
@@ -2314,6 +2344,7 @@ static int cc_run_deps_only(DriverEnv* env, const CcOptions* o,
out:
if (compiler) driver_compiler_free(compiler);
+ kit_target_free(target);
if (discard) kit_writer_close(discard);
if (loaded) ctx.file_io->release(ctx.file_io->user, &fd);
return rc;
@@ -2344,6 +2375,7 @@ static int cc_run_compile_one(DriverEnv* env, const CcOptions* o,
const KitPreprocessOptions* pp, int is_memory,
uint32_t index, const char* out_path) {
KitContext ctx = driver_env_to_context(env);
+ KitTarget* target = NULL;
KitCompiler* compiler = NULL;
KitWriter* obj_w = NULL;
KitFileData fd = {0};
@@ -2372,7 +2404,7 @@ static int cc_run_compile_one(DriverEnv* env, const CcOptions* o,
goto out;
}
- if (driver_compiler_new(o->target, &ctx, &compiler) != KIT_OK) {
+ if (cc_compiler_new(o, &ctx, &target, &compiler) != KIT_OK) {
driver_errf(CC_TOOL, "failed to initialize compiler");
goto out;
}
@@ -2409,6 +2441,7 @@ static int cc_run_compile_one(DriverEnv* env, const CcOptions* o,
out:
if (compiler) driver_compiler_free(compiler);
+ kit_target_free(target);
if (obj_w) kit_writer_close(obj_w);
if (loaded) ctx.file_io->release(ctx.file_io->user, &fd);
return rc;
@@ -2450,6 +2483,7 @@ static int cc_run_check(DriverEnv* env, const CcOptions* o,
const KitPreprocessOptions* pp) {
KitContext ctx = driver_env_to_context(env);
const KitFileIO* io = ctx.file_io;
+ KitTarget* target = NULL;
KitCompiler* compiler = NULL;
DriverLoad* src_lf = NULL;
KitSlice* src_bytes = NULL;
@@ -2477,7 +2511,7 @@ static int cc_run_check(DriverEnv* env, const CcOptions* o,
goto out;
}
- if (driver_compiler_new(o->target, &ctx, &compiler) != KIT_OK) {
+ if (cc_compiler_new(o, &ctx, &target, &compiler) != KIT_OK) {
driver_errf(CC_TOOL, "failed to initialize compiler");
goto out;
}
@@ -2506,6 +2540,7 @@ static int cc_run_check(DriverEnv* env, const CcOptions* o,
out:
if (compiler) driver_compiler_free(compiler);
+ kit_target_free(target);
if (src_lf) {
for (i = 0; i < o->nsource_files; ++i) driver_release_bytes(io, &src_lf[i]);
}
@@ -2523,6 +2558,7 @@ static int cc_run_link_exe(DriverEnv* env, const CcOptions* o,
const KitPreprocessOptions* pp) {
KitContext ctx = driver_env_to_context(env);
const KitFileIO* io = ctx.file_io;
+ KitTarget* target = NULL;
KitCompiler* compiler = NULL;
KitWriter* out_w = NULL;
DriverLoad* src_lf = NULL;
@@ -2627,7 +2663,7 @@ static int cc_run_link_exe(DriverEnv* env, const CcOptions* o,
goto out;
}
- if (driver_compiler_new(o->target, &ctx, &compiler) != KIT_OK) {
+ if (cc_compiler_new(o, &ctx, &target, &compiler) != KIT_OK) {
driver_errf(CC_TOOL, "failed to initialize compiler");
goto out;
}
@@ -2769,6 +2805,7 @@ out:
}
if (script) kit_link_script_free(&ctx, script);
if (compiler) driver_compiler_free(compiler);
+ kit_target_free(target);
driver_release_bytes(io, &script_lf);
if (arch_lf) {
for (i = 0; i < o->narchives; ++i) driver_release_bytes(io, &arch_lf[i]);
diff --git a/driver/cmd/compile.c b/driver/cmd/compile.c
@@ -49,7 +49,8 @@ typedef struct CompileOptions {
const char* output_path;
int warnings_are_errors;
uint32_t max_errors;
- KitTarget target;
+ KitTargetSpec target;
+ DriverTargetFeatures target_features;
} CompileOptions;
static void compile_usage(void) {
@@ -275,6 +276,13 @@ static int compile_parse(int argc, char** argv, CompileOptions* o) {
continue;
}
+ {
+ int tr = driver_target_features_try_consume(&o->target_features, o->env,
+ COMPILE_TOOL, argc, argv, &i);
+ if (tr < 0) return 1;
+ if (tr > 0) continue;
+ }
+
if (driver_streq(a, "--")) {
for (++i; i < argc; ++i)
if (compile_classify_positional(o, argv[i]) != 0) return 1;
@@ -369,8 +377,7 @@ static char* compile_default_out(DriverEnv* env, const CompileOptions* o,
/* Compile one source. out_path is NULL for check-only. */
static int compile_one(const KitContext* ctx, KitCompiler* compiler,
- KitLanguage lang,
- const KitCodeOptions* code,
+ KitLanguage lang, const KitCodeOptions* code,
const KitDiagnosticOptions* diag,
const KitPreprocessOptions* pp, const void* lang_extra,
const char* src, const char* out_path) {
@@ -417,6 +424,7 @@ int driver_compile(int argc, char** argv) {
DriverRuntimeSupport runtime = {0};
int runtime_resolved = 0;
KitContext ctx;
+ KitTarget* target = NULL;
KitCompiler* compiler = NULL;
KitFrontendCaps caps = {0};
KitLanguage lang = KIT_LANG_UNKNOWN;
@@ -438,9 +446,10 @@ int driver_compile(int argc, char** argv) {
o.sources = driver_alloc_zeroed(&env, (size_t)argc * sizeof(*o.sources));
o.fe_args = driver_alloc_zeroed(&env, (size_t)argc * sizeof(*o.fe_args));
- if (!o.sources || !o.fe_args || driver_cflags_init(&o.cf, &env, argc) != 0) {
+ if (!o.sources || !o.fe_args || driver_cflags_init(&o.cf, &env, argc) != 0 ||
+ driver_target_features_init(&o.target_features, &env, argc) != 0) {
driver_errf(COMPILE_TOOL, "out of memory");
- goto done_early;
+ goto done;
}
if (compile_parse(argc, argv, &o) != 0) goto done;
@@ -461,7 +470,9 @@ int driver_compile(int argc, char** argv) {
}
ctx = driver_env_to_context(&env);
- if (driver_compiler_new(o.target, &ctx, &compiler) != KIT_OK) {
+ if (driver_target_new(&ctx, o.target, &o.target_features, COMPILE_TOOL,
+ &target) != KIT_OK ||
+ driver_compiler_new(target, &ctx, &compiler) != KIT_OK) {
driver_errf(COMPILE_TOOL, "failed to initialize compiler");
rc = 1;
goto done;
@@ -552,11 +563,14 @@ int driver_compile(int argc, char** argv) {
done:
if (lang_extra) kit_frontend_free_options(compiler, lang, lang_extra);
if (compiler) driver_compiler_free(compiler);
+ kit_target_free(target);
if (runtime_resolved) driver_runtime_support_fini(&env, &runtime);
+ driver_target_features_fini(&o.target_features, &env);
driver_cflags_fini(&o.cf, &env);
-done_early:
- if (o.sources) driver_free(&env, o.sources, (size_t)argc * sizeof(*o.sources));
- if (o.fe_args) driver_free(&env, o.fe_args, (size_t)argc * sizeof(*o.fe_args));
+ if (o.sources)
+ driver_free(&env, o.sources, (size_t)argc * sizeof(*o.sources));
+ if (o.fe_args)
+ driver_free(&env, o.fe_args, (size_t)argc * sizeof(*o.fe_args));
driver_env_fini(&env);
return rc;
}
diff --git a/driver/cmd/cpp.c b/driver/cmd/cpp.c
@@ -29,7 +29,7 @@ typedef struct CppOptions {
const char* output_path;
const char* source_path; /* NULL when stdin source */
int from_stdin;
- KitTarget target;
+ KitTargetSpec target;
} CppOptions;
void driver_help_cpp(void) {
@@ -73,7 +73,7 @@ static void cpp_usage(void) {
}
static int cpp_parse(int argc, char** argv, CppOptions* o, DriverEnv* env,
- DriverCflags* cf) {
+ DriverCflags* cf, DriverTargetFeatures* tf) {
int i;
o->target = driver_host_target();
@@ -108,6 +108,13 @@ static int cpp_parse(int argc, char** argv, CppOptions* o, DriverEnv* env,
continue;
}
+ {
+ int tr =
+ driver_target_features_try_consume(tf, env, CPP_TOOL, argc, argv, &i);
+ if (tr < 0) return 1;
+ if (tr > 0) continue;
+ }
+
if (driver_streq(a, "-")) {
if (o->source_path || o->from_stdin) {
driver_errf(CPP_TOOL, "multiple inputs not supported");
@@ -142,8 +149,10 @@ int driver_cpp(int argc, char** argv) {
DriverEnv env;
CppOptions o = {0};
DriverCflags cf = {0};
+ DriverTargetFeatures tf = {0};
KitContext ctx;
KitPreprocessOptions pp;
+ KitTarget* target = NULL;
KitCompiler* compiler = NULL;
KitWriter* writer = NULL;
KitFileData src = {0};
@@ -161,13 +170,17 @@ int driver_cpp(int argc, char** argv) {
driver_env_init(&env);
- if (driver_cflags_init(&cf, &env, argc) != 0) {
+ if (driver_cflags_init(&cf, &env, argc) != 0 ||
+ driver_target_features_init(&tf, &env, argc) != 0) {
driver_errf(CPP_TOOL, "out of memory");
+ driver_target_features_fini(&tf, &env);
+ driver_cflags_fini(&cf, &env);
driver_env_fini(&env);
return 2;
}
- if (cpp_parse(argc, argv, &o, &env, &cf) != 0) {
+ if (cpp_parse(argc, argv, &o, &env, &cf, &tf) != 0) {
+ driver_target_features_fini(&tf, &env);
driver_cflags_fini(&cf, &env);
driver_env_fini(&env);
return 2;
@@ -212,7 +225,8 @@ int driver_cpp(int argc, char** argv) {
}
}
- if (driver_compiler_new(o.target, &ctx, &compiler) != KIT_OK) {
+ if (driver_target_new(&ctx, o.target, &tf, CPP_TOOL, &target) != KIT_OK ||
+ driver_compiler_new(target, &ctx, &compiler) != KIT_OK) {
driver_errf(CPP_TOOL, "failed to initialize compiler");
goto out;
}
@@ -223,9 +237,11 @@ int driver_cpp(int argc, char** argv) {
out:
if (compiler) driver_compiler_free(compiler);
+ kit_target_free(target);
if (writer) kit_writer_close(writer);
if (loaded) ctx.file_io->release(ctx.file_io->user, &src);
if (stdin_buf) driver_free(&env, stdin_buf, stdin_size);
+ driver_target_features_fini(&tf, &env);
driver_cflags_fini(&cf, &env);
driver_env_fini(&env);
return rc;
diff --git a/driver/cmd/dbg.c b/driver/cmd/dbg.c
@@ -2375,7 +2375,7 @@ static void dbg_cmd_disasm(DbgState* s, uint64_t addr, size_t count) {
}
memset(&dctx, 0, sizeof(dctx));
- dctx.target = driver_host_target();
+ dctx.target = kit_compiler_target(s->compiler);
dctx.context = s->ctx;
if (kit_disasm_iter_new(&dctx, buf, byte_count, addr, s->view, &it) !=
KIT_OK) {
@@ -3377,12 +3377,12 @@ int driver_dbg(int argc, char** argv) {
DriverEnv env;
DbgOpts o = {0};
KitCompiler* compiler = NULL;
+ KitTarget* target = NULL;
KitJit* jit = NULL;
DbgState st = {0};
KitContext ctx;
KitJitHost jhost;
KitDbgHost dhost;
- KitTarget target;
int rc;
if (driver_argv_wants_help(argc, argv, 1)) {
@@ -3402,17 +3402,24 @@ int driver_dbg(int argc, char** argv) {
ctx = driver_env_to_context(&env);
jhost = driver_env_to_jit_host(&env);
dhost = driver_env_to_dbg_host(&env);
- target = driver_host_target();
- if (driver_compiler_new(target, &ctx, &compiler) != KIT_OK) {
- driver_errf(DBG_TOOL, "failed to initialize compiler");
- dbg_options_release(&o);
- driver_env_fini(&env);
- return 1;
+ {
+ KitTargetOptions topts;
+ memset(&topts, 0, sizeof topts);
+ topts.spec = driver_host_target();
+ if (kit_target_new(&ctx, &topts, &target) != KIT_OK ||
+ driver_compiler_new(target, &ctx, &compiler) != KIT_OK) {
+ driver_errf(DBG_TOOL, "failed to initialize compiler");
+ kit_target_free(target);
+ dbg_options_release(&o);
+ driver_env_fini(&env);
+ return 1;
+ }
}
rc = dbg_compile_and_jit(&o, compiler, &jhost, &jit);
if (rc != 0) {
driver_compiler_free(compiler);
+ kit_target_free(target);
dbg_options_release(&o);
driver_env_fini(&env);
return rc;
@@ -3436,6 +3443,7 @@ int driver_dbg(int argc, char** argv) {
KIT_SLICE_ARG(kit_slice_cstr(o.entry)));
kit_jit_free(jit);
driver_compiler_free(compiler);
+ kit_target_free(target);
dbg_options_release(&o);
driver_env_fini(&env);
return 1;
@@ -3469,6 +3477,7 @@ int driver_dbg(int argc, char** argv) {
if (st.session) kit_jit_session_free(st.session);
kit_jit_free(jit);
driver_compiler_free(compiler);
+ kit_target_free(target);
dbg_options_release(&o);
driver_env_fini(&env);
return 0;
diff --git a/driver/cmd/disas.c b/driver/cmd/disas.c
@@ -16,7 +16,7 @@
#define DISAS_TOOL "disas"
typedef struct DisasOpts {
- KitTarget target;
+ KitTargetSpec target;
uint64_t base; /* --base: vaddr of the first byte */
const char* hex; /* -x: inline hex string, or NULL */
const char* in; /* positional file, "-" for stdin, or NULL */
@@ -132,6 +132,8 @@ int driver_disas(int argc, char** argv) {
KitContext ctx;
KitDisasmContext dctx;
DisasOpts o;
+ DriverTargetFeatures tf = {0};
+ KitTarget* target = NULL;
const uint8_t* data = NULL;
size_t len = 0;
DriverLoad ld = {0};
@@ -150,6 +152,12 @@ int driver_disas(int argc, char** argv) {
memset(&o, 0, sizeof o);
o.target = driver_host_target();
driver_env_init(&env);
+ if (driver_target_features_init(&tf, &env, argc) != 0) {
+ driver_errf(DISAS_TOOL, "out of memory");
+ driver_target_features_fini(&tf, &env);
+ driver_env_fini(&env);
+ return 1;
+ }
for (i = 1; i < argc; ++i) {
const char* a = argv[i];
@@ -164,6 +172,12 @@ int driver_disas(int argc, char** argv) {
}
continue;
}
+ {
+ int tr = driver_target_features_try_consume(&tf, &env, DISAS_TOOL, argc,
+ argv, &i);
+ if (tr < 0) goto done;
+ if (tr > 0) continue;
+ }
if (driver_streq(a, "-x")) {
if (i + 1 >= argc) {
driver_errf(DISAS_TOOL, "-x requires a hex string");
@@ -257,16 +271,23 @@ int driver_disas(int argc, char** argv) {
}
ctx = driver_env_to_context(&env);
+ if (driver_target_new(&ctx, o.target, &tf, DISAS_TOOL, &target) != KIT_OK) {
+ driver_errf(DISAS_TOOL, "failed to initialize target");
+ rc = 1;
+ goto done;
+ }
memset(&dctx, 0, sizeof dctx);
- dctx.target = o.target;
+ dctx.target = target;
dctx.context = ctx;
disas_run(&dctx, data, len, o.base);
rc = 0;
done:
+ kit_target_free(target);
if (hexbuf) driver_free(&env, hexbuf, hexbuf_len);
if (sbuf) driver_free(&env, sbuf, sbuf_len);
if (loaded) driver_release_bytes(&env.file_io, &ld);
+ driver_target_features_fini(&tf, &env);
driver_env_fini(&env);
return rc;
}
diff --git a/driver/cmd/emu.c b/driver/cmd/emu.c
@@ -3,6 +3,7 @@
#include <kit/object.h>
#include <stddef.h>
#include <stdint.h>
+#include <string.h>
#include "driver.h"
@@ -29,7 +30,7 @@ typedef struct EmuOptions {
KitEmuTraceFlags trace;
KitArchKind guest_arch;
int guest_arch_set;
- KitTarget guest_target;
+ KitTargetSpec guest_target;
int guest_target_set;
const char* guest_path; /* positional input (required) */
@@ -231,7 +232,7 @@ static const char* emu_arch_name(KitArchKind a) {
}
static int emu_resolve_target(EmuOptions* o, const KitSlice* input) {
- KitTarget detected;
+ KitTargetSpec detected;
if (kit_detect_target(input->data, input->len, &detected) != KIT_OK) {
driver_errf(EMU_TOOL, "could not detect target from %.*s",
KIT_SLICE_ARG(kit_slice_cstr(o->guest_path)));
@@ -261,6 +262,7 @@ int driver_emu(int argc, char** argv) {
DriverEnv env;
EmuOptions eo = {0};
KitContext ctx;
+ KitTarget* target = NULL;
KitCompiler* compiler = NULL;
DriverLoad guest_lf = {0};
KitSlice guest_in;
@@ -300,9 +302,15 @@ int driver_emu(int argc, char** argv) {
/* The emu's host-side compiler runs at the host's native target —
* the JIT image holds host code, while the guest target is resolved
* from the executable and optional driver flags. */
- if (driver_compiler_new(driver_host_target(), &ctx, &compiler) != KIT_OK) {
- driver_errf(EMU_TOOL, "failed to initialize compiler");
- goto out;
+ {
+ KitTargetOptions topts;
+ memset(&topts, 0, sizeof topts);
+ topts.spec = driver_host_target();
+ if (kit_target_new(&ctx, &topts, &target) != KIT_OK ||
+ driver_compiler_new(target, &ctx, &compiler) != KIT_OK) {
+ driver_errf(EMU_TOOL, "failed to initialize compiler");
+ goto out;
+ }
}
emu_finalize_argv(&eo, &guest_argv);
@@ -335,6 +343,7 @@ int driver_emu(int argc, char** argv) {
out:
if (compiler) driver_compiler_free(compiler);
+ kit_target_free(target);
if (guest_lf.loaded && ctx.file_io)
driver_release_bytes(ctx.file_io, &guest_lf);
emu_options_release(&eo);
diff --git a/driver/cmd/ld.c b/driver/cmd/ld.c
@@ -71,7 +71,7 @@ typedef struct LdOptions {
const char* driver_path;
size_t argv_bound;
- KitTarget target;
+ KitTargetSpec target;
const char* output_path; /* -o */
int output_seen;
@@ -1082,6 +1082,7 @@ static void release_all(LoadedFile* arr, uint32_t n) {
static int ld_run_link(LdOptions* o) {
KitContext ctx = driver_env_to_context(o->env);
const KitFileIO* io = ctx.file_io;
+ KitTarget* target = NULL;
KitCompiler* compiler = NULL;
KitWriter* writer = NULL;
LoadedFile* obj_lf = NULL;
@@ -1128,7 +1129,7 @@ static int ld_run_link(LdOptions* o) {
/* Auto-detect target from the first object input, falling back to
* the host target. PIC overrides parsed from flags are preserved. */
if (o->nobject_files > 0) {
- KitTarget detected;
+ KitTargetSpec detected;
if (kit_detect_target(obj_lf[0].data.data, obj_lf[0].data.size,
&detected) == KIT_OK) {
uint8_t pic = o->target.pic;
@@ -1205,9 +1206,15 @@ static int ld_run_link(LdOptions* o) {
}
}
- if (driver_compiler_new(o->target, &ctx, &compiler) != KIT_OK) {
- driver_errf(LD_TOOL, "failed to initialize compiler");
- goto out;
+ {
+ KitTargetOptions topts;
+ memset(&topts, 0, sizeof topts);
+ topts.spec = o->target;
+ if (kit_target_new(&ctx, &topts, &target) != KIT_OK ||
+ driver_compiler_new(target, &ctx, &compiler) != KIT_OK) {
+ driver_errf(LD_TOOL, "failed to initialize compiler");
+ goto out;
+ }
}
if (script_lf.loaded) {
@@ -1331,6 +1338,7 @@ out:
}
if (script) kit_link_script_free(&ctx, script);
if (compiler) driver_compiler_free(compiler);
+ kit_target_free(target);
driver_runtime_archive_fini(o->env, &rt_archive);
if (runtime_resolved) driver_runtime_support_fini(o->env, &runtime);
release_file(&script_lf);
diff --git a/driver/cmd/mc.c b/driver/cmd/mc.c
@@ -19,7 +19,7 @@
#define MC_TOOL "mc"
typedef struct McOpts {
- KitTarget target;
+ KitTargetSpec target;
int plain; /* -p: raw .text hex only */
} McOpts;
@@ -73,7 +73,7 @@ static void mc_print_plain(const uint8_t* text, size_t len) {
/* Disassemble the assembled .text and print one `mnemonic ops # encoding: [..]`
* line per instruction. */
-static void mc_print_encoding(const KitContext* ctx, KitTarget target,
+static void mc_print_encoding(const KitContext* ctx, const KitTarget* target,
const uint8_t* text, size_t len) {
KitDisasmContext dctx;
KitDisasmIter* it = NULL;
@@ -143,6 +143,8 @@ int driver_mc(int argc, char** argv) {
DriverEnv env;
KitContext ctx;
McOpts o;
+ DriverTargetFeatures tf = {0};
+ KitTarget* target = NULL;
KitCompiler* compiler = NULL;
KitCompileSession* session = NULL;
KitObjBuilder* ob = NULL;
@@ -164,6 +166,12 @@ int driver_mc(int argc, char** argv) {
memset(&o, 0, sizeof o);
o.target = driver_host_target();
driver_env_init(&env);
+ if (driver_target_features_init(&tf, &env, argc) != 0) {
+ driver_errf(MC_TOOL, "out of memory");
+ driver_target_features_fini(&tf, &env);
+ driver_env_fini(&env);
+ return 1;
+ }
for (i = 1; i < argc; ++i) {
const char* a = argv[i];
@@ -182,6 +190,12 @@ int driver_mc(int argc, char** argv) {
o.plain = 1;
continue;
}
+ {
+ int tr = driver_target_features_try_consume(&tf, &env, MC_TOOL, argc,
+ argv, &i);
+ if (tr < 0) goto done;
+ if (tr > 0) continue;
+ }
if (driver_streq(a, "-")) {
read_stdin = 1;
first_pos = i; /* marks "have input"; stdin overrides token join */
@@ -216,7 +230,8 @@ int driver_mc(int argc, char** argv) {
}
ctx = driver_env_to_context(&env);
- if (driver_compiler_new(o.target, &ctx, &compiler) != KIT_OK) {
+ if (driver_target_new(&ctx, o.target, &tf, MC_TOOL, &target) != KIT_OK ||
+ driver_compiler_new(target, &ctx, &compiler) != KIT_OK) {
driver_errf(MC_TOOL, "failed to initialize compiler");
rc = 1;
goto done;
@@ -278,7 +293,7 @@ int driver_mc(int argc, char** argv) {
if (o.plain)
mc_print_plain(text, text_len);
else
- mc_print_encoding(&ctx, o.target, text, text_len);
+ mc_print_encoding(&ctx, target, text, text_len);
mc_print_relocs(objf);
rc = 0;
}
@@ -289,8 +304,10 @@ done:
if (ob) kit_obj_builder_free(ob);
if (session) kit_compile_session_free(session);
if (compiler) driver_compiler_free(compiler);
+ kit_target_free(target);
if (stdin_buf) driver_free(&env, stdin_buf, stdin_len);
if (src && !read_stdin) driver_free(&env, src, src_len);
+ driver_target_features_fini(&tf, &env);
driver_env_fini(&env);
return rc;
}
diff --git a/driver/cmd/nm.c b/driver/cmd/nm.c
@@ -97,7 +97,7 @@ static int nm_value_cmp(const void* a, const void* b) {
static int nm_append_sym(DriverEnv* env, NmSym** syms, uint32_t* n,
uint32_t* cap, const KitObjSymInfo* si,
const char* file_prefix, int* ptr_digits,
- KitTarget t) {
+ KitTargetSpec t) {
int d = (t.ptr_size == 4) ? 8 : 16;
char* name;
if (d > *ptr_digits) *ptr_digits = d;
@@ -130,7 +130,7 @@ static int nm_append_sym(DriverEnv* env, NmSym** syms, uint32_t* n,
static int nm_collect_obj(KitObjFile* of, const NmOpts* opts,
const char* file_prefix, NmSym** syms, uint32_t* n,
uint32_t* cap, int* ptr_digits, DriverEnv* env) {
- KitTarget t = kit_obj_target(of);
+ KitTargetSpec t = kit_obj_target(of);
KitObjSymIter* it = NULL;
int rc = 0;
KitStatus st = opts->dynamic ? kit_obj_dynsymiter_new(of, &it)
diff --git a/driver/cmd/objdump.c b/driver/cmd/objdump.c
@@ -1023,10 +1023,15 @@ static void dump_disasm(const KitDisasmContext* dctx, KitObjFile* f,
uint32_t i;
uint32_t emitted = 0;
KitDisasmContext file_dctx;
+ KitTarget* file_target = NULL;
+ KitTargetOptions topts;
if (!dctx) return;
file_dctx = *dctx;
- file_dctx.target = kit_obj_target(f);
+ memset(&topts, 0, sizeof topts);
+ topts.spec = kit_obj_target(f);
+ if (kit_target_new(&dctx->context, &topts, &file_target) != KIT_OK) return;
+ file_dctx.target = file_target;
for (i = 0; i < nsec; ++i) {
KitObjSecInfo sec;
@@ -1056,6 +1061,7 @@ static void dump_disasm(const KitDisasmContext* dctx, KitObjFile* f,
* was stripped. Fall back to the executable load segments. */
if (emitted == 0 && kit_obj_kind(f) != KIT_OBJ_KIND_REL)
dump_disasm_segments(&file_dctx, f, opts, image);
+ kit_target_free(file_target);
}
/* `-f`: GNU objdump-style file header summary. Object files have no
@@ -1064,7 +1070,7 @@ static void dump_disasm(const KitDisasmContext* dctx, KitObjFile* f,
* whether the input has symbols and relocations so it's clear at a
* glance whether further -t / -r work is going to be productive. */
static void dump_file_header(KitObjFile* f, const char* label) {
- KitTarget target = kit_obj_target(f);
+ KitTargetSpec target = kit_obj_target(f);
KitObjFmt fmt = kit_obj_fmt(f);
KitObjSymIter* sit = NULL;
KitObjRelocIter* rit = NULL;
@@ -1587,7 +1593,7 @@ static void dump_private(KitObjFile* f) {
static void dump_obj(const KitContext* ctx, const KitDisasmContext* dctx,
const char* label, KitObjFile* f, const ObjdumpOpts* opts,
const KitSlice* image) {
- KitTarget target = kit_obj_target(f);
+ KitTargetSpec target = kit_obj_target(f);
KitObjFmt fmt = kit_obj_fmt(f);
driver_printf("%.*s:\tfile format %.*s-%.*s\n\n",
@@ -1853,7 +1859,7 @@ int driver_objdump(int argc, char** argv) {
/* Disassembler context: a target + ctx value pair. Disasm consults
* the per-file object reader for annotation. */
if (opts.d || opts.D) {
- dctx.target = driver_host_target();
+ dctx.target = NULL;
dctx.context = ctx;
dctx_p = &dctx;
}
diff --git a/driver/cmd/run.c b/driver/cmd/run.c
@@ -39,7 +39,8 @@ typedef struct RunOptions {
const char* entry; /* -e, default "main" */
const char* sysroot; /* --sysroot */
int wants_hosted_libc; /* -lc */
- KitTarget target; /* -target / host */
+ KitTargetSpec target; /* -target / host */
+ DriverTargetFeatures target_features;
DriverHostedPlan hosted;
DriverCflags cf;
@@ -349,6 +350,10 @@ static int run_alloc_arrays(RunOptions* o, int argc) {
driver_errf(RUN_TOOL, "out of memory");
return 1;
}
+ if (driver_target_features_init(&o->target_features, o->env, argc) != 0) {
+ driver_errf(RUN_TOOL, "out of memory");
+ return 1;
+ }
return 0;
}
@@ -540,6 +545,12 @@ static int run_parse(int argc, char** argv, RunOptions* o) {
if (run_record_mcmodel(o, a + 9) != 0) return 1;
continue;
}
+ {
+ int tr = driver_target_features_try_consume(&o->target_features, o->env,
+ RUN_TOOL, argc, argv, &i);
+ if (tr < 0) return 1;
+ if (tr > 0) continue;
+ }
if (driver_streq(a, "-target")) {
if (++i >= argc) {
@@ -634,6 +645,7 @@ static void run_options_release(RunOptions* o) {
size_t bound = o->argv_bound;
driver_hosted_plan_fini(o->env, &o->hosted);
driver_inputs_release(&o->inputs);
+ driver_target_features_fini(&o->target_features, o->env);
driver_cflags_fini(&o->cf, o->env);
driver_free(o->env, o->prog_argv, bound * sizeof(*o->prog_argv));
}
@@ -881,6 +893,7 @@ int driver_run(int argc, char** argv) {
RunOptions ro = {0};
KitContext ctx;
KitJitHost jhost;
+ KitTarget* target = NULL;
KitCompiler* compiler = NULL;
KitJit* jit = NULL;
KitInterpProgram* interp = NULL;
@@ -922,8 +935,11 @@ int driver_run(int argc, char** argv) {
* and the entry call, free after kit_jit_free. */
ctx = driver_env_to_context(&env);
jhost = driver_env_to_jit_host(&env);
- if (driver_compiler_new(ro.target, &ctx, &compiler) != KIT_OK) {
+ if (driver_target_new(&ctx, ro.target, &ro.target_features, RUN_TOOL,
+ &target) != KIT_OK ||
+ driver_compiler_new(target, &ctx, &compiler) != KIT_OK) {
driver_errf(RUN_TOOL, "failed to initialize compiler");
+ kit_target_free(target);
run_metrics_finish(metrics);
run_options_release(&ro);
driver_env_fini(&env);
@@ -939,6 +955,7 @@ int driver_run(int argc, char** argv) {
if (!interp) {
driver_errf(RUN_TOOL, "failed to initialize interpreter");
driver_compiler_free(compiler);
+ kit_target_free(target);
run_metrics_finish(metrics);
run_options_release(&ro);
driver_env_fini(&env);
@@ -958,6 +975,7 @@ int driver_run(int argc, char** argv) {
bench_compile_end - bench_compile_start);
kit_interp_program_free(interp);
driver_compiler_free(compiler);
+ kit_target_free(target);
run_metrics_finish(metrics);
run_options_release(&ro);
driver_env_fini(&env);
@@ -973,6 +991,7 @@ int driver_run(int argc, char** argv) {
kit_interp_program_free(interp);
kit_jit_free(jit);
driver_compiler_free(compiler);
+ kit_target_free(target);
run_metrics_finish(metrics);
run_options_release(&ro);
driver_env_fini(&env);
@@ -1051,6 +1070,7 @@ after_entry:
kit_interp_program_free(interp);
kit_jit_free(jit);
driver_compiler_free(compiler);
+ kit_target_free(target);
run_metrics_finish(metrics);
run_options_release(&ro);
driver_env_fini(&env);
diff --git a/driver/driver.h b/driver/driver.h
@@ -141,18 +141,43 @@ int driver_is_help_flag(const char* arg);
int driver_argv_wants_help(int argc, char** argv, int accept_short_h);
/* Parse a target triple string (`<arch>[-<vendor>]-<os>[-<env>]`) into a
- * KitTarget. Recognized arches: x86_64/amd64, i386/i486/i586/i686, aarch64/
+ * KitTargetSpec. Recognized arches: x86_64/amd64, i386/i486/i586/i686, aarch64/
* arm64, arm/armv7, riscv64, riscv32, wasm32, wasm64. Recognized OSes (scanned
* across the remaining components, so vendor tokens like `pc`/`apple`/
* `unknown` are skipped): linux, darwin/macos, windows/win32, wasi, none/
* freestanding. Sets arch/os/obj/ptr_size/ptr_align/big_endian; pic and
* code_model are left at their defaults. Returns 0 on success, nonzero on
* unrecognized arch or NULL inputs. */
-int driver_target_from_triple(const char* triple, KitTarget* out);
+int driver_target_from_triple(const char* triple, KitTargetSpec* out);
/* Render a canonical driver target triple into `buf`. Returns 0 on success,
* nonzero when `buf` is too small. */
-int driver_target_to_triple(KitTarget target, char* buf, size_t cap);
+int driver_target_to_triple(KitTargetSpec target, char* buf, size_t cap);
+
+typedef struct DriverTargetFeatures {
+ DriverEnv* env;
+ KitTargetFeature* features;
+ uint32_t nfeatures;
+ uint32_t cap_features;
+ KitSlice isa;
+ KitSlice cpu;
+ KitSlice tune;
+} DriverTargetFeatures;
+
+/* Shared target-feature parser. Canonical spelling is `-mattr=+foo,-bar`;
+ * GCC/clang-style `-mfoo` and `-mno-foo` are accepted as aliases and lowered
+ * into the same KitTargetFeature list before libkit sees the target. */
+int driver_target_features_init(DriverTargetFeatures*, DriverEnv*,
+ int argc_bound);
+void driver_target_features_fini(DriverTargetFeatures*, DriverEnv*);
+int driver_target_features_try_consume(DriverTargetFeatures*, DriverEnv*,
+ const char* tool, int argc, char** argv,
+ int* i);
+int driver_target_options(const DriverTargetFeatures*, const char* tool,
+ KitTargetSpec, KitTargetOptions* out);
+KitStatus driver_target_new(const KitContext*, KitTargetSpec,
+ const DriverTargetFeatures*, const char* tool,
+ KitTarget** out);
/* Default PIC/PIE model for a target. Hosted targets default to PIE,
* matching modern gcc/clang and platform norms (ELF -> ET_DYN, Mach-O ->
@@ -163,7 +188,7 @@ KitPic driver_default_pic(KitObjFmt obj, KitOSKind os);
/* Resolve whether the link step should emit a position-independent
* executable. An explicit -pie always wins; -shared and -r (relocatable)
* always suppress it; otherwise it follows the target's PIC model. */
-int driver_link_pie(KitTarget target, int explicit_pie, int shared,
+int driver_link_pie(KitTargetSpec target, int explicit_pie, int shared,
int relocatable);
#endif
diff --git a/driver/env.h b/driver/env.h
@@ -51,16 +51,18 @@ KitDbgHost driver_env_to_dbg_host(const DriverEnv*);
* KitCompiler from outside those helpers (none today). */
void driver_diag_set_compiler(KitCompiler*);
-/* Lifecycle helpers around kit_compiler_{new,free}. Identical to the
- * raw entries except they register the active compiler with the stderr
- * diag sink so diagnostics resolve loc.file_id to its registered path.
+/* Lifecycle helpers around kit_compiler_{new,free}. Identical to the raw
+ * entries except they register the active compiler with the stderr diag sink
+ * so diagnostics resolve loc.file_id to its registered path. The compiler
+ * borrows `target`; callers own it and must free it after driver_compiler_free.
* Returns KIT_OK on success; on failure *out is NULL. */
-KitStatus driver_compiler_new(KitTarget, const KitContext*, KitCompiler** out);
+KitStatus driver_compiler_new(const KitTarget*, const KitContext*,
+ KitCompiler** out);
void driver_compiler_free(KitCompiler*);
/* Default target used by tools that don't expose a target-selection flag
* yet. v1: native-looking host target (chosen at compile time). */
-KitTarget driver_host_target(void);
+KitTargetSpec driver_host_target(void);
/* ----------------------------------------------------------------------
* Hosted-libc search directories
@@ -118,7 +120,7 @@ void driver_hosted_dirs_fini(DriverHostedDirs* dirs);
* nothing (its MinGW sysroot comes from --sysroot/KIT_SYSROOT in the cc
* driver). The single env-var override, KIT_SYSROOT, is consulted by the
* caller, not here. */
-int driver_default_hosted_dirs(DriverEnv* env, KitTarget target,
+int driver_default_hosted_dirs(DriverEnv* env, KitTargetSpec target,
DriverHostedDirs* out);
/* ----------------------------------------------------------------------
diff --git a/driver/env/common.c b/driver/env/common.c
@@ -62,7 +62,7 @@ static KitCompiler* g_diag_active_compiler;
void driver_diag_set_compiler(KitCompiler* c) { g_diag_active_compiler = c; }
-KitStatus driver_compiler_new(KitTarget t, const KitContext* ctx,
+KitStatus driver_compiler_new(const KitTarget* t, const KitContext* ctx,
KitCompiler** out) {
KitCompiler* c = NULL;
KitStatus st = kit_compiler_new(t, ctx, &c);
diff --git a/driver/env/env_posix.h b/driver/env/env_posix.h
@@ -92,8 +92,8 @@ int os_stat_mtime_ns(const struct stat* sb, int64_t* out);
* underscore for dlsym; ELF passes through). */
void* os_dlsym(const char* name);
-/* Fill the OS/object-format slots of KitTarget for the host. */
-void os_host_target_fill(KitTarget* t);
+/* Fill the OS/object-format slots of KitTargetSpec for the host. */
+void os_host_target_fill(KitTargetSpec* t);
/* ---- vtable singletons wired into DriverEnv on POSIX -------------------- */
extern KitExecMem g_execmem_posix; /* posix.c — page_size set in init */
diff --git a/driver/env/freebsd.c b/driver/env/freebsd.c
@@ -133,7 +133,7 @@ void* os_dlsym(const char* name) {
/* ---------------- host_target os/obj ---------------- */
-void os_host_target_fill(KitTarget* t) {
+void os_host_target_fill(KitTargetSpec* t) {
t->os = KIT_OS_FREEBSD;
t->obj = KIT_OBJ_ELF;
}
@@ -171,7 +171,7 @@ int driver_self_exe_path(DriverEnv* env, char** out, size_t* out_size) {
/* FreeBSD base system is flat: headers in /usr/include, crt + libc in /usr/lib
* and /lib (libc.so.7 lives in /lib). Host target only. UNTESTED on the macOS
* dev host -- see hosted_resolve_freebsd in driver/lib/hosted.c. */
-int driver_default_hosted_dirs(DriverEnv* env, KitTarget target,
+int driver_default_hosted_dirs(DriverEnv* env, KitTargetSpec target,
DriverHostedDirs* out) {
(void)env;
if (target.os != KIT_OS_FREEBSD) return 1;
diff --git a/driver/env/linux.c b/driver/env/linux.c
@@ -136,7 +136,7 @@ void* os_dlsym(const char* name) {
/* ---------------- host_target os/obj ---------------- */
-void os_host_target_fill(KitTarget* t) {
+void os_host_target_fill(KitTargetSpec* t) {
t->os = KIT_OS_LINUX;
t->obj = KIT_OBJ_ELF;
}
@@ -190,7 +190,7 @@ static const char* linux_multiarch_triple(KitArchKind arch) {
* /usr/lib + /lib. We hand the resolver an ordered library search list that
* covers both, plus the standard include roots, and let its per-file search
* bind each crt/libc wherever it actually lives. Host target only. */
-int driver_default_hosted_dirs(DriverEnv* env, KitTarget target,
+int driver_default_hosted_dirs(DriverEnv* env, KitTargetSpec target,
DriverHostedDirs* out) {
const char* triple;
(void)env;
diff --git a/driver/env/macos.c b/driver/env/macos.c
@@ -124,7 +124,7 @@ void* os_dlsym(const char* name) {
/* ---------------- host_target os/obj ---------------- */
-void os_host_target_fill(KitTarget* t) {
+void os_host_target_fill(KitTargetSpec* t) {
t->os = KIT_OS_MACOS;
t->obj = KIT_OBJ_MACHO;
}
@@ -177,7 +177,7 @@ int driver_self_exe_path(DriverEnv* env, char** out, size_t* out_size) {
* nothing. The <sdk>/usr/{include,lib} mapping mirrors
* hosted_dirs_from_sysroot's macOS case in driver/lib/hosted.c (layering
* forbids calling into it from the env TU). */
-int driver_default_hosted_dirs(DriverEnv* env, KitTarget target,
+int driver_default_hosted_dirs(DriverEnv* env, KitTargetSpec target,
DriverHostedDirs* out) {
static const char* const candidates[] = {
"/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk",
diff --git a/driver/env/posix.c b/driver/env/posix.c
@@ -1144,8 +1144,8 @@ static KitArchKind host_arch_self(void) {
#endif
}
-KitTarget driver_host_target(void) {
- KitTarget t;
+KitTargetSpec driver_host_target(void) {
+ KitTargetSpec t;
t.arch = host_arch_self();
os_host_target_fill(&t);
t.ptr_size = (uint8_t)sizeof(void*);
diff --git a/driver/env/windows.c b/driver/env/windows.c
@@ -1783,8 +1783,8 @@ static KitArchKind host_arch_self_win(void) {
#endif
}
-KitTarget driver_host_target(void) {
- KitTarget t;
+KitTargetSpec driver_host_target(void) {
+ KitTargetSpec t;
t.arch = host_arch_self_win();
t.os = KIT_OS_WINDOWS;
t.obj = KIT_OBJ_COFF;
@@ -1799,7 +1799,7 @@ KitTarget driver_host_target(void) {
/* No host probe on Windows: the MinGW sysroot is supplied via --sysroot or the
* KIT_SYSROOT env var (handled in the cc driver), not auto-discovered from a
* fixed install path. */
-int driver_default_hosted_dirs(DriverEnv* env, KitTarget target,
+int driver_default_hosted_dirs(DriverEnv* env, KitTargetSpec target,
DriverHostedDirs* out) {
(void)env;
(void)target;
diff --git a/driver/lib/hosted.c b/driver/lib/hosted.c
@@ -158,8 +158,15 @@ static int hosted_add_clang_compat_defines(DriverHostedPlan* plan) {
}
static int hosted_add_darwin_defines(DriverHostedPlan* plan) {
+ /* __APPLE_CC__ is what the SDK's <TargetConditionals.h> actually keys on:
+ * its compiler-detection ladder treats us as "GCC/clang on Mac OS X" only
+ * when __GNUC__ AND one of __APPLE_CC__/__APPLE_CPP__/__MACOS_CLASSIC__ are
+ * defined. Without it the header can't map __arm64__/__x86_64__ onto a
+ * TARGET_CPU_* and hits its `#error unknown compiler`. 6000 is the value
+ * modern Apple clang advertises. */
if (hosted_add_clang_compat_defines(plan) != 0 ||
hosted_add_define(plan, "__APPLE__", "1") != 0 ||
+ hosted_add_define(plan, "__APPLE_CC__", "6000") != 0 ||
hosted_add_define(plan, "__MACH__", "1") != 0 ||
hosted_add_define(plan, "__DYNAMIC__", "1") != 0)
return 1;
@@ -532,8 +539,8 @@ static const char* hosted_linux_inc_triple_sub(KitArchKind arch) {
* layout. Mirrors the per-host probes' shape so both producers converge on the
* same resolver contract. Dirs are added unconditionally (existence is checked
* when the resolver consumes them); returns nonzero only on alloc/overflow. */
-static int hosted_dirs_from_sysroot(DriverHostedDirs* dirs, KitTarget target,
- const char* sysroot) {
+static int hosted_dirs_from_sysroot(DriverHostedDirs* dirs,
+ KitTargetSpec target, const char* sysroot) {
dirs->root =
sysroot; /* a single explicit sysroot; -print-sysroot reports it */
switch (target.os) {
@@ -594,7 +601,7 @@ int driver_hosted_dirs_resolve(const DriverHostedRequest* req,
* cross-compile -- a host SDK is meaningless for a foreign platform.
* Best-effort: leaves dirs empty when nothing is found, and the resolver
* then emits its "requires --sysroot" error. */
- KitTarget host = driver_host_target();
+ KitTargetSpec host = driver_host_target();
if (req->target.os == host.os && req->target.arch == host.arch)
(void)driver_default_hosted_dirs(req->env, req->target, out);
}
diff --git a/driver/lib/hosted.h b/driver/lib/hosted.h
@@ -46,7 +46,7 @@ typedef struct DriverHostedPlan {
typedef struct DriverHostedRequest {
DriverEnv* env;
const char* tool;
- KitTarget target;
+ KitTargetSpec target;
const char* sysroot;
int static_link;
int link_inputs;
diff --git a/driver/lib/runtime.c b/driver/lib/runtime.c
@@ -318,7 +318,7 @@ int driver_runtime_append_freestanding_headers(const DriverRuntimeSupport* s,
return 0;
}
-static const RuntimeVariant* rt_variant_for_target(KitTarget target) {
+static const RuntimeVariant* rt_variant_for_target(KitTargetSpec target) {
uint32_t i;
for (i = 0; i < (uint32_t)(sizeof(kRtVariants) / sizeof(kRtVariants[0]));
++i) {
@@ -588,12 +588,13 @@ static int rt_build_archive(DriverEnv* env, const DriverRuntimeSupport* support,
const RuntimeVariant* variant, const char* tool,
uint64_t epoch, const char* archive_path) {
KitContext ctx = driver_env_to_context(env);
+ KitTarget* resolved_target = NULL;
KitCompiler* compiler = NULL;
KitWriter* archive_writer = NULL;
KitArInput* members = NULL;
KitWriter** obj_writers = NULL;
KitArWriteOptions ar_opts = {0};
- KitTarget target;
+ KitTargetSpec target;
uint32_t i;
int rc = 1;
@@ -615,9 +616,15 @@ static int rt_build_archive(DriverEnv* env, const DriverRuntimeSupport* support,
target.pic = KIT_PIC_NONE;
target.code_model = KIT_CM_DEFAULT;
- if (driver_compiler_new(target, &ctx, &compiler) != KIT_OK) {
- driver_errf(tool, "failed to initialize compiler for runtime");
- goto out;
+ {
+ KitTargetOptions topts;
+ memset(&topts, 0, sizeof topts);
+ topts.spec = target;
+ if (kit_target_new(&ctx, &topts, &resolved_target) != KIT_OK ||
+ driver_compiler_new(resolved_target, &ctx, &compiler) != KIT_OK) {
+ driver_errf(tool, "failed to initialize compiler for runtime");
+ goto out;
+ }
}
for (i = 0; i < variant->nsources; ++i) {
@@ -647,6 +654,7 @@ static int rt_build_archive(DriverEnv* env, const DriverRuntimeSupport* support,
out:
if (archive_writer) kit_writer_close(archive_writer);
if (compiler) driver_compiler_free(compiler);
+ kit_target_free(resolved_target);
if (obj_writers) {
for (i = 0; i < variant->nsources; ++i)
if (obj_writers[i]) kit_writer_close(obj_writers[i]);
@@ -744,7 +752,7 @@ static int rt_archive_try_dir(DriverEnv* env, const char* tool,
int driver_runtime_ensure_archive(DriverEnv* env, const char* tool,
const DriverRuntimeSupport* support,
- KitTarget target, uint64_t epoch,
+ KitTargetSpec target, uint64_t epoch,
char** out_path, size_t* out_path_size) {
const RuntimeVariant* variant = rt_variant_for_target(target);
const char* diag_tool = tool ? tool : "rt";
@@ -828,7 +836,7 @@ int driver_runtime_ensure_archive(DriverEnv* env, const char* tool,
int driver_runtime_prepare_archive(DriverEnv* env, const char* tool,
const DriverRuntimeSupport* support,
- KitTarget target, uint64_t epoch,
+ KitTargetSpec target, uint64_t epoch,
DriverRuntimeArchive* out) {
DriverRuntimeArchive z = {0};
if (!out) return 1;
diff --git a/driver/lib/runtime.h b/driver/lib/runtime.h
@@ -41,11 +41,11 @@ int driver_runtime_append_freestanding_headers(const DriverRuntimeSupport* s,
int driver_runtime_ensure_archive(DriverEnv* env, const char* tool,
const DriverRuntimeSupport* support,
- KitTarget target, uint64_t epoch,
+ KitTargetSpec target, uint64_t epoch,
char** out_path, size_t* out_path_size);
int driver_runtime_prepare_archive(DriverEnv* env, const char* tool,
const DriverRuntimeSupport* support,
- KitTarget target, uint64_t epoch,
+ KitTargetSpec target, uint64_t epoch,
DriverRuntimeArchive* out);
void driver_runtime_archive_fini(DriverEnv* env, DriverRuntimeArchive* a);
diff --git a/driver/lib/target.c b/driver/lib/target.c
@@ -23,19 +23,216 @@ KitPic driver_default_pic(KitObjFmt obj, KitOSKind os) {
return KIT_PIC_PIE;
}
-int driver_link_pie(KitTarget target, int explicit_pie, int shared,
+int driver_link_pie(KitTargetSpec target, int explicit_pie, int shared,
int relocatable) {
if (explicit_pie) return 1;
if (shared || relocatable) return 0;
return target.pic == KIT_PIC_PIE;
}
-int driver_target_from_triple(const char* triple, KitTarget* out) {
+static int target_features_grow(DriverTargetFeatures* tf) {
+ DriverEnv* env = tf->env;
+ uint32_t old_cap = tf->cap_features;
+ uint32_t new_cap = old_cap ? old_cap * 2u : 8u;
+ size_t old_sz = (size_t)old_cap * sizeof(*tf->features);
+ size_t new_sz = (size_t)new_cap * sizeof(*tf->features);
+ void* p = env->heap->realloc(env->heap, tf->features, old_sz, new_sz,
+ _Alignof(KitTargetFeature));
+ if (!p) return 1;
+ tf->features = (KitTargetFeature*)p;
+ memset(tf->features + old_cap, 0, new_sz - old_sz);
+ tf->cap_features = new_cap;
+ return 0;
+}
+
+int driver_target_features_init(DriverTargetFeatures* tf, DriverEnv* env,
+ int argc_bound) {
+ size_t bound = argc_bound > 0 ? (size_t)argc_bound + 8u : 8u;
+ if (!tf || !env || !env->heap) return 1;
+ memset(tf, 0, sizeof(*tf));
+ tf->env = env;
+ tf->cap_features = (uint32_t)bound;
+ tf->features = driver_alloc_zeroed(env, bound * sizeof(*tf->features));
+ if (!tf->features) return 1;
+ return 0;
+}
+
+void driver_target_features_fini(DriverTargetFeatures* tf, DriverEnv* env) {
+ if (!tf || !env) return;
+ driver_free(env, tf->features,
+ (size_t)tf->cap_features * sizeof(*tf->features));
+ memset(tf, 0, sizeof(*tf));
+}
+
+static int target_features_record_feature(DriverTargetFeatures* tf,
+ DriverEnv* env, KitSlice name,
+ int enabled) {
+ KitTargetFeature* f;
+ (void)env;
+ if (!name.s || name.len == 0) return 1;
+ if (tf->nfeatures >= tf->cap_features && target_features_grow(tf) != 0)
+ return 1;
+ f = &tf->features[tf->nfeatures++];
+ f->name = name;
+ f->enabled = enabled ? true : false;
+ return 0;
+}
+
+static const char* target_features_pull_value(const char* tool, int argc,
+ char** argv, int* i,
+ size_t prefix_len,
+ const char* flag_label) {
+ const char* a = argv[*i];
+ if (a[prefix_len]) return a + prefix_len;
+ if (++(*i) >= argc) {
+ driver_errf(tool, "%.*s requires an argument",
+ KIT_SLICE_ARG(kit_slice_cstr(flag_label)));
+ return NULL;
+ }
+ return argv[*i];
+}
+
+static int target_features_parse_mattr(DriverTargetFeatures* tf, DriverEnv* env,
+ const char* tool, const char* list) {
+ const char* p = list;
+ if (!p || !*p) {
+ driver_errf(tool, "-mattr= requires a comma-separated feature list");
+ return 1;
+ }
+ while (*p) {
+ int enabled;
+ const char* start;
+ if (*p == '+') {
+ enabled = 1;
+ } else if (*p == '-') {
+ enabled = 0;
+ } else {
+ driver_errf(tool, "-mattr entries must start with '+' or '-': %.*s",
+ KIT_SLICE_ARG(kit_slice_cstr(p)));
+ return 1;
+ }
+ ++p;
+ start = p;
+ while (*p && *p != ',') ++p;
+ if (p == start) {
+ driver_errf(tool, "empty -mattr feature");
+ return 1;
+ }
+ if (target_features_record_feature(
+ tf, env, (KitSlice){.s = start, .len = (size_t)(p - start)},
+ enabled) != 0) {
+ driver_errf(tool, "out of memory");
+ return 1;
+ }
+ if (*p == ',') ++p;
+ }
+ return 0;
+}
+
+int driver_target_features_try_consume(DriverTargetFeatures* tf, DriverEnv* env,
+ const char* tool, int argc, char** argv,
+ int* i) {
+ const char* a = argv[*i];
+ const char* v;
+ if (!tf || !a) return 0;
+
+ if (driver_strneq(a, "-mattr=", 7)) {
+ return target_features_parse_mattr(tf, env, tool, a + 7) == 0 ? 1 : -1;
+ }
+ if (driver_streq(a, "-mattr")) {
+ if (++(*i) >= argc) {
+ driver_errf(tool, "-mattr requires an argument");
+ return -1;
+ }
+ return target_features_parse_mattr(tf, env, tool, argv[*i]) == 0 ? 1 : -1;
+ }
+ if (driver_strneq(a, "-mfeature=", 10) ||
+ driver_strneq(a, "-mno-feature=", 13)) {
+ return 0;
+ }
+ if (driver_strneq(a, "-march=", 7)) {
+ tf->isa = kit_slice_cstr(a + 7);
+ return 1;
+ }
+ if (driver_streq(a, "-march")) {
+ if (++(*i) >= argc) {
+ driver_errf(tool, "-march requires an argument");
+ return -1;
+ }
+ tf->isa = kit_slice_cstr(argv[*i]);
+ return 1;
+ }
+ if (driver_strneq(a, "-mcpu=", 6)) {
+ tf->cpu = kit_slice_cstr(a + 6);
+ return 1;
+ }
+ if (driver_streq(a, "-mcpu")) {
+ v = target_features_pull_value(tool, argc, argv, i, 5, "-mcpu");
+ if (!v) return -1;
+ tf->cpu = kit_slice_cstr(v);
+ return 1;
+ }
+ if (driver_strneq(a, "-mtune=", 7)) {
+ tf->tune = kit_slice_cstr(a + 7);
+ return 1;
+ }
+ if (driver_streq(a, "-mtune")) {
+ v = target_features_pull_value(tool, argc, argv, i, 6, "-mtune");
+ if (!v) return -1;
+ tf->tune = kit_slice_cstr(v);
+ return 1;
+ }
+ if (driver_strneq(a, "-mno-", 5) && a[5] != '\0') {
+ if (target_features_record_feature(tf, env, kit_slice_cstr(a + 5), 0) !=
+ 0) {
+ driver_errf(tool, "out of memory");
+ return -1;
+ }
+ return 1;
+ }
+ if (driver_strneq(a, "-m", 2) && a[2] != '\0') {
+ if (target_features_record_feature(tf, env, kit_slice_cstr(a + 2), 1) !=
+ 0) {
+ driver_errf(tool, "out of memory");
+ return -1;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+int driver_target_options(const DriverTargetFeatures* tf, const char* tool,
+ KitTargetSpec target, KitTargetOptions* out) {
+ (void)tool;
+ if (!out) return 1;
+ memset(out, 0, sizeof(*out));
+ out->spec = target;
+ if (!tf) return 0;
+ out->isa = tf->isa;
+ out->cpu = tf->cpu;
+ out->tune = tf->tune;
+ out->features = tf->features;
+ out->nfeatures = tf->nfeatures;
+ return 0;
+}
+
+KitStatus driver_target_new(const KitContext* ctx, KitTargetSpec target,
+ const DriverTargetFeatures* tf, const char* tool,
+ KitTarget** out) {
+ KitTargetOptions opts;
+ if (driver_target_options(tf, tool, target, &opts) != 0) {
+ if (out) *out = NULL;
+ return KIT_INVALID;
+ }
+ return kit_target_new(ctx, &opts, out);
+}
+
+int driver_target_from_triple(const char* triple, KitTargetSpec* out) {
const char* parts[4];
size_t plen[4];
int np = 0;
const char* p;
- KitTarget t;
+ KitTargetSpec t;
int os_set;
int i;
@@ -137,7 +334,7 @@ int driver_target_from_triple(const char* triple, KitTarget* out) {
return 0;
}
-int driver_target_to_triple(KitTarget target, char* buf, size_t cap) {
+int driver_target_to_triple(KitTargetSpec target, char* buf, size_t cap) {
const char* arch;
const char* os;
int n;
diff --git a/include/kit/core.h b/include/kit/core.h
@@ -25,6 +25,7 @@
/* Opaque handles shared across component headers. */
typedef struct KitCompiler KitCompiler;
typedef struct KitCompileSession KitCompileSession;
+typedef struct KitTarget KitTarget;
typedef struct KitObjBuilder KitObjBuilder;
typedef struct KitObjFile KitObjFile;
typedef struct KitLinkSession KitLinkSession;
@@ -157,7 +158,7 @@ typedef enum KitCodeModel {
KIT_CM_LARGE,
} KitCodeModel;
-typedef struct KitTarget {
+typedef struct KitTargetSpec {
KitArchKind arch;
KitOSKind os;
KitObjFmt obj;
@@ -166,7 +167,21 @@ typedef struct KitTarget {
bool big_endian;
uint8_t pic; /* KitPic */
uint8_t code_model; /* KitCodeModel */
-} KitTarget;
+} KitTargetSpec;
+
+typedef struct KitTargetFeature {
+ KitSlice name; /* canonical target-owned feature name */
+ bool enabled;
+} KitTargetFeature;
+
+typedef struct KitTargetOptions {
+ KitTargetSpec spec;
+ KitSlice isa; /* optional ISA/profile string, e.g. rv64gc or x86-64-v3 */
+ KitSlice cpu; /* optional target CPU/profile name */
+ KitSlice tune; /* optional tuning CPU/profile name */
+ const KitTargetFeature* features;
+ uint32_t nfeatures;
+} KitTargetOptions;
typedef enum KitSymBind {
KIT_SB_LOCAL,
@@ -314,10 +329,17 @@ typedef struct KitContext {
int64_t now;
} KitContext;
-KIT_API KitStatus kit_compiler_new(KitTarget, const KitContext*,
+KIT_API KitStatus kit_target_new(const KitContext*, const KitTargetOptions*,
+ KitTarget** out);
+KIT_API void kit_target_free(KitTarget*);
+KIT_API KitTargetSpec kit_target_spec(const KitTarget*);
+KIT_API int kit_target_has_feature(const KitTarget*, KitSlice name);
+
+KIT_API KitStatus kit_compiler_new(const KitTarget*, const KitContext*,
KitCompiler** out);
KIT_API void kit_compiler_free(KitCompiler*);
-KIT_API KitTarget kit_compiler_target(KitCompiler*);
+KIT_API const KitTarget* kit_compiler_target(KitCompiler*);
+KIT_API KitTargetSpec kit_compiler_target_spec(KitCompiler*);
KIT_API const KitContext* kit_compiler_context(KitCompiler*);
diff --git a/include/kit/disasm.h b/include/kit/disasm.h
@@ -22,7 +22,7 @@ typedef struct KitInsn {
typedef struct KitDisasmIter KitDisasmIter;
typedef struct KitDisasmContext {
- KitTarget target;
+ const KitTarget* target;
KitContext context;
} KitDisasmContext;
diff --git a/include/kit/emu.h b/include/kit/emu.h
@@ -98,7 +98,7 @@ typedef enum KitEmuMode {
typedef struct KitEmuOptions {
KitSlice guest_name;
KitSlice guest_bytes;
- KitTarget guest_target;
+ KitTargetSpec guest_target;
bool has_guest_target;
const KitJitHost* jit_host;
int optimize;
diff --git a/include/kit/object.h b/include/kit/object.h
@@ -301,14 +301,14 @@ typedef struct KitObjRpathIter KitObjRpathIter;
KIT_API KitBinFmt kit_detect_fmt(const uint8_t* data, size_t len);
KIT_API KitStatus kit_detect_target(const uint8_t* data, size_t len,
- KitTarget* out);
+ KitTargetSpec* out);
KIT_API KitStatus kit_obj_open(const KitContext*, KitSlice name,
const KitSlice*, KitObjFile** out);
KIT_API void kit_obj_free(KitObjFile*);
KIT_API KitObjFmt kit_obj_fmt(const KitObjFile*);
-KIT_API KitTarget kit_obj_target(const KitObjFile*);
+KIT_API KitTargetSpec kit_obj_target(const KitObjFile*);
KIT_API uint32_t kit_obj_nsections(const KitObjFile*);
KIT_API KitStatus kit_obj_section(const KitObjFile*, KitObjSection idx,
diff --git a/lang/c/abi/c_abi.c b/lang/c/abi/c_abi.c
@@ -112,7 +112,7 @@ const ABIFuncInfo* c_abi_func_info(KitCompiler* a, Pool* p,
}
static const Type* c_size_or_uintptr(KitCompiler* a, Pool* p) {
- KitTarget target = kit_compiler_target(a);
+ KitTargetSpec target = kit_compiler_target_spec(a);
return target.ptr_size == 8 ? type_prim(p, TY_ULLONG) : type_prim(p, TY_UINT);
}
@@ -121,7 +121,7 @@ const Type* c_abi_size_type(KitCompiler* a, Pool* p) {
}
const Type* c_abi_ptrdiff_type(KitCompiler* a, Pool* p) {
- KitTarget target = kit_compiler_target(a);
+ KitTargetSpec target = kit_compiler_target_spec(a);
return target.ptr_size == 8 ? type_prim(p, TY_LLONG) : type_prim(p, TY_INT);
}
@@ -134,7 +134,7 @@ const Type* c_abi_uintptr_type(KitCompiler* a, Pool* p) {
}
const Type* c_abi_va_list_type(KitCompiler* a, Pool* p) {
- KitTarget target = kit_compiler_target(a);
+ KitTargetSpec target = kit_compiler_target_spec(a);
switch (target.arch) {
case KIT_ARCH_X86_64: {
const Type* vp = type_ptr(p, type_void(p));
diff --git a/lang/c/parse/parse_expr.c b/lang/c/parse/parse_expr.c
@@ -49,7 +49,7 @@ static const Type* ty_char16(Parser* p) {
static const Type* ty_char32(Parser* p) { return type_prim(p->pool, TY_UINT); }
static const Type* ty_wchar(Parser* p) {
- KitTarget target = kit_compiler_target(p->c);
+ KitTargetSpec target = kit_compiler_target_spec(p->c);
return target.os == KIT_OS_WINDOWS ? ty_char16(p) : ty_int(p);
}
@@ -1276,7 +1276,7 @@ static int parse_builtin_clear_cache_call(Parser* p, Sym name, SrcLoc loc) {
* Emitting the __clear_cache libcall there would reference an undefined
* symbol. Targets that need explicit coherency (ARM, RISC-V) keep the call.
* The argument expressions are still evaluated for their side effects. */
- switch (kit_compiler_target(p->c).arch) {
+ switch (kit_compiler_target_spec(p->c).arch) {
case KIT_ARCH_WASM:
case KIT_ARCH_X86_32:
case KIT_ARCH_X86_64:
diff --git a/lang/c/type/type.c b/lang/c/type/type.c
@@ -495,7 +495,7 @@ static int type_is_signed_integer_for_cg(const Type* t) {
static KitCgTypeId type_cg_builtin(KitCompiler* c, TypeKind kind) {
KitCgBuiltinTypes b = kit_cg_builtin_types(c);
- KitTarget target = kit_compiler_target(c);
+ KitTargetSpec target = kit_compiler_target_spec(c);
switch (kind) {
case TY_VOID:
return b.id[KIT_CG_BUILTIN_VOID];
diff --git a/lang/cpp/cpp_support.h b/lang/cpp/cpp_support.h
@@ -84,7 +84,7 @@ _Noreturn static inline void compiler_panicv(Compiler* c, SrcLoc loc,
* double to double. Centralized so the preprocessor's __LDBL_* /
* __SIZEOF_LONG_DOUBLE__ macros and the C type system's long-double ->
* CG-builtin mapping cannot drift apart. */
-static inline int kit_target_long_double_is_binary128(KitTarget t) {
+static inline int kit_target_long_double_is_binary128(KitTargetSpec t) {
if (t.arch == KIT_ARCH_RV64) return 1;
if (t.arch == KIT_ARCH_ARM_64 && t.os == KIT_OS_LINUX) return 1;
if (t.arch == KIT_ARCH_WASM) return 1;
diff --git a/lang/cpp/pp/pp.c b/lang/cpp/pp/pp.c
@@ -344,7 +344,7 @@ static void pp_register_static_predefined(Pp* pp) {
* pointer width plus the target data model: LP64 for Unix-like 64-bit targets,
* LLP64 for 64-bit Windows, and ILP32 for 32-bit targets. */
static void pp_register_target_predefined(Pp* pp) {
- KitTarget target = kit_compiler_target(pp->c);
+ KitTargetSpec target = kit_compiler_target_spec(pp->c);
const KitPredefinedMacro* arch_defs = NULL;
uint32_t narch_defs = kit_compiler_arch_predefines(pp->c, &arch_defs);
uint32_t i;
diff --git a/lang/toy/internal.h b/lang/toy/internal.h
@@ -237,7 +237,7 @@ typedef struct ToyParser {
KitCgTypeId int_type;
KitCgTypeId int_ptr_type;
KitCgTypeId va_list_type;
- KitTarget target;
+ KitTargetSpec target;
/* Durable cross-snippet state lives in the module; the parser borrows it
* for one compile and stages/commits/rolls back through it. */
diff --git a/lang/toy/parser_core.c b/lang/toy/parser_core.c
@@ -62,7 +62,7 @@ void toy_parser_init(ToyParser* p, KitCompiler* c, KitCg* cg, ToyModule* module,
p->int_type = toy_builtin_type(p, KIT_CG_BUILTIN_I64);
p->int_ptr_type = kit_cg_type_ptr(c, p->int_type, 0);
p->va_list_type = toy_builtin_type(p, KIT_CG_BUILTIN_VARARG_STATE);
- p->target = kit_compiler_target(c);
+ p->target = kit_compiler_target_spec(c);
p->nvars = 0;
p->cap_vars = 0;
p->vars = NULL;
@@ -103,7 +103,7 @@ void toy_parser_reinit(ToyParser* p, KitCompiler* c, KitCg* cg,
p->int_type = toy_builtin_type(p, KIT_CG_BUILTIN_I64);
p->int_ptr_type = kit_cg_type_ptr(c, p->int_type, 0);
p->va_list_type = toy_builtin_type(p, KIT_CG_BUILTIN_VARARG_STATE);
- p->target = kit_compiler_target(c);
+ p->target = kit_compiler_target_spec(c);
p->nvars = 0;
p->nscopes = 0;
p->nlabels = 0;
diff --git a/src/api/core.c b/src/api/core.c
@@ -3,23 +3,149 @@
#include "core/core.h"
#include <kit/core.h>
+#include <stdarg.h>
#include <string.h>
+#include "arch/arch.h"
#include "core/heap.h"
#include "core/pool.h"
#include "core/slice.h"
-KitStatus kit_compiler_new(KitTarget target, const KitContext* ctx,
+static void target_diag(const KitContext* ctx, const char* fmt, ...) {
+ va_list ap;
+ KitSrcLoc loc;
+ if (!ctx || !ctx->diag || !ctx->diag->emit) return;
+ loc.file_id = 0;
+ loc.line = 0;
+ loc.col = 0;
+ va_start(ap, fmt);
+ ctx->diag->emit(ctx->diag, KIT_DIAG_ERROR, loc, fmt, ap);
+ va_end(ap);
+}
+
+static void bitset_set(u64* words, u32 nwords, u32 idx, int enabled) {
+ u32 w = idx / 64u;
+ u64 bit = 1ull << (idx % 64u);
+ if (!words || w >= nwords) return;
+ if (enabled)
+ words[w] |= bit;
+ else
+ words[w] &= ~bit;
+}
+
+static int bitset_get(const u64* words, u32 nwords, u32 idx) {
+ u32 w = idx / 64u;
+ if (!words || w >= nwords) return 0;
+ return (words[w] & (1ull << (idx % 64u))) != 0;
+}
+
+KitStatus kit_target_new(const KitContext* ctx, const KitTargetOptions* opts,
+ KitTarget** out) {
+ const ArchImpl* arch;
+ KitTarget* t;
+ Heap* h;
+ u32 nwords;
+ u32 i;
+
+ if (!out) return KIT_INVALID;
+ *out = NULL;
+ if (!ctx || !ctx->heap || !opts) return KIT_INVALID;
+ arch = arch_lookup(opts->spec.arch);
+ if (!arch) {
+ target_diag(ctx, "unsupported target architecture: %u",
+ (unsigned)opts->spec.arch);
+ return KIT_UNSUPPORTED;
+ }
+
+ h = ctx->heap;
+ t = (KitTarget*)h->alloc(h, sizeof(*t), _Alignof(KitTarget));
+ if (!t) return KIT_NOMEM;
+ memset(t, 0, sizeof(*t));
+ t->ctx = ctx;
+ t->spec = opts->spec;
+
+ nwords = (arch->ntarget_features + 63u) / 64u;
+ if (nwords) {
+ t->feature_words =
+ (u64*)h->alloc(h, sizeof(*t->feature_words) * nwords, _Alignof(u64));
+ if (!t->feature_words) {
+ h->free(h, t, sizeof(*t));
+ return KIT_NOMEM;
+ }
+ memset(t->feature_words, 0, sizeof(*t->feature_words) * nwords);
+ t->nfeature_words = nwords;
+ arch_target_feature_defaults(arch, &t->spec, t->feature_words, nwords);
+ }
+
+ if (opts->isa.s && opts->isa.len) {
+ KitStatus st = arch_target_feature_apply_isa(
+ arch, &t->spec, opts->isa, t->feature_words, t->nfeature_words);
+ if (st != KIT_OK) {
+ target_diag(ctx, "unsupported ISA/profile for %s: %.*s", arch->name,
+ KIT_SLICE_ARG(opts->isa));
+ kit_target_free(t);
+ return st == KIT_UNSUPPORTED ? KIT_INVALID : st;
+ }
+ }
+
+ for (i = 0; i < opts->nfeatures; ++i) {
+ u32 idx;
+ KitSlice name = opts->features[i].name;
+ if (!arch_target_feature_index(arch, name, &idx)) {
+ target_diag(ctx, "unknown target feature for %s: %.*s", arch->name,
+ KIT_SLICE_ARG(name));
+ kit_target_free(t);
+ return KIT_INVALID;
+ }
+ bitset_set(t->feature_words, t->nfeature_words, idx,
+ opts->features[i].enabled);
+ }
+
+ *out = t;
+ return KIT_OK;
+}
+
+void kit_target_free(KitTarget* t) {
+ Heap* h;
+ if (!t) return;
+ h = t->ctx ? t->ctx->heap : NULL;
+ if (!h) return;
+ if (t->feature_words)
+ h->free(h, t->feature_words, sizeof(*t->feature_words) * t->nfeature_words);
+ h->free(h, t, sizeof(*t));
+}
+
+KitTargetSpec kit_target_spec(const KitTarget* t) {
+ KitTargetSpec spec;
+ memset(&spec, 0, sizeof spec);
+ return t ? t->spec : spec;
+}
+
+int kit_target_has_feature(const KitTarget* t, KitSlice name) {
+ const ArchImpl* arch;
+ u32 idx;
+ if (!t) return 0;
+ arch = arch_lookup(t->spec.arch);
+ if (!arch_target_feature_index(arch, name, &idx)) return 0;
+ return bitset_get(t->feature_words, t->nfeature_words, idx);
+}
+
+KitStatus kit_compiler_new(const KitTarget* target, const KitContext* ctx,
KitCompiler** out) {
Heap* h;
Compiler* c;
+ KitStatus st;
if (!out) return KIT_INVALID;
- if (!ctx || !ctx->heap) return KIT_INVALID;
+ if (!target || !ctx || !ctx->heap) return KIT_INVALID;
h = ctx->heap;
c = h->alloc(h, sizeof(*c), _Alignof(Compiler));
if (!c) return KIT_NOMEM;
- compiler_init(c, target, ctx);
+ st = compiler_init(c, target, ctx);
+ if (st != KIT_OK) {
+ h->free(h, c, sizeof(*c));
+ return st;
+ }
*out = c;
return KIT_OK;
}
@@ -32,8 +158,12 @@ void kit_compiler_free(KitCompiler* c) {
h->free(h, c, sizeof(*c));
}
-KitTarget kit_compiler_target(KitCompiler* c) {
- KitTarget t;
+const KitTarget* kit_compiler_target(KitCompiler* c) {
+ return c ? c->target_ref : NULL;
+}
+
+KitTargetSpec kit_compiler_target_spec(KitCompiler* c) {
+ KitTargetSpec t;
memset(&t, 0, sizeof t);
if (!c) return t;
return c->target;
diff --git a/src/api/disasm.c b/src/api/disasm.c
@@ -110,7 +110,17 @@ KitStatus kit_disasm_iter_new(const KitDisasmContext* dctx,
memset(it, 0, sizeof(*it));
it->ctx = &dctx->context;
it->heap = h;
- compiler_init(&it->compiler, dctx->target, &dctx->context);
+ if (!dctx->target) {
+ h->free(h, it, sizeof(*it));
+ return KIT_INVALID;
+ }
+ {
+ KitStatus st = compiler_init(&it->compiler, dctx->target, &dctx->context);
+ if (st != KIT_OK) {
+ h->free(h, it, sizeof(*it));
+ return st;
+ }
+ }
it->arch = arch_disasm_new(&it->compiler);
if (!it->arch) {
compiler_fini(&it->compiler);
@@ -229,8 +239,15 @@ KitStatus kit_disasm_obj(const KitContext* ctx, const KitObjFile* f,
KitWriter* out) {
uint32_t nsec, i;
KitDisasmContext dctx;
+ KitTarget* target = NULL;
+ KitTargetOptions topts;
+ KitStatus st;
if (!ctx || !f || !out) return KIT_INVALID;
- dctx.target = kit_obj_target(f);
+ memset(&topts, 0, sizeof topts);
+ topts.spec = kit_obj_target(f);
+ st = kit_target_new(ctx, &topts, &target);
+ if (st != KIT_OK) return st;
+ dctx.target = target;
dctx.context = *ctx;
nsec = kit_obj_nsections(f);
for (i = 0; i < nsec; ++i) {
@@ -238,7 +255,6 @@ KitStatus kit_disasm_obj(const KitContext* ctx, const KitObjFile* f,
const uint8_t* data = NULL;
size_t n = 0;
KitDisasmIter* it = NULL;
- KitStatus st;
Slice head;
if (kit_obj_section(f, i, &s) != KIT_OK) continue;
@@ -251,7 +267,10 @@ KitStatus kit_disasm_obj(const KitContext* ctx, const KitObjFile* f,
w_str(out, ":\n\n");
st = kit_disasm_iter_new(&dctx, data, n, 0, f, &it);
- if (st != KIT_OK) return st;
+ if (st != KIT_OK) {
+ kit_target_free(target);
+ return st;
+ }
for (;;) {
KitInsn ins;
KitIterResult r = kit_disasm_iter_next(it, &ins);
@@ -291,7 +310,9 @@ KitStatus kit_disasm_obj(const KitContext* ctx, const KitObjFile* f,
}
kit_disasm_iter_free(it);
}
- return kit_writer_status(out);
+ st = kit_writer_status(out);
+ kit_target_free(target);
+ return st;
}
KitStatus kit_disasm_obj_bytes(const KitContext* ctx, const KitSlice* bytes,
diff --git a/src/api/object_detect.c b/src/api/object_detect.c
@@ -77,13 +77,13 @@ KitBinFmt kit_detect_fmt(const uint8_t* data, size_t len) {
return KIT_BIN_UNKNOWN;
}
-static void detect_target_defaults(KitTarget* t) {
+static void detect_target_defaults(KitTargetSpec* t) {
t->big_endian = 0;
t->pic = KIT_PIC_NONE;
t->code_model = KIT_CM_DEFAULT;
}
-static void detect_set_ptr(KitTarget* t, KitArchKind arch) {
+static void detect_set_ptr(KitTargetSpec* t, KitArchKind arch) {
t->arch = arch;
switch (arch) {
case KIT_ARCH_X86_64:
@@ -102,7 +102,7 @@ static void detect_set_ptr(KitTarget* t, KitArchKind arch) {
}
}
-static KitStatus detect_elf(const u8* d, size_t len, KitTarget* out) {
+static KitStatus detect_elf(const u8* d, size_t len, KitTargetSpec* out) {
u8 ei_class, ei_data, ei_osabi;
u16 e_machine;
if (len < 20) return KIT_MALFORMED;
@@ -152,7 +152,7 @@ static KitStatus detect_elf(const u8* d, size_t len, KitTarget* out) {
return KIT_OK;
}
-static KitStatus detect_coff(const u8* d, size_t len, KitTarget* out) {
+static KitStatus detect_coff(const u8* d, size_t len, KitTargetSpec* out) {
u16 machine;
if (len < 2) return KIT_MALFORMED;
machine = (u16)d[0] | ((u16)d[1] << 8);
@@ -184,7 +184,7 @@ static KitStatus detect_coff(const u8* d, size_t len, KitTarget* out) {
return KIT_OK;
}
-static KitStatus detect_macho(const u8* d, size_t len, KitTarget* out) {
+static KitStatus detect_macho(const u8* d, size_t len, KitTargetSpec* out) {
u32 magic, cputype;
int swap, is64;
if (len < 8) return KIT_MALFORMED;
@@ -239,7 +239,8 @@ static KitStatus detect_macho(const u8* d, size_t len, KitTarget* out) {
return KIT_OK;
}
-KitStatus kit_detect_target(const uint8_t* data, size_t len, KitTarget* out) {
+KitStatus kit_detect_target(const uint8_t* data, size_t len,
+ KitTargetSpec* out) {
KitBinFmt bin;
if (!data || !out) return KIT_INVALID;
bin = kit_detect_fmt(data, len);
@@ -258,7 +259,7 @@ KitStatus kit_detect_target(const uint8_t* data, size_t len, KitTarget* out) {
#endif
#if KIT_OBJ_WASM_ENABLED
case KIT_BIN_WASM: {
- KitTarget t;
+ KitTargetSpec t;
t.big_endian = 0;
t.pic = KIT_PIC_NONE;
t.code_model = KIT_CM_DEFAULT;
diff --git a/src/api/object_file.c b/src/api/object_file.c
@@ -17,9 +17,10 @@
struct KitObjFile {
Compiler compiler;
const KitContext* ctx;
+ KitTarget* resolved_target;
ObjBuilder* ob;
ObjFmt fmt;
- KitTarget target;
+ KitTargetSpec target;
const u8** sec_data_cache;
u32* sec_data_size;
u32 sec_data_n;
@@ -30,7 +31,7 @@ KitStatus kit_obj_open(const KitContext* ctx, KitSlice name,
Heap* h;
KitObjFile* f;
const ObjFormatImpl* impl;
- KitTarget target;
+ KitTargetSpec target;
KitStatus st;
if (!out) return KIT_INVALID;
@@ -51,16 +52,33 @@ KitStatus kit_obj_open(const KitContext* ctx, KitSlice name,
f->fmt = target.obj;
f->target = target;
- compiler_init(&f->compiler, target, ctx);
+ {
+ KitTargetOptions topts;
+ memset(&topts, 0, sizeof topts);
+ topts.spec = target;
+ st = kit_target_new(ctx, &topts, &f->resolved_target);
+ if (st != KIT_OK) {
+ h->free(h, f, sizeof(*f));
+ return st;
+ }
+ }
+ st = compiler_init(&f->compiler, f->resolved_target, ctx);
+ if (st != KIT_OK) {
+ kit_target_free(f->resolved_target);
+ h->free(h, f, sizeof(*f));
+ return st;
+ }
if (setjmp(f->compiler.panic)) {
compiler_run_cleanups(&f->compiler);
compiler_fini(&f->compiler);
+ kit_target_free(f->resolved_target);
h->free(h, f, sizeof(*f));
return KIT_MALFORMED;
}
f->ob = impl->read(&f->compiler, name.s, input->data, input->len);
if (!f->ob) {
compiler_fini(&f->compiler);
+ kit_target_free(f->resolved_target);
h->free(h, f, sizeof(*f));
return KIT_MALFORMED;
}
@@ -84,12 +102,13 @@ void kit_obj_free(KitObjFile* f) {
}
if (f->ob) obj_free(f->ob);
compiler_fini(&f->compiler);
+ kit_target_free(f->resolved_target);
h->free(h, f, sizeof(*f));
}
KitObjFmt kit_obj_fmt(const KitObjFile* f) { return f->fmt; }
-KitTarget kit_obj_target(const KitObjFile* f) { return f->target; }
+KitTargetSpec kit_obj_target(const KitObjFile* f) { return f->target; }
uint32_t kit_obj_nsections(const KitObjFile* f) {
return obj_section_count(f->ob);
@@ -555,8 +574,8 @@ KitObjBuilder* kit_obj_file_builder(const KitObjFile* f) {
* kit_obj_free path is keyed off obj_read_bytes, so the view path uses
* its own teardown that does not depend on the cached section data
* tables. */
-KitObjFile* kit_objfile_internal_new(const KitContext* ctx, KitTarget target,
- KitObjFmt fmt) {
+KitObjFile* kit_objfile_internal_new(const KitContext* ctx,
+ KitTargetSpec target, KitObjFmt fmt) {
Heap* h;
KitObjFile* f;
if (!ctx || !ctx->heap) return NULL;
@@ -567,16 +586,34 @@ KitObjFile* kit_objfile_internal_new(const KitContext* ctx, KitTarget target,
f->ctx = ctx;
f->fmt = fmt;
f->target = target;
- compiler_init(&f->compiler, target, ctx);
+ {
+ KitTargetOptions topts;
+ KitStatus st;
+ memset(&topts, 0, sizeof topts);
+ topts.spec = target;
+ st = kit_target_new(ctx, &topts, &f->resolved_target);
+ if (st != KIT_OK) {
+ h->free(h, f, sizeof(*f));
+ return NULL;
+ }
+ st = compiler_init(&f->compiler, f->resolved_target, ctx);
+ if (st != KIT_OK) {
+ kit_target_free(f->resolved_target);
+ h->free(h, f, sizeof(*f));
+ return NULL;
+ }
+ }
if (setjmp(f->compiler.panic)) {
compiler_run_cleanups(&f->compiler);
compiler_fini(&f->compiler);
+ kit_target_free(f->resolved_target);
h->free(h, f, sizeof(*f));
return NULL;
}
f->ob = obj_new(&f->compiler);
if (!f->ob) {
compiler_fini(&f->compiler);
+ kit_target_free(f->resolved_target);
h->free(h, f, sizeof(*f));
return NULL;
}
diff --git a/src/arch/aa64/arch.c b/src/arch/aa64/arch.c
@@ -154,6 +154,24 @@ static const KitPredefinedMacro aa64_predefined_macros[] = {
{KIT_SLICE_LIT("__LITTLE_ENDIAN__"), KIT_SLICE_LIT("1")},
};
+static const ArchTargetFeature aa64_target_features[] = {
+ {"bti"},
+ {"pac-ret"},
+ {"lse"},
+};
+
+static KitStatus aa64_target_feature_apply_isa(const Target* target,
+ KitSlice isa, u64* words,
+ u32 nwords) {
+ (void)target;
+ (void)words;
+ (void)nwords;
+ if (kit_slice_eq_cstr(isa, "aarch64") || kit_slice_eq_cstr(isa, "arm64") ||
+ kit_slice_eq_cstr(isa, "armv8-a"))
+ return KIT_OK;
+ return KIT_UNSUPPORTED;
+}
+
const ArchImpl arch_impl_aa64 = {
.backend = {.name = "aa64", .make = aa64_backend_make},
.kind = KIT_ARCH_ARM_64,
@@ -169,6 +187,10 @@ const ArchImpl arch_impl_aa64 = {
.predefined_macros = aa64_predefined_macros,
.npredefined_macros =
(u32)(sizeof aa64_predefined_macros / sizeof aa64_predefined_macros[0]),
+ .target_features = aa64_target_features,
+ .ntarget_features =
+ (u32)(sizeof aa64_target_features / sizeof aa64_target_features[0]),
+ .target_feature_apply_isa = aa64_target_feature_apply_isa,
.register_name = aa64_register_name,
.register_index = aa64_register_index,
.register_count = aa64_register_iter_size,
diff --git a/src/arch/arch.h b/src/arch/arch.h
@@ -143,6 +143,10 @@ typedef struct ArchDwarfOps {
u8 pad[2];
} ArchDwarfOps;
+typedef struct ArchTargetFeature {
+ const char* name;
+} ArchTargetFeature;
+
#define ARCH_DBG_MAX_TRAP_BYTES 8u
#define ARCH_DBG_MAX_INSN_BYTES 15u
@@ -269,6 +273,11 @@ typedef struct ArchImpl {
const KitPredefinedMacro* predefined_macros;
u32 npredefined_macros;
+ const ArchTargetFeature* target_features;
+ u32 ntarget_features;
+ void (*target_feature_defaults)(const Target*, u64* words, u32 nwords);
+ KitStatus (*target_feature_apply_isa)(const Target*, KitSlice isa, u64* words,
+ u32 nwords);
const char* (*register_name)(uint32_t dwarf_idx);
int (*register_index)(const char* name, uint32_t* idx_out);
@@ -288,6 +297,11 @@ typedef struct ArchImpl {
const ArchImpl* arch_lookup(KitArchKind);
const ArchImpl* arch_for_compiler(const Compiler*);
+int arch_target_feature_index(const ArchImpl*, KitSlice name, u32* idx_out);
+void arch_target_feature_defaults(const ArchImpl*, const Target*, u64* words,
+ u32 nwords);
+KitStatus arch_target_feature_apply_isa(const ArchImpl*, const Target*,
+ KitSlice isa, u64* words, u32 nwords);
/* Spelling for a relocated operand in `cc -S` text, for the compiler's target
* arch+format. Returns 1 and fills *out when symbolizable, 0 to keep numeric
diff --git a/src/arch/registry.c b/src/arch/registry.c
@@ -95,6 +95,34 @@ const ArchImpl* arch_for_compiler(const Compiler* c) {
return arch_lookup(c->target.arch);
}
+int arch_target_feature_index(const ArchImpl* a, KitSlice name, u32* idx_out) {
+ u32 i;
+ if (!a || !name.s) return 0;
+ for (i = 0; i < a->ntarget_features; ++i) {
+ if (kit_slice_eq_cstr(name, a->target_features[i].name)) {
+ if (idx_out) *idx_out = i;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void arch_target_feature_defaults(const ArchImpl* a, const Target* target,
+ u64* words, u32 nwords) {
+ if (!a || !words || nwords == 0) return;
+ if (a->target_feature_defaults) {
+ a->target_feature_defaults(target, words, nwords);
+ }
+}
+
+KitStatus arch_target_feature_apply_isa(const ArchImpl* a, const Target* target,
+ KitSlice isa, u64* words, u32 nwords) {
+ if (!a || !isa.s || isa.len == 0) return KIT_OK;
+ if (!words && nwords != 0) return KIT_INVALID;
+ if (!a->target_feature_apply_isa) return KIT_UNSUPPORTED;
+ return a->target_feature_apply_isa(target, isa, words, nwords);
+}
+
int arch_reloc_operand(const Compiler* c, u16 reloc_kind,
ArchRelocOperand* out) {
const ArchImpl* a = arch_for_compiler(c);
diff --git a/src/arch/rv64/arch.c b/src/arch/rv64/arch.c
@@ -1,5 +1,7 @@
#include "arch/arch.h"
+#include <string.h>
+
#include "arch/rv64/asm.h"
#include "arch/rv64/disasm.h"
#include "arch/rv64/regs.h"
@@ -136,6 +138,147 @@ static const KitPredefinedMacro rv64_predefined_macros[] = {
{KIT_SLICE_LIT("__LITTLE_ENDIAN__"), KIT_SLICE_LIT("1")},
};
+enum {
+ RV64_FEAT_I = 0,
+ RV64_FEAT_M,
+ RV64_FEAT_A,
+ RV64_FEAT_F,
+ RV64_FEAT_D,
+ RV64_FEAT_C,
+ RV64_FEAT_ZICSR,
+ RV64_FEAT_ZIFENCEI,
+};
+
+static const ArchTargetFeature rv64_target_features[] = {
+ {"i"}, {"m"}, {"a"}, {"f"}, {"d"}, {"c"}, {"zicsr"}, {"zifencei"},
+};
+
+static void rv64_feature_set(u64* words, u32 nwords, u32 idx) {
+ if (!words || idx / 64u >= nwords) return;
+ words[idx / 64u] |= 1ull << (idx % 64u);
+}
+
+static void rv64_feature_clear(u64* words, u32 nwords, u32 idx) {
+ if (!words || idx / 64u >= nwords) return;
+ words[idx / 64u] &= ~(1ull << (idx % 64u));
+}
+
+static void rv64_feature_disable_all(u64* words, u32 nwords) {
+ rv64_feature_clear(words, nwords, RV64_FEAT_I);
+ rv64_feature_clear(words, nwords, RV64_FEAT_M);
+ rv64_feature_clear(words, nwords, RV64_FEAT_A);
+ rv64_feature_clear(words, nwords, RV64_FEAT_F);
+ rv64_feature_clear(words, nwords, RV64_FEAT_D);
+ rv64_feature_clear(words, nwords, RV64_FEAT_C);
+ rv64_feature_clear(words, nwords, RV64_FEAT_ZICSR);
+ rv64_feature_clear(words, nwords, RV64_FEAT_ZIFENCEI);
+}
+
+static void rv64_feature_enable_g(u64* words, u32 nwords) {
+ rv64_feature_set(words, nwords, RV64_FEAT_I);
+ rv64_feature_set(words, nwords, RV64_FEAT_M);
+ rv64_feature_set(words, nwords, RV64_FEAT_A);
+ rv64_feature_set(words, nwords, RV64_FEAT_F);
+ rv64_feature_set(words, nwords, RV64_FEAT_D);
+ rv64_feature_set(words, nwords, RV64_FEAT_ZICSR);
+ rv64_feature_set(words, nwords, RV64_FEAT_ZIFENCEI);
+}
+
+static int rv64_has_prefix(const char* p, const char* end, const char* lit) {
+ size_t n = strlen(lit);
+ return (size_t)(end - p) >= n && memcmp(p, lit, n) == 0;
+}
+
+static void rv64_skip_version(const char** pp, const char* end) {
+ const char* p = *pp;
+ while (p < end && ((*p >= '0' && *p <= '9') || *p == 'p')) ++p;
+ *pp = p;
+}
+
+static KitStatus rv64_target_feature_apply_isa(const Target* target,
+ KitSlice isa, u64* words,
+ u32 nwords) {
+ const char* p;
+ const char* end;
+ (void)target;
+ if (isa.len < 5 || memcmp(isa.s, "rv64", 4) != 0) return KIT_UNSUPPORTED;
+ p = isa.s + 4;
+ end = isa.s + isa.len;
+ rv64_feature_disable_all(words, nwords);
+ while (p < end) {
+ if (*p == '_') {
+ ++p;
+ continue;
+ }
+ switch (*p) {
+ case 'i':
+ rv64_feature_set(words, nwords, RV64_FEAT_I);
+ ++p;
+ rv64_skip_version(&p, end);
+ continue;
+ case 'm':
+ rv64_feature_set(words, nwords, RV64_FEAT_M);
+ ++p;
+ rv64_skip_version(&p, end);
+ continue;
+ case 'a':
+ rv64_feature_set(words, nwords, RV64_FEAT_A);
+ ++p;
+ rv64_skip_version(&p, end);
+ continue;
+ case 'f':
+ rv64_feature_set(words, nwords, RV64_FEAT_F);
+ ++p;
+ rv64_skip_version(&p, end);
+ continue;
+ case 'd':
+ rv64_feature_set(words, nwords, RV64_FEAT_D);
+ ++p;
+ rv64_skip_version(&p, end);
+ continue;
+ case 'c':
+ rv64_feature_set(words, nwords, RV64_FEAT_C);
+ ++p;
+ rv64_skip_version(&p, end);
+ continue;
+ case 'g':
+ rv64_feature_enable_g(words, nwords);
+ ++p;
+ rv64_skip_version(&p, end);
+ continue;
+ case 'z':
+ if (rv64_has_prefix(p, end, "zicsr")) {
+ rv64_feature_set(words, nwords, RV64_FEAT_ZICSR);
+ p += 5;
+ rv64_skip_version(&p, end);
+ continue;
+ }
+ if (rv64_has_prefix(p, end, "zifencei")) {
+ rv64_feature_set(words, nwords, RV64_FEAT_ZIFENCEI);
+ p += 8;
+ rv64_skip_version(&p, end);
+ continue;
+ }
+ break;
+ }
+ return KIT_UNSUPPORTED;
+ }
+ return KIT_OK;
+}
+
+static void rv64_target_feature_defaults(const Target* target, u64* words,
+ u32 nwords) {
+ (void)target;
+ rv64_feature_set(words, nwords, RV64_FEAT_I);
+ rv64_feature_set(words, nwords, RV64_FEAT_M);
+ rv64_feature_set(words, nwords, RV64_FEAT_A);
+ rv64_feature_set(words, nwords, RV64_FEAT_F);
+ rv64_feature_set(words, nwords, RV64_FEAT_D);
+ rv64_feature_set(words, nwords, RV64_FEAT_C);
+ rv64_feature_set(words, nwords, RV64_FEAT_ZICSR);
+ rv64_feature_set(words, nwords, RV64_FEAT_ZIFENCEI);
+}
+
static CgTarget* rv64_backend_make(Compiler* c, ObjBuilder* o,
const KitCodeOptions* opts) {
MCEmitter* mc = NULL;
@@ -184,6 +327,11 @@ const ArchImpl arch_impl_rv64 = {
.predefined_macros = rv64_predefined_macros,
.npredefined_macros =
(u32)(sizeof rv64_predefined_macros / sizeof rv64_predefined_macros[0]),
+ .target_features = rv64_target_features,
+ .ntarget_features =
+ (u32)(sizeof rv64_target_features / sizeof rv64_target_features[0]),
+ .target_feature_defaults = rv64_target_feature_defaults,
+ .target_feature_apply_isa = rv64_target_feature_apply_isa,
.register_name = rv64_register_name,
.register_index = rv64_register_index,
.register_count = rv64_register_iter_size,
diff --git a/src/arch/wasm/arch.c b/src/arch/wasm/arch.c
@@ -22,6 +22,49 @@ static const KitPredefinedMacro wasm_predefined_macros[] = {
{KIT_SLICE_LIT("__LITTLE_ENDIAN__"), KIT_SLICE_LIT("1")},
};
+enum {
+ WASM_TFEAT_THREADS = 0,
+ WASM_TFEAT_TYPED_FUNC_REFS,
+ WASM_TFEAT_TAIL_CALLS,
+ WASM_TFEAT_MULTI_MEMORY,
+ WASM_TFEAT_MEMORY64,
+ WASM_TFEAT_BULK_MEMORY,
+ WASM_TFEAT_NONTRAPPING_FTOI,
+};
+
+static const ArchTargetFeature wasm_target_features[] = {
+ {"threads"}, {"typed-func-refs"}, {"tail-calls"}, {"multi-memory"},
+ {"memory64"}, {"bulk-memory"}, {"nontrapping-ftoi"},
+};
+
+static void wasm_feature_set(u64* words, u32 nwords, u32 idx) {
+ if (!words || idx / 64u >= nwords) return;
+ words[idx / 64u] |= 1ull << (idx % 64u);
+}
+
+static KitStatus wasm_target_feature_apply_isa(const Target* target,
+ KitSlice isa, u64* words,
+ u32 nwords) {
+ (void)target;
+ (void)words;
+ (void)nwords;
+ if (kit_slice_eq_cstr(isa, "wasm32") || kit_slice_eq_cstr(isa, "wasm64"))
+ return KIT_OK;
+ return KIT_UNSUPPORTED;
+}
+
+static void wasm_target_feature_defaults(const Target* target, u64* words,
+ u32 nwords) {
+ (void)target;
+ wasm_feature_set(words, nwords, WASM_TFEAT_THREADS);
+ wasm_feature_set(words, nwords, WASM_TFEAT_TYPED_FUNC_REFS);
+ wasm_feature_set(words, nwords, WASM_TFEAT_TAIL_CALLS);
+ wasm_feature_set(words, nwords, WASM_TFEAT_MULTI_MEMORY);
+ wasm_feature_set(words, nwords, WASM_TFEAT_MEMORY64);
+ wasm_feature_set(words, nwords, WASM_TFEAT_BULK_MEMORY);
+ wasm_feature_set(words, nwords, WASM_TFEAT_NONTRAPPING_FTOI);
+}
+
static CGTarget* wasm_backend_make(Compiler* c, ObjBuilder* o,
const KitCodeOptions* opts) {
(void)opts;
@@ -40,6 +83,11 @@ const ArchImpl arch_impl_wasm = {
.predefined_macros = wasm_predefined_macros,
.npredefined_macros =
(u32)(sizeof wasm_predefined_macros / sizeof wasm_predefined_macros[0]),
+ .target_features = wasm_target_features,
+ .ntarget_features =
+ (u32)(sizeof wasm_target_features / sizeof wasm_target_features[0]),
+ .target_feature_defaults = wasm_target_feature_defaults,
+ .target_feature_apply_isa = wasm_target_feature_apply_isa,
.register_name = NULL,
.register_index = NULL,
.register_count = NULL,
diff --git a/src/arch/x64/arch.c b/src/arch/x64/arch.c
@@ -39,6 +39,68 @@ static const KitPredefinedMacro x64_predefined_macros[] = {
{KIT_SLICE_LIT("__LITTLE_ENDIAN__"), KIT_SLICE_LIT("1")},
};
+enum {
+ X64_FEAT_SSE = 0,
+ X64_FEAT_SSE2,
+ X64_FEAT_SSE3,
+ X64_FEAT_SSSE3,
+ X64_FEAT_SSE41,
+ X64_FEAT_SSE42,
+ X64_FEAT_AVX,
+ X64_FEAT_AVX2,
+};
+
+static const ArchTargetFeature x64_target_features[] = {
+ {"sse"}, {"sse2"}, {"sse3"}, {"ssse3"},
+ {"sse4.1"}, {"sse4.2"}, {"avx"}, {"avx2"},
+};
+
+static void x64_feature_set(u64* words, u32 nwords, u32 idx) {
+ if (!words || idx / 64u >= nwords) return;
+ words[idx / 64u] |= 1ull << (idx % 64u);
+}
+
+static KitStatus x64_target_feature_apply_isa(const Target* target,
+ KitSlice isa, u64* words,
+ u32 nwords) {
+ (void)target;
+ if (kit_slice_eq_cstr(isa, "x86-64") || kit_slice_eq_cstr(isa, "x86-64-v1")) {
+ x64_feature_set(words, nwords, X64_FEAT_SSE);
+ x64_feature_set(words, nwords, X64_FEAT_SSE2);
+ return KIT_OK;
+ }
+ if (kit_slice_eq_cstr(isa, "x86-64-v2")) {
+ x64_feature_set(words, nwords, X64_FEAT_SSE);
+ x64_feature_set(words, nwords, X64_FEAT_SSE2);
+ x64_feature_set(words, nwords, X64_FEAT_SSE3);
+ x64_feature_set(words, nwords, X64_FEAT_SSSE3);
+ x64_feature_set(words, nwords, X64_FEAT_SSE41);
+ x64_feature_set(words, nwords, X64_FEAT_SSE42);
+ return KIT_OK;
+ }
+ if (kit_slice_eq_cstr(isa, "x86-64-v3") ||
+ kit_slice_eq_cstr(isa, "x86-64-v4") ||
+ kit_slice_eq_cstr(isa, "haswell") || kit_slice_eq_cstr(isa, "skylake")) {
+ x64_feature_set(words, nwords, X64_FEAT_SSE);
+ x64_feature_set(words, nwords, X64_FEAT_SSE2);
+ x64_feature_set(words, nwords, X64_FEAT_SSE3);
+ x64_feature_set(words, nwords, X64_FEAT_SSSE3);
+ x64_feature_set(words, nwords, X64_FEAT_SSE41);
+ x64_feature_set(words, nwords, X64_FEAT_SSE42);
+ x64_feature_set(words, nwords, X64_FEAT_AVX);
+ x64_feature_set(words, nwords, X64_FEAT_AVX2);
+ return KIT_OK;
+ }
+ return KIT_UNSUPPORTED;
+}
+
+static void x64_target_feature_defaults(const Target* target, u64* words,
+ u32 nwords) {
+ (void)target;
+ x64_feature_set(words, nwords, X64_FEAT_SSE);
+ x64_feature_set(words, nwords, X64_FEAT_SSE2);
+}
+
static int x64_register_at_public(uint32_t idx, KitArchReg* out) {
const char* nm = NULL;
int rc;
@@ -94,6 +156,11 @@ const ArchImpl arch_impl_x64 = {
.predefined_macros = x64_predefined_macros,
.npredefined_macros =
(u32)(sizeof x64_predefined_macros / sizeof x64_predefined_macros[0]),
+ .target_features = x64_target_features,
+ .ntarget_features =
+ (u32)(sizeof x64_target_features / sizeof x64_target_features[0]),
+ .target_feature_defaults = x64_target_feature_defaults,
+ .target_feature_apply_isa = x64_target_feature_apply_isa,
.register_name = x64_register_name,
.register_index = x64_register_index,
.register_count = x64_register_iter_size,
diff --git a/src/cg/session.c b/src/cg/session.c
@@ -120,7 +120,7 @@ KitStatus kit_cg_begin_obj(KitCg* g, KitObjBuilder* out,
compiler_panic((Compiler*)c, api_no_loc(),
"KitCg: no code generator for target arch '%s' — no "
"backend enabled in this build (KIT_ARCH_*_ENABLED)",
- arch_kind_name(kit_compiler_target(c).arch));
+ arch_kind_name(kit_compiler_target_spec(c).arch));
}
target = backend->make((Compiler*)c, (ObjBuilder*)out, opts);
if (!target) return KIT_UNSUPPORTED;
diff --git a/src/core/core.c b/src/core/core.c
@@ -64,29 +64,42 @@ struct CompilerCleanup {
CompilerCleanup* prev;
};
-void compiler_init(Compiler* c, Target target, const KitContext* ctx) {
+KitStatus compiler_init(Compiler* c, const KitTarget* target,
+ const KitContext* ctx) {
Heap* h = ctx->heap;
+ if (!c || !target || !ctx || !h) return KIT_INVALID;
memset(c, 0, sizeof(*c));
c->ctx = ctx;
- c->target = target;
+ c->target_ref = target;
+ c->target = target->spec;
c->global = (Pool*)h->alloc(h, sizeof(Pool), _Alignof(Pool));
+ if (!c->global) goto nomem;
pool_init(c->global, h);
c->tu = (Arena*)h->alloc(h, sizeof(Arena), _Alignof(Arena));
+ if (!c->tu) goto nomem;
arena_init(c->tu, h, 0);
c->scratch = (Arena*)h->alloc(h, sizeof(Arena), _Alignof(Arena));
+ if (!c->scratch) goto nomem;
arena_init(c->scratch, h, 0);
c->sources = source_new(c);
+ if (!c->sources) goto nomem;
c->abi = abi_new(c);
+ if (!c->abi) goto nomem;
c->cleanup = NULL;
lang_registry_init(c);
+ return KIT_OK;
+
+nomem:
+ compiler_fini(c);
+ return KIT_NOMEM;
}
void compiler_fini(Compiler* c) {
diff --git a/src/core/core.h b/src/core/core.h
@@ -26,7 +26,7 @@ typedef KitContext Context;
typedef KitHeap Heap;
typedef KitDiagSink DiagSink;
typedef KitWriter Writer;
-typedef KitTarget Target;
+typedef KitTargetSpec Target;
typedef KitObjBuilder ObjBuilder;
typedef enum KitArchKind ArchKind;
typedef enum KitOSKind OSKind;
@@ -50,6 +50,13 @@ typedef struct SrcRange {
SrcLoc end;
} SrcRange;
+struct KitTarget {
+ const KitContext* ctx;
+ Target spec;
+ u64* feature_words;
+ u32 nfeature_words;
+};
+
typedef enum SourceFileKind {
SRC_FILE_REAL,
SRC_FILE_MEMORY,
@@ -116,6 +123,7 @@ struct KitCompiler {
Arena* scratch;
SourceManager* sources;
TargetABI* abi;
+ const KitTarget* target_ref;
Target target;
CompilerCleanup* cleanup;
const KitFrontendVTable* frontends[KIT_LANG_COUNT];
@@ -140,7 +148,7 @@ struct KitCompiler {
jmp_buf panic;
};
-void compiler_init(Compiler*, Target, const KitContext*);
+KitStatus compiler_init(Compiler*, const KitTarget*, const KitContext*);
void compiler_fini(Compiler*);
CompilerCleanup* compiler_defer(Compiler*, void (*fn)(void*), void* arg);
diff --git a/src/emu/emu.c b/src/emu/emu.c
@@ -26,7 +26,7 @@
struct KitEmu {
Compiler* c;
- KitTarget guest_target;
+ KitTargetSpec guest_target;
int opt_level;
KitEmuTraceFlags trace;
KitEmuExternalBindings bindings;
@@ -68,7 +68,7 @@ static SrcLoc no_loc(void) {
typedef u64 (*EmuBlockFn)(EmuThread*);
typedef struct EmuResolvedConfig {
- KitTarget target;
+ KitTargetSpec target;
const ObjFormatImpl* obj_format;
const ArchImpl* arch;
const KitOsImpl* os;
@@ -186,7 +186,7 @@ void emu_thread_os_free(Compiler* c, EmuThread* thread, size_t size) {
static KitStatus emu_resolve_config(Compiler* c, const KitEmuOptions* opts,
EmuResolvedConfig* out) {
KitBinFmt bin_fmt;
- KitTarget target;
+ KitTargetSpec target;
const ObjFormatImpl* obj_format;
const ObjFormatImpl* target_format;
const ArchImpl* arch;
diff --git a/src/emu/emu.h b/src/emu/emu.h
@@ -264,7 +264,7 @@ typedef struct EmuLoadedImage {
typedef struct EmuLoadOptions {
KitSlice name;
KitSlice bytes;
- KitTarget guest_target;
+ KitTargetSpec guest_target;
const char* const* argv;
const char* const* envp;
const KitOsImpl* os;
@@ -305,7 +305,7 @@ typedef struct EmuFaultEvent {
struct EmuProcess {
Compiler* compiler;
- KitTarget guest_target;
+ KitTargetSpec guest_target;
const ObjFormatImpl* obj_format;
const ArchImpl* arch;
const KitOsImpl* os;
diff --git a/src/link/link_jit.c b/src/link/link_jit.c
@@ -29,8 +29,8 @@
* KitObjFile and the internal-only helpers for allocating an empty
* KitObjFile (used by the JIT debug-view builder). */
ObjBuilder* kit_objfile_builder(const KitObjFile*);
-KitObjFile* kit_objfile_internal_new(const KitContext* ctx, KitTarget target,
- KitObjFmt fmt);
+KitObjFile* kit_objfile_internal_new(const KitContext* ctx,
+ KitTargetSpec target, KitObjFmt fmt);
void kit_objfile_internal_free(KitObjFile*);
#define jit_view_objfile_free(f) kit_objfile_internal_free(f)
diff --git a/src/obj/elf/emu_load.c b/src/obj/elf/emu_load.c
@@ -76,7 +76,7 @@ static u8 elf_phdr_perms(u32 p_flags) {
}
static KitStatus elf_detect_executable(Compiler* c, KitSlice slice,
- KitTarget* out) {
+ KitTargetSpec* out) {
const u8* bytes = slice.data;
const ObjFormatImpl* fmt;
const ObjElfArchOps* arch_ops;
diff --git a/src/obj/format.h b/src/obj/format.h
@@ -89,7 +89,7 @@ typedef struct ObjFormatDsoReader {
typedef struct ObjFormatEmuOps {
KitStatus (*detect_executable)(Compiler*, KitSlice bytes,
- KitTarget* target_out);
+ KitTargetSpec* target_out);
KitStatus (*load_executable)(Compiler*, const EmuLoadOptions*,
EmuLoadedImage* out);
KitStatus (*map_object)(Compiler*, EmuProcess*, EmuLoadedImage*,
diff --git a/test/api/abi_classify_test.c b/test/api/abi_classify_test.c
@@ -27,7 +27,7 @@ static void expect_direct_1x_int(const char* tag, const ABIArgInfo* ai,
static KitCompiler* new_compiler(KitArchKind arch, KitOSKind os,
KitObjFmt obj) {
- KitTarget t = kit_unit_target(arch, os, obj);
+ KitTargetSpec t = kit_unit_target(arch, os, obj);
KitCompiler* c = NULL;
if (kit_unit_compiler_new(&g_u, t, &c) != KIT_OK || !c) {
fprintf(stderr, "compiler_new failed for arch=%d os=%d\n", (int)arch,
diff --git a/test/api/cg_fp_cmp_test.c b/test/api/cg_fp_cmp_test.c
@@ -177,7 +177,8 @@ static void build_cmp_fn(KitCompiler* c, KitCg* cg, const char* name,
* linked runtime. The f128 lowering is covered by run_emit (emission) and, end
* to end, by the `long double` cases in the parse suite under JIT. */
static void run_exec(void) {
- KitTarget tgt = kit_unit_target(KIT_ARCH_X86_64, KIT_OS_LINUX, KIT_OBJ_ELF);
+ KitTargetSpec tgt =
+ kit_unit_target(KIT_ARCH_X86_64, KIT_OS_LINUX, KIT_OBJ_ELF);
KitCompiler* c = NULL;
KitInterpProgram* pp;
KitObjBuilder* ob = NULL;
@@ -237,7 +238,7 @@ static void run_exec(void) {
static void run_emit(KitArchKind arch, KitOSKind os, KitObjFmt fmt,
const char* tag, int opt_level, int do_f128) {
- KitTarget tgt = kit_unit_target(arch, os, fmt);
+ KitTargetSpec tgt = kit_unit_target(arch, os, fmt);
KitCompiler* c = NULL;
KitObjBuilder* ob = NULL;
KitCg* cg = NULL;
diff --git a/test/api/cg_switch_test.c b/test/api/cg_switch_test.c
@@ -251,7 +251,7 @@ static void run_all_shapes(KitCompiler* c, KitCgTypeId i32_ty,
/* ---- Entry ----------------------------------------------------------- */
int main(void) {
- KitTarget target;
+ KitTargetSpec target;
KitCompiler* c = NULL;
KitCgBuiltinTypes bi;
KitCgTypeId i32_ty;
diff --git a/test/api/cg_type_test.c b/test/api/cg_type_test.c
@@ -1354,7 +1354,7 @@ static void exercise_cg_begin_end_two_objects(KitCompiler* c) {
}
int main(void) {
- KitTarget target;
+ KitTargetSpec target;
KitCompiler* c;
KitCgBuiltinTypes bi;
KitCgTypeId void_ty;
diff --git a/test/api/target_test.c b/test/api/target_test.c
@@ -0,0 +1,129 @@
+/* target_test - public <kit/core.h> target creation and feature API. */
+
+#include <kit/core.h>
+#include <string.h>
+
+#include "lib/kit_unit.h"
+
+static KitUnit g_u;
+#define EXPECT(c, ...) CU_EXPECT(&g_u, c, __VA_ARGS__)
+
+static KitTargetSpec target_spec(KitArchKind arch, KitOSKind os,
+ KitObjFmt obj) {
+ KitTargetSpec t = kit_unit_target(arch, os, obj);
+ if (arch == KIT_ARCH_WASM) {
+ t.ptr_size = 4;
+ t.ptr_align = 4;
+ }
+ return t;
+}
+
+static KitStatus make_target(KitTargetSpec spec, KitSlice isa,
+ const KitTargetFeature* features,
+ uint32_t nfeatures, KitTarget** out) {
+ KitTargetOptions opts;
+ memset(&opts, 0, sizeof opts);
+ opts.spec = spec;
+ opts.isa = isa;
+ opts.features = features;
+ opts.nfeatures = nfeatures;
+ return kit_target_new(&g_u.ctx, &opts, out);
+}
+
+static int has(KitTarget* t, const char* name) {
+ return kit_target_has_feature(t, kit_slice_cstr(name));
+}
+
+static void check_x64_defaults_and_isa(void) {
+ KitTargetSpec spec = target_spec(KIT_ARCH_X86_64, KIT_OS_LINUX, KIT_OBJ_ELF);
+ KitTargetFeature disable_avx2[] = {
+ {KIT_SLICE_LIT("avx2"), false},
+ };
+ KitTarget* t = NULL;
+
+ EXPECT(make_target(spec, KIT_SLICE_NULL, NULL, 0, &t) == KIT_OK,
+ "x64 default target");
+ EXPECT(has(t, "sse"), "x64 default has sse");
+ EXPECT(has(t, "sse2"), "x64 default has sse2");
+ EXPECT(!has(t, "avx"), "x64 default lacks avx");
+ kit_target_free(t);
+
+ t = NULL;
+ EXPECT(make_target(spec, KIT_SLICE_LIT("x86-64-v3"), disable_avx2, 1, &t) ==
+ KIT_OK,
+ "x64 isa profile plus feature override");
+ EXPECT(has(t, "avx"), "x86-64-v3 enables avx");
+ EXPECT(!has(t, "avx2"), "explicit feature override disables avx2");
+ kit_target_free(t);
+}
+
+static void check_rv64_isa_and_overrides(void) {
+ KitTargetSpec spec = target_spec(KIT_ARCH_RV64, KIT_OS_LINUX, KIT_OBJ_ELF);
+ KitTargetFeature enable_c[] = {
+ {KIT_SLICE_LIT("c"), true},
+ };
+ KitTarget* t = NULL;
+
+ EXPECT(make_target(spec, KIT_SLICE_LIT("rv64im"), enable_c, 1, &t) == KIT_OK,
+ "rv64 isa plus feature override");
+ EXPECT(has(t, "i"), "rv64im has i");
+ EXPECT(has(t, "m"), "rv64im has m");
+ EXPECT(!has(t, "a"), "rv64im lacks a");
+ EXPECT(has(t, "c"), "explicit feature override enables c");
+ EXPECT(!has(t, "zicsr"), "rv64im lacks zicsr");
+ kit_target_free(t);
+}
+
+static void check_wasm_features(void) {
+ KitTargetSpec spec = target_spec(KIT_ARCH_WASM, KIT_OS_WASI, KIT_OBJ_WASM);
+ KitTargetFeature disable_tail_calls[] = {
+ {KIT_SLICE_LIT("tail-calls"), false},
+ };
+ KitTarget* t = NULL;
+ KitTargetSpec resolved;
+
+ EXPECT(make_target(spec, KIT_SLICE_LIT("wasm32"), disable_tail_calls, 1,
+ &t) == KIT_OK,
+ "wasm32 target with disabled tail-calls");
+ resolved = kit_target_spec(t);
+ EXPECT(resolved.arch == KIT_ARCH_WASM && resolved.ptr_size == 4,
+ "kit_target_spec preserves wasm32 shape");
+ EXPECT(!has(t, "tail-calls"),
+ "explicit feature override disables tail-calls");
+ EXPECT(has(t, "bulk-memory"), "wasm default still has bulk-memory");
+ EXPECT(!has(t, "not-a-feature"), "unknown queried feature is absent");
+ kit_target_free(t);
+}
+
+static void check_errors(void) {
+ KitTargetSpec spec = target_spec(KIT_ARCH_X86_64, KIT_OS_LINUX, KIT_OBJ_ELF);
+ KitTargetFeature bad_feature[] = {
+ {KIT_SLICE_LIT("nope"), true},
+ };
+ KitTarget* t = NULL;
+
+ g_u.last_diag[0] = '\0';
+ EXPECT(make_target(spec, KIT_SLICE_NULL, bad_feature, 1, &t) == KIT_INVALID,
+ "unknown feature rejected");
+ EXPECT(t == NULL, "unknown feature leaves target NULL");
+ EXPECT(strstr(g_u.last_diag, "unknown target feature") != NULL,
+ "unknown feature diagnostic");
+
+ g_u.last_diag[0] = '\0';
+ EXPECT(
+ make_target(spec, KIT_SLICE_LIT("x86-64-v9"), NULL, 0, &t) == KIT_INVALID,
+ "unknown ISA/profile rejected");
+ EXPECT(t == NULL, "unknown ISA/profile leaves target NULL");
+ EXPECT(strstr(g_u.last_diag, "unsupported ISA/profile") != NULL,
+ "unknown ISA/profile diagnostic");
+}
+
+int main(void) {
+ kit_unit_init(&g_u);
+ check_x64_defaults_and_isa();
+ check_rv64_isa_and_overrides();
+ check_wasm_features();
+ check_errors();
+ kit_unit_summary(&g_u, "target_test");
+ return kit_unit_status(&g_u);
+}
diff --git a/test/arch/aa64_isa_test.c b/test/arch/aa64_isa_test.c
@@ -7,7 +7,7 @@
* invariant: an alias-bearing word (e.g. ORR Rd, ZR, Rm) resolves to
* the alias spelling (MOV) rather than the canonical row.
*
- * Builds against the internal arch/aa64/isa.h surface (test.mk passes
+ * Builds against the internal arch/aa64/isa.h surface (mk/test.mk passes
* -Isrc). No public-API dependency — this is a unit test of the
* descriptor table itself. */
diff --git a/test/arch/aa64_sweep_gen.c b/test/arch/aa64_sweep_gen.c
@@ -18,7 +18,8 @@
* they aren't assemblable standalone without a label/symbol, and L1/L2 of the
* codegen round-trip already cover them.
*
- * Builds against the internal arch/aa64/isa.h surface (test.mk passes -Isrc).
+ * Builds against the internal arch/aa64/isa.h surface (mk/test.mk passes
+ * -Isrc).
*/
#include <stdint.h>
diff --git a/test/arch/inline_public_test.h b/test/arch/inline_public_test.h
@@ -39,7 +39,7 @@ typedef struct InlineEmit {
const char* name;
} InlineEmit;
-static inline KitTarget it_target(KitArchKind arch) {
+static inline KitTargetSpec it_target(KitArchKind arch) {
return kit_unit_target(arch, KIT_OS_LINUX, KIT_OBJ_ELF);
}
@@ -84,6 +84,8 @@ static inline int it_emit_text(InlineTestEnv* env, KitArchKind arch,
const char* name, InlineBodyFn body,
InlineText* text) {
KitCompiler* c = NULL;
+ KitTarget* target = NULL;
+ KitTargetOptions target_opts;
InlineEmit emit;
KitSlice bytes;
size_t len = 0;
@@ -96,8 +98,14 @@ static inline int it_emit_text(InlineTestEnv* env, KitArchKind arch,
emit.body = body;
emit.name = name;
- if (kit_compiler_new(it_target(arch), &env->ctx, &c) != KIT_OK || !c)
+ memset(&target_opts, 0, sizeof target_opts);
+ target_opts.spec = it_target(arch);
+ if (kit_target_new(&env->ctx, &target_opts, &target) != KIT_OK || !target)
return 0;
+ if (kit_compiler_new(target, &env->ctx, &c) != KIT_OK || !c) {
+ kit_target_free(target);
+ return 0;
+ }
if (kit_frontend_run(c, it_emit_func, &emit) != KIT_OK) goto done;
if (kit_writer_mem(&env->heap, &text->writer) != KIT_OK || !text->writer)
goto done;
@@ -118,6 +126,7 @@ static inline int it_emit_text(InlineTestEnv* env, KitArchKind arch,
done:
if (emit.ob) kit_obj_builder_free(emit.ob);
kit_compiler_free(c);
+ kit_target_free(target);
if (!ok) {
if (text->file) kit_obj_free(text->file);
if (text->writer) kit_writer_close(text->writer);
@@ -153,11 +162,19 @@ static inline int it_expect_panic(InlineTestEnv* env, KitArchKind arch,
const char* name, InlineBodyFn body,
const char* expected) {
KitCompiler* c = NULL;
+ KitTarget* target = NULL;
+ KitTargetOptions target_opts;
InlinePanic panic;
KitStatus st;
int ok;
- if (kit_compiler_new(it_target(arch), &env->ctx, &c) != KIT_OK || !c)
+ memset(&target_opts, 0, sizeof target_opts);
+ target_opts.spec = it_target(arch);
+ if (kit_target_new(&env->ctx, &target_opts, &target) != KIT_OK || !target)
return 0;
+ if (kit_compiler_new(target, &env->ctx, &c) != KIT_OK || !c) {
+ kit_target_free(target);
+ return 0;
+ }
panic.body = body;
panic.name = name;
env->last_diag[0] = '\0';
@@ -166,6 +183,7 @@ static inline int it_expect_panic(InlineTestEnv* env, KitArchKind arch,
env->suppress_fatal--;
ok = st == KIT_ERR && (!expected || strstr(env->last_diag, expected) != NULL);
kit_compiler_free(c);
+ kit_target_free(target);
return ok;
}
diff --git a/test/arch/rv64_decode_test.c b/test/arch/rv64_decode_test.c
@@ -21,7 +21,7 @@ static KitUnit g_u;
#define EXPECT(cond, ...) CU_EXPECT(&g_u, cond, __VA_ARGS__)
static KitCompiler* new_compiler(void) {
- KitTarget t = kit_unit_target(KIT_ARCH_RV64, KIT_OS_LINUX, KIT_OBJ_ELF);
+ KitTargetSpec t = kit_unit_target(KIT_ARCH_RV64, KIT_OS_LINUX, KIT_OBJ_ELF);
KitCompiler* c = NULL;
if (kit_unit_compiler_new(&g_u, t, &c) != KIT_OK || !c) {
fprintf(stderr, "compiler_new failed\n");
diff --git a/test/asm/harness/asm_runner.c b/test/asm/harness/asm_runner.c
@@ -251,13 +251,32 @@ static void ctx_init(KitContext* ctx) {
ctx->now = -1;
}
-static void target_from_env(KitTarget* t) {
+static void target_from_env(KitTargetSpec* t) {
if (kit_test_target_init(t) != 0) {
fprintf(stderr, "asm-runner: kit_test_target_init failed\n");
exit(2);
}
}
+static KitStatus compiler_new_for_target(KitTargetSpec spec, KitContext* ctx,
+ KitTarget** target_out,
+ KitCompiler** compiler_out) {
+ KitTargetOptions opts;
+ KitStatus st;
+ if (target_out) *target_out = NULL;
+ if (compiler_out) *compiler_out = NULL;
+ memset(&opts, 0, sizeof opts);
+ opts.spec = spec;
+ st = kit_target_new(ctx, &opts, target_out);
+ if (st != KIT_OK) return st;
+ st = kit_compiler_new(*target_out, ctx, compiler_out);
+ if (st != KIT_OK) {
+ kit_target_free(*target_out);
+ *target_out = NULL;
+ }
+ return st;
+}
+
static KitStatus compile_asm_obj(KitCompiler* c,
const KitAsmCompileOptions* opts,
KitSlice name, const KitSlice* in,
@@ -418,8 +437,9 @@ static int hex_decode(const uint8_t* in, size_t in_len, uint8_t** out,
static int mode_encode(const char* src_path, const char* out_path) {
uint8_t* src = NULL;
size_t src_len = 0;
- KitTarget tgt;
+ KitTargetSpec tgt;
KitContext ctx;
+ KitTarget* target = NULL;
KitCompiler* c = NULL;
KitSlice in;
KitAsmCompileOptions opts;
@@ -439,7 +459,7 @@ static int mode_encode(const char* src_path, const char* out_path) {
}
target_from_env(&tgt);
ctx_init(&ctx);
- if (kit_compiler_new(tgt, &ctx, &c) != KIT_OK || !c) {
+ if (compiler_new_for_target(tgt, &ctx, &target, &c) != KIT_OK || !c) {
free(src);
return 2;
}
@@ -453,6 +473,7 @@ static int mode_encode(const char* src_path, const char* out_path) {
if (compile_asm_emit(c, &opts, kit_slice_cstr(src_path), &in, w) != KIT_OK) {
kit_writer_close(w);
kit_compiler_free(c);
+ kit_target_free(target);
free(src);
return 1;
}
@@ -465,6 +486,7 @@ static int mode_encode(const char* src_path, const char* out_path) {
!of) {
kit_writer_close(w);
kit_compiler_free(c);
+ kit_target_free(target);
free(src);
return 1;
}
@@ -512,6 +534,7 @@ static int mode_encode(const char* src_path, const char* out_path) {
kit_obj_free(of);
kit_writer_close(w);
kit_compiler_free(c);
+ kit_target_free(target);
free(src);
return rc;
}
@@ -526,8 +549,9 @@ static int mode_decode(const char* in_path, const char* out_path) {
size_t raw_len = 0;
uint8_t* bytes = NULL;
size_t nbytes = 0;
- KitTarget tgt;
+ KitTargetSpec tgt;
KitContext ctx;
+ KitTarget* target = NULL;
KitCompiler* c = NULL;
KitDisasmIter* it = NULL;
KitDisasmContext dctx;
@@ -547,17 +571,18 @@ static int mode_decode(const char* in_path, const char* out_path) {
target_from_env(&tgt);
ctx_init(&ctx);
- if (kit_compiler_new(tgt, &ctx, &c) != KIT_OK || !c) {
+ if (compiler_new_for_target(tgt, &ctx, &target, &c) != KIT_OK || !c) {
free(bytes);
return 2;
}
memset(&dctx, 0, sizeof dctx);
- dctx.target = tgt;
+ dctx.target = target;
dctx.context = ctx;
if (kit_disasm_iter_new(&dctx, bytes, nbytes, 0, NULL, &it) != KIT_OK ||
!it) {
kit_compiler_free(c);
+ kit_target_free(target);
free(bytes);
return 1;
}
@@ -567,6 +592,7 @@ static int mode_decode(const char* in_path, const char* out_path) {
perror(out_path);
kit_disasm_iter_free(it);
kit_compiler_free(c);
+ kit_target_free(target);
free(bytes);
return 2;
}
@@ -588,6 +614,7 @@ static int mode_decode(const char* in_path, const char* out_path) {
kit_disasm_iter_free(it);
kit_compiler_free(c);
+ kit_target_free(target);
free(bytes);
return rc;
}
@@ -599,8 +626,9 @@ static int mode_decode(const char* in_path, const char* out_path) {
static int mode_listing(const char* in_path, const char* out_path) {
uint8_t* bytes = NULL;
size_t nbytes = 0;
- KitTarget tgt;
+ KitTargetSpec tgt;
KitContext ctx;
+ KitTarget* target = NULL;
KitCompiler* c = NULL;
KitSlice in;
KitWriter* w = NULL;
@@ -614,7 +642,7 @@ static int mode_listing(const char* in_path, const char* out_path) {
}
target_from_env(&tgt);
ctx_init(&ctx);
- if (kit_compiler_new(tgt, &ctx, &c) != KIT_OK || !c) {
+ if (compiler_new_for_target(tgt, &ctx, &target, &c) != KIT_OK || !c) {
free(bytes);
return 2;
}
@@ -627,6 +655,7 @@ static int mode_listing(const char* in_path, const char* out_path) {
if (kit_disasm_obj_bytes(&ctx, &in, w) != KIT_OK) {
kit_writer_close(w);
kit_compiler_free(c);
+ kit_target_free(target);
free(bytes);
return 1;
}
@@ -635,6 +664,7 @@ static int mode_listing(const char* in_path, const char* out_path) {
kit_writer_close(w);
kit_compiler_free(c);
+ kit_target_free(target);
free(bytes);
return rc;
}
@@ -645,8 +675,9 @@ static int mode_listing(const char* in_path, const char* out_path) {
static int mode_emit(const char* src_path, const char* out_path) {
uint8_t* src = NULL;
size_t src_len = 0;
- KitTarget tgt;
+ KitTargetSpec tgt;
KitContext ctx;
+ KitTarget* target = NULL;
KitCompiler* c = NULL;
KitSlice in;
KitAsmCompileOptions opts;
@@ -661,7 +692,7 @@ static int mode_emit(const char* src_path, const char* out_path) {
}
target_from_env(&tgt);
ctx_init(&ctx);
- if (kit_compiler_new(tgt, &ctx, &c) != KIT_OK || !c) {
+ if (compiler_new_for_target(tgt, &ctx, &target, &c) != KIT_OK || !c) {
free(src);
return 2;
}
@@ -675,6 +706,7 @@ static int mode_emit(const char* src_path, const char* out_path) {
if (compile_asm_emit(c, &opts, kit_slice_cstr(src_path), &in, w) != KIT_OK) {
kit_writer_close(w);
kit_compiler_free(c);
+ kit_target_free(target);
free(src);
return 1;
}
@@ -684,6 +716,7 @@ static int mode_emit(const char* src_path, const char* out_path) {
kit_writer_close(w);
kit_compiler_free(c);
+ kit_target_free(target);
free(src);
return rc;
}
@@ -701,8 +734,9 @@ static char g_tls_block[8192] __attribute__((aligned(16)));
static int mode_jit(const char* src_path) {
uint8_t* src = NULL;
size_t src_len = 0;
- KitTarget tgt;
+ KitTargetSpec tgt;
KitContext ctx;
+ KitTarget* target = NULL;
KitCompiler* c = NULL;
KitSlice in;
KitAsmCompileOptions opts;
@@ -718,7 +752,7 @@ static int mode_jit(const char* src_path) {
}
target_from_env(&tgt);
ctx_init(&ctx);
- if (kit_compiler_new(tgt, &ctx, &c) != KIT_OK || !c) {
+ if (compiler_new_for_target(tgt, &ctx, &target, &c) != KIT_OK || !c) {
free(src);
return 2;
}
@@ -731,6 +765,7 @@ static int mode_jit(const char* src_path) {
if (compile_asm_obj(c, &opts, kit_slice_cstr(src_path), &in, &ob) != KIT_OK ||
!ob) {
kit_compiler_free(c);
+ kit_target_free(target);
free(src);
return 1;
}
@@ -740,6 +775,7 @@ static int mode_jit(const char* src_path) {
if (link_one_obj_jit(c, ob, &jhost, "test_main", &jit) != KIT_OK || !jit) {
kit_compiler_free(c);
+ kit_target_free(target);
free(src);
return 1;
}
@@ -772,6 +808,7 @@ static int mode_jit(const char* src_path) {
kit_jit_free(jit);
kit_compiler_free(c);
+ kit_target_free(target);
free(src);
return result;
}
diff --git a/test/cg/ir_recorder_test.c b/test/cg/ir_recorder_test.c
@@ -23,7 +23,7 @@ typedef struct TestCtx {
} TestCtx;
static void tc_init(TestCtx* tc) {
- KitTarget target;
+ KitTargetSpec target;
KitCgBuiltinTypes b;
memset(tc, 0, sizeof *tc);
target = kit_unit_target(KIT_ARCH_X86_64, KIT_OS_LINUX, KIT_OBJ_ELF);
diff --git a/test/cg/native_direct_target_test.c b/test/cg/native_direct_target_test.c
@@ -22,7 +22,7 @@ typedef struct TestCtx {
} TestCtx;
static void tc_init(TestCtx* tc) {
- KitTarget target;
+ KitTargetSpec target;
KitCgBuiltinTypes b;
memset(tc, 0, sizeof *tc);
target = kit_unit_target(KIT_ARCH_X86_64, KIT_OS_LINUX, KIT_OBJ_ELF);
diff --git a/test/cg/strength_reduce_test.c b/test/cg/strength_reduce_test.c
@@ -119,7 +119,9 @@ static void slice_to_buf(KitSlice s, char* buf, size_t cap) {
* Returns the instruction count, or -1 on harness failure. */
static int op_disasm(KitArchKind arch, KitCgIntBinOp op, int64_t imm,
DisInsn* out, int cap) {
- KitTarget target = kit_unit_target(arch, KIT_OS_LINUX, KIT_OBJ_ELF);
+ KitTargetSpec target = kit_unit_target(arch, KIT_OS_LINUX, KIT_OBJ_ELF);
+ KitTargetOptions target_opts;
+ KitTarget* kt = NULL;
KitCompiler* c = NULL;
EmitCtx ctx;
KitWriter* writer = NULL;
@@ -138,20 +140,25 @@ static int op_disasm(KitArchKind arch, KitCgIntBinOp op, int64_t imm,
ctx.op = op;
ctx.imm = imm;
- if (kit_compiler_new(target, &g_u.ctx, &c) != KIT_OK || !c) return -1;
+ memset(&target_opts, 0, sizeof target_opts);
+ target_opts.spec = target;
+ if (kit_target_new(&g_u.ctx, &target_opts, &kt) != KIT_OK || !kt) return -1;
+ if (kit_compiler_new(kt, &g_u.ctx, &c) != KIT_OK || !c) goto done;
if (kit_frontend_run(c, emit_binop_fn, &ctx) != KIT_OK) goto done;
if (kit_writer_mem(&g_u.heap, &writer) != KIT_OK || !writer) goto done;
if (kit_obj_builder_emit(ctx.ob, writer) != KIT_OK) goto done;
bytes.data = kit_writer_mem_bytes(writer, &len);
bytes.len = len;
- if (kit_obj_open(&g_u.ctx, KIT_SLICE_LIT("<sr-test>"), &bytes, &file) != KIT_OK)
+ if (kit_obj_open(&g_u.ctx, KIT_SLICE_LIT("<sr-test>"), &bytes, &file) !=
+ KIT_OK)
goto done;
- if (kit_obj_section_by_name(file, KIT_SLICE_LIT(".text"), &text_sec) != KIT_OK)
+ if (kit_obj_section_by_name(file, KIT_SLICE_LIT(".text"), &text_sec) !=
+ KIT_OK)
goto done;
if (kit_obj_section_data(file, text_sec, &data, &len) != KIT_OK) goto done;
memset(&dc, 0, sizeof dc);
- dc.target = target;
+ dc.target = kt;
dc.context = g_u.ctx;
if (kit_disasm_iter_new(&dc, data, len, 0, file, &it) != KIT_OK || !it)
goto done;
@@ -168,6 +175,7 @@ done:
if (writer) kit_writer_close(writer);
if (ctx.ob) kit_obj_builder_free(ctx.ob);
kit_compiler_free(c);
+ kit_target_free(kt);
return result;
}
@@ -195,7 +203,7 @@ typedef struct ArchExpect {
const char* shl_mnem; /* immediate shift-left mnemonic (x*2^k) */
const char* shr_mnem; /* immediate logical shift-right (x u/ 2^k) */
const char* and_mnem; /* immediate bitwise-and (x u% 2^k) */
- const char* mark; /* operand marker for an immediate ("" if in mnemonic) */
+ const char* mark; /* operand marker for an immediate ("" if in mnemonic) */
} ArchExpect;
static void check_arch(const ArchExpect* ex) {
diff --git a/test/coff/kit-roundtrip-coff.c b/test/coff/kit-roundtrip-coff.c
@@ -12,7 +12,7 @@
*
* Mixes public (<kit/core.h>, <kit/object.h>) and internal
* (src/obj/obj.h, src/core/core.h) surfaces. Compiled with -Isrc
- * by test/test.mk. Not a libkit consumer in the usual sense — a
+ * by mk/test.mk. Not a libkit consumer in the usual sense — a
* test binary that pokes the same private headers the writer /
* reader use. */
@@ -75,7 +75,7 @@ static const char* g_test_name = "?";
/* ---- target builders ---------------------------------------------- */
-static void target_x64_windows(KitTarget* t) {
+static void target_x64_windows(KitTargetSpec* t) {
memset(t, 0, sizeof *t);
t->arch = KIT_ARCH_X86_64;
t->os = KIT_OS_WINDOWS;
@@ -87,7 +87,7 @@ static void target_x64_windows(KitTarget* t) {
t->code_model = KIT_CM_SMALL;
}
-static void target_aa64_windows(KitTarget* t) {
+static void target_aa64_windows(KitTargetSpec* t) {
memset(t, 0, sizeof *t);
t->arch = KIT_ARCH_ARM_64;
t->os = KIT_OS_WINDOWS;
@@ -254,16 +254,31 @@ static void run_roundtrip(Compiler* c, ObjBuilder* in,
static KitContext g_ctx;
-static Compiler* make_compiler(const KitTarget* t) {
+static Compiler* make_compiler(const KitTargetSpec* t) {
memset(&g_ctx, 0, sizeof g_ctx);
g_ctx.heap = &g_heap;
g_ctx.diag = &g_diag;
g_ctx.now = -1;
+ KitTargetOptions opts;
+ memset(&opts, 0, sizeof opts);
+ opts.spec = *t;
+ KitTarget* target = NULL;
+ if (kit_target_new(&g_ctx, &opts, &target) != KIT_OK || !target) return NULL;
KitCompiler* cc = NULL;
- if (kit_compiler_new(*t, &g_ctx, &cc) != KIT_OK || !cc) return NULL;
+ if (kit_compiler_new(target, &g_ctx, &cc) != KIT_OK || !cc) {
+ kit_target_free(target);
+ return NULL;
+ }
return (Compiler*)cc;
}
+static void free_compiler(Compiler* c) {
+ if (!c) return;
+ const KitTarget* target = kit_compiler_target((KitCompiler*)c);
+ kit_compiler_free((KitCompiler*)c);
+ kit_target_free((KitTarget*)target);
+}
+
/* ---- payload bytes ------------------------------------------------- */
/* x64: mov eax, 42 ; ret. */
@@ -294,7 +309,7 @@ static void verify_header_minimal(const ObjBuilder* ob, Pool* p) {
static void test_header_minimal_x64(void) {
g_test_name = "header_minimal_x64";
- KitTarget t;
+ KitTargetSpec t;
target_x64_windows(&t);
Compiler* c = make_compiler(&t);
EXPECT(c != NULL, "compiler_new");
@@ -302,7 +317,7 @@ static void test_header_minimal_x64(void) {
if (setjmp(c->panic)) {
compiler_run_cleanups(c);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
EXPECT(0, "panic during test");
return;
}
@@ -316,12 +331,12 @@ static void test_header_minimal_x64(void) {
run_roundtrip(c, ob, verify_header_minimal);
obj_free(ob);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
}
static void test_header_minimal_aa64(void) {
g_test_name = "header_minimal_aa64";
- KitTarget t;
+ KitTargetSpec t;
target_aa64_windows(&t);
Compiler* c = make_compiler(&t);
EXPECT(c != NULL, "compiler_new");
@@ -329,7 +344,7 @@ static void test_header_minimal_aa64(void) {
if (setjmp(c->panic)) {
compiler_run_cleanups(c);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
EXPECT(0, "panic during test");
return;
}
@@ -343,7 +358,7 @@ static void test_header_minimal_aa64(void) {
run_roundtrip(c, ob, verify_header_minimal);
obj_free(ob);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
}
/* test_text_only_x64: .text + one defined global function symbol. */
@@ -363,7 +378,7 @@ static void verify_text_only(const ObjBuilder* ob, Pool* p) {
static void test_text_only_x64(void) {
g_test_name = "text_only_x64";
- KitTarget t;
+ KitTargetSpec t;
target_x64_windows(&t);
Compiler* c = make_compiler(&t);
if (!c) {
@@ -372,7 +387,7 @@ static void test_text_only_x64(void) {
}
if (setjmp(c->panic)) {
compiler_run_cleanups(c);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
EXPECT(0, "panic");
return;
}
@@ -388,12 +403,12 @@ static void test_text_only_x64(void) {
run_roundtrip(c, ob, verify_text_only);
obj_free(ob);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
}
static void test_text_only_aa64(void) {
g_test_name = "text_only_aa64";
- KitTarget t;
+ KitTargetSpec t;
target_aa64_windows(&t);
Compiler* c = make_compiler(&t);
if (!c) {
@@ -402,7 +417,7 @@ static void test_text_only_aa64(void) {
}
if (setjmp(c->panic)) {
compiler_run_cleanups(c);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
EXPECT(0, "panic");
return;
}
@@ -418,7 +433,7 @@ static void test_text_only_aa64(void) {
run_roundtrip(c, ob, verify_text_only);
obj_free(ob);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
}
/* test_rodata: .rdata read-only data + a defined object symbol. */
@@ -438,7 +453,7 @@ static void verify_rodata(const ObjBuilder* ob, Pool* p) {
static void test_rodata(void) {
g_test_name = "rodata";
- KitTarget t;
+ KitTargetSpec t;
target_x64_windows(&t);
Compiler* c = make_compiler(&t);
if (!c) {
@@ -447,7 +462,7 @@ static void test_rodata(void) {
}
if (setjmp(c->panic)) {
compiler_run_cleanups(c);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
EXPECT(0, "panic");
return;
}
@@ -464,7 +479,7 @@ static void test_rodata(void) {
run_roundtrip(c, ob, verify_rodata);
obj_free(ob);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
}
/* test_bss: .bss section (NOBITS), one defined symbol, size > 0. */
@@ -480,7 +495,7 @@ static void verify_bss(const ObjBuilder* ob, Pool* p) {
static void test_bss(void) {
g_test_name = "bss";
- KitTarget t;
+ KitTargetSpec t;
target_x64_windows(&t);
Compiler* c = make_compiler(&t);
if (!c) {
@@ -489,7 +504,7 @@ static void test_bss(void) {
}
if (setjmp(c->panic)) {
compiler_run_cleanups(c);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
EXPECT(0, "panic");
return;
}
@@ -506,7 +521,7 @@ static void test_bss(void) {
run_roundtrip(c, ob, verify_bss);
obj_free(ob);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
}
/* test_data_with_reloc_abs64_x64: .data with an 8-byte slot
@@ -544,7 +559,7 @@ static void verify_data_abs64(const ObjBuilder* ob, Pool* p) {
static void test_data_with_reloc_abs64_x64(void) {
g_test_name = "data_with_reloc_abs64_x64";
- KitTarget t;
+ KitTargetSpec t;
target_x64_windows(&t);
Compiler* c = make_compiler(&t);
if (!c) {
@@ -553,7 +568,7 @@ static void test_data_with_reloc_abs64_x64(void) {
}
if (setjmp(c->panic)) {
compiler_run_cleanups(c);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
EXPECT(0, "panic");
return;
}
@@ -571,12 +586,12 @@ static void test_data_with_reloc_abs64_x64(void) {
run_roundtrip(c, ob, verify_data_abs64);
obj_free(ob);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
}
static void test_data_with_reloc_abs64_aa64(void) {
g_test_name = "data_with_reloc_abs64_aa64";
- KitTarget t;
+ KitTargetSpec t;
target_aa64_windows(&t);
Compiler* c = make_compiler(&t);
if (!c) {
@@ -585,7 +600,7 @@ static void test_data_with_reloc_abs64_aa64(void) {
}
if (setjmp(c->panic)) {
compiler_run_cleanups(c);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
EXPECT(0, "panic");
return;
}
@@ -603,7 +618,7 @@ static void test_data_with_reloc_abs64_aa64(void) {
run_roundtrip(c, ob, verify_data_abs64);
obj_free(ob);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
}
/* test_data_with_reloc_rel32_x64: .text with a REL32 relocation
@@ -629,7 +644,7 @@ static void verify_rel32(const ObjBuilder* ob, Pool* p) {
static void test_data_with_reloc_rel32_x64(void) {
g_test_name = "reloc_rel32_x64";
- KitTarget t;
+ KitTargetSpec t;
target_x64_windows(&t);
Compiler* c = make_compiler(&t);
if (!c) {
@@ -638,7 +653,7 @@ static void test_data_with_reloc_rel32_x64(void) {
}
if (setjmp(c->panic)) {
compiler_run_cleanups(c);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
EXPECT(0, "panic");
return;
}
@@ -661,7 +676,7 @@ static void test_data_with_reloc_rel32_x64(void) {
run_roundtrip(c, ob, verify_rel32);
obj_free(ob);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
}
/* test_aa64_branch26: .text with a BRANCH26 (R_AARCH64_CALL26)
@@ -685,7 +700,7 @@ static void verify_aa64_branch26(const ObjBuilder* ob, Pool* p) {
static void test_aa64_branch26(void) {
g_test_name = "aa64_branch26";
- KitTarget t;
+ KitTargetSpec t;
target_aa64_windows(&t);
Compiler* c = make_compiler(&t);
if (!c) {
@@ -694,7 +709,7 @@ static void test_aa64_branch26(void) {
}
if (setjmp(c->panic)) {
compiler_run_cleanups(c);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
EXPECT(0, "panic");
return;
}
@@ -714,7 +729,7 @@ static void test_aa64_branch26(void) {
run_roundtrip(c, ob, verify_aa64_branch26);
obj_free(ob);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
}
/* test_aa64_pagebase_pageoffset: ADRP + ADD pair against a .rdata
@@ -738,7 +753,7 @@ static void verify_aa64_adrp_add(const ObjBuilder* ob, Pool* p) {
static void test_aa64_pagebase_pageoffset(void) {
g_test_name = "aa64_pagebase_pageoffset";
- KitTarget t;
+ KitTargetSpec t;
target_aa64_windows(&t);
Compiler* c = make_compiler(&t);
if (!c) {
@@ -747,7 +762,7 @@ static void test_aa64_pagebase_pageoffset(void) {
}
if (setjmp(c->panic)) {
compiler_run_cleanups(c);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
EXPECT(0, "panic");
return;
}
@@ -773,7 +788,7 @@ static void test_aa64_pagebase_pageoffset(void) {
run_roundtrip(c, ob, verify_aa64_adrp_add);
obj_free(ob);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
}
/* test_long_section_name: section whose name exceeds 8 bytes,
@@ -787,7 +802,7 @@ static void verify_long_section_name(const ObjBuilder* ob, Pool* p) {
static void test_long_section_name(void) {
g_test_name = "long_section_name";
- KitTarget t;
+ KitTargetSpec t;
target_x64_windows(&t);
Compiler* c = make_compiler(&t);
if (!c) {
@@ -796,7 +811,7 @@ static void test_long_section_name(void) {
}
if (setjmp(c->panic)) {
compiler_run_cleanups(c);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
EXPECT(0, "panic");
return;
}
@@ -810,7 +825,7 @@ static void test_long_section_name(void) {
run_roundtrip(c, ob, verify_long_section_name);
obj_free(ob);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
}
/* test_long_symbol_name: symbol whose name exceeds 8 bytes — uses
@@ -828,7 +843,7 @@ static void verify_long_symbol_name(const ObjBuilder* ob, Pool* p) {
static void test_long_symbol_name(void) {
g_test_name = "long_symbol_name";
- KitTarget t;
+ KitTargetSpec t;
target_x64_windows(&t);
Compiler* c = make_compiler(&t);
if (!c) {
@@ -837,7 +852,7 @@ static void test_long_symbol_name(void) {
}
if (setjmp(c->panic)) {
compiler_run_cleanups(c);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
EXPECT(0, "panic");
return;
}
@@ -853,7 +868,7 @@ static void test_long_symbol_name(void) {
run_roundtrip(c, ob, verify_long_symbol_name);
obj_free(ob);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
}
/* test_weak_global: weak global symbol — IMAGE_SYM_CLASS_WEAK_EXTERNAL
@@ -871,7 +886,7 @@ static void verify_weak_global(const ObjBuilder* ob, Pool* p) {
static void test_weak_global(void) {
g_test_name = "weak_global";
- KitTarget t;
+ KitTargetSpec t;
target_x64_windows(&t);
Compiler* c = make_compiler(&t);
if (!c) {
@@ -880,7 +895,7 @@ static void test_weak_global(void) {
}
if (setjmp(c->panic)) {
compiler_run_cleanups(c);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
EXPECT(0, "panic");
return;
}
@@ -896,7 +911,7 @@ static void test_weak_global(void) {
run_roundtrip(c, ob, verify_weak_global);
obj_free(ob);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
}
/* test_common_symbol: COFF common — UNDEFINED section number with
@@ -916,7 +931,7 @@ static void verify_common_symbol(const ObjBuilder* ob, Pool* p) {
static void test_common_symbol(void) {
g_test_name = "common_symbol";
- KitTarget t;
+ KitTargetSpec t;
target_x64_windows(&t);
Compiler* c = make_compiler(&t);
if (!c) {
@@ -925,7 +940,7 @@ static void test_common_symbol(void) {
}
if (setjmp(c->panic)) {
compiler_run_cleanups(c);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
EXPECT(0, "panic");
return;
}
@@ -939,7 +954,7 @@ static void test_common_symbol(void) {
run_roundtrip(c, ob, verify_common_symbol);
obj_free(ob);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
}
/* test_comdat_group: two sections wired into one COMDAT group. */
@@ -975,7 +990,7 @@ static void verify_comdat_group(const ObjBuilder* ob, Pool* p) {
static void test_comdat_group(void) {
g_test_name = "comdat_group";
- KitTarget t;
+ KitTargetSpec t;
target_x64_windows(&t);
Compiler* c = make_compiler(&t);
if (!c) {
@@ -984,7 +999,7 @@ static void test_comdat_group(void) {
}
if (setjmp(c->panic)) {
compiler_run_cleanups(c);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
EXPECT(0, "panic");
return;
}
@@ -1020,7 +1035,7 @@ static void test_comdat_group(void) {
run_roundtrip(c, ob, verify_comdat_group);
obj_free(ob);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
}
/* test_static_local_symbol: STATIC storage class — file-local symbol. */
@@ -1037,7 +1052,7 @@ static void verify_static_local(const ObjBuilder* ob, Pool* p) {
static void test_static_local_symbol(void) {
g_test_name = "static_local_symbol";
- KitTarget t;
+ KitTargetSpec t;
target_x64_windows(&t);
Compiler* c = make_compiler(&t);
if (!c) {
@@ -1046,7 +1061,7 @@ static void test_static_local_symbol(void) {
}
if (setjmp(c->panic)) {
compiler_run_cleanups(c);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
EXPECT(0, "panic");
return;
}
@@ -1062,7 +1077,7 @@ static void test_static_local_symbol(void) {
run_roundtrip(c, ob, verify_static_local);
obj_free(ob);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
}
/* test_section_symbol_synthesis: input has no explicit SK_SECTION
@@ -1089,7 +1104,7 @@ static void verify_section_symbol_synthesis(const ObjBuilder* ob, Pool* p) {
static void test_section_symbol_synthesis(void) {
g_test_name = "section_symbol_synthesis";
- KitTarget t;
+ KitTargetSpec t;
target_x64_windows(&t);
Compiler* c = make_compiler(&t);
if (!c) {
@@ -1098,7 +1113,7 @@ static void test_section_symbol_synthesis(void) {
}
if (setjmp(c->panic)) {
compiler_run_cleanups(c);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
EXPECT(0, "panic");
return;
}
@@ -1125,7 +1140,7 @@ static void test_section_symbol_synthesis(void) {
run_roundtrip(c, ob, verify_section_symbol_synthesis);
obj_free(ob);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
}
/* test_tls_section: ".tls$" section gets SF_TLS on readback (name-
@@ -1142,7 +1157,7 @@ static void verify_tls_section(const ObjBuilder* ob, Pool* p) {
static void test_tls_section(void) {
g_test_name = "tls_section";
- KitTarget t;
+ KitTargetSpec t;
target_x64_windows(&t);
Compiler* c = make_compiler(&t);
if (!c) {
@@ -1151,7 +1166,7 @@ static void test_tls_section(void) {
}
if (setjmp(c->panic)) {
compiler_run_cleanups(c);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
EXPECT(0, "panic");
return;
}
@@ -1168,7 +1183,7 @@ static void test_tls_section(void) {
run_roundtrip(c, ob, verify_tls_section);
obj_free(ob);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
}
/* test_align_nibble: section with a non-trivial alignment (4096)
@@ -1184,7 +1199,7 @@ static void verify_align_nibble(const ObjBuilder* ob, Pool* p) {
static void test_align_nibble(void) {
g_test_name = "align_nibble";
- KitTarget t;
+ KitTargetSpec t;
target_x64_windows(&t);
Compiler* c = make_compiler(&t);
if (!c) {
@@ -1193,7 +1208,7 @@ static void test_align_nibble(void) {
}
if (setjmp(c->panic)) {
compiler_run_cleanups(c);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
EXPECT(0, "panic");
return;
}
@@ -1208,7 +1223,7 @@ static void test_align_nibble(void) {
run_roundtrip(c, ob, verify_align_nibble);
obj_free(ob);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
}
/* test_empty_obj: no sections, no symbols. Smallest valid .obj. */
@@ -1227,7 +1242,7 @@ static void verify_empty_obj(const ObjBuilder* ob, Pool* p) {
static void test_empty_obj(void) {
g_test_name = "empty_obj";
- KitTarget t;
+ KitTargetSpec t;
target_x64_windows(&t);
Compiler* c = make_compiler(&t);
if (!c) {
@@ -1236,7 +1251,7 @@ static void test_empty_obj(void) {
}
if (setjmp(c->panic)) {
compiler_run_cleanups(c);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
EXPECT(0, "panic");
return;
}
@@ -1246,7 +1261,7 @@ static void test_empty_obj(void) {
run_roundtrip(c, ob, verify_empty_obj);
obj_free(ob);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
}
/* ---- short-import (Microsoft .lib member) smoke ------------------ */
@@ -1263,7 +1278,7 @@ static void test_empty_obj(void) {
* name is recoverable via obj_get_coff_import_dll. */
static void test_short_import_amd64(void) {
g_test_name = "short_import_amd64";
- KitTarget t;
+ KitTargetSpec t;
target_x64_windows(&t);
Compiler* c = make_compiler(&t);
if (!c) {
@@ -1272,7 +1287,7 @@ static void test_short_import_amd64(void) {
}
if (setjmp(c->panic)) {
compiler_run_cleanups(c);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
EXPECT(0, "panic during test");
return;
}
@@ -1311,7 +1326,7 @@ static void test_short_import_amd64(void) {
ObjBuilder* ob = read_coff(c, "short-import", buf, kTotal);
EXPECT(ob != NULL, "read_coff returned NULL on short-import");
if (!ob) {
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
return;
}
@@ -1345,7 +1360,7 @@ static void test_short_import_amd64(void) {
(void)kSymLen;
(void)kDllLen;
obj_free(ob);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
}
/* ---- driver -------------------------------------------------------- */
diff --git a/test/coff/pe-dso-forwarder.c b/test/coff/pe-dso-forwarder.c
@@ -68,7 +68,7 @@ static int g_failures;
static KitContext g_ctx;
-static void target_x64_windows(KitTarget* t) {
+static void target_x64_windows(KitTargetSpec* t) {
memset(t, 0, sizeof *t);
t->arch = KIT_ARCH_X86_64;
t->os = KIT_OS_WINDOWS;
@@ -80,16 +80,31 @@ static void target_x64_windows(KitTarget* t) {
t->code_model = KIT_CM_SMALL;
}
-static Compiler* make_compiler(const KitTarget* t) {
+static Compiler* make_compiler(const KitTargetSpec* t) {
memset(&g_ctx, 0, sizeof g_ctx);
g_ctx.heap = &g_heap;
g_ctx.diag = &g_diag;
g_ctx.now = -1;
+ KitTargetOptions opts;
+ memset(&opts, 0, sizeof opts);
+ opts.spec = *t;
+ KitTarget* target = NULL;
+ if (kit_target_new(&g_ctx, &opts, &target) != KIT_OK || !target) return NULL;
KitCompiler* cc = NULL;
- if (kit_compiler_new(*t, &g_ctx, &cc) != KIT_OK || !cc) return NULL;
+ if (kit_compiler_new(target, &g_ctx, &cc) != KIT_OK || !cc) {
+ kit_target_free(target);
+ return NULL;
+ }
return (Compiler*)cc;
}
+static void free_compiler(Compiler* c) {
+ if (!c) return;
+ const KitTarget* target = kit_compiler_target((KitCompiler*)c);
+ kit_compiler_free((KitCompiler*)c);
+ kit_target_free((KitTarget*)target);
+}
+
/* ---- little-endian writers ---------------------------------------- */
static void wr_u16(uint8_t* p, uint16_t v) {
@@ -252,7 +267,7 @@ static int has_sym(const ObjBuilder* ob, Pool* p, const char* name) {
}
int main(void) {
- KitTarget t;
+ KitTargetSpec t;
target_x64_windows(&t);
Compiler* c = make_compiler(&t);
if (!c) {
@@ -262,14 +277,14 @@ int main(void) {
if (setjmp(c->panic)) {
fprintf(stderr, "FAIL: panic during pe-dso-forwarder\n");
compiler_run_cleanups(c);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
return 1;
}
uint8_t* buf = (uint8_t*)malloc(FILE_SIZE);
EXPECT(buf != NULL, "malloc PE buffer");
if (!buf) {
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
return 1;
}
build_dso(buf);
@@ -292,7 +307,7 @@ int main(void) {
"forwarded export \"%s\" missing from ObjBuilder", kForwarded);
free(buf);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
if (g_failures) {
fprintf(stderr, "FAILED %d assertion(s)\n", g_failures);
diff --git a/test/coff/pe-import-mingw.c b/test/coff/pe-import-mingw.c
@@ -91,7 +91,7 @@ static int g_failures;
static KitContext g_ctx;
-static void target_x64_windows(KitTarget* t) {
+static void target_x64_windows(KitTargetSpec* t) {
memset(t, 0, sizeof *t);
t->arch = KIT_ARCH_X86_64;
t->os = KIT_OS_WINDOWS;
@@ -103,16 +103,31 @@ static void target_x64_windows(KitTarget* t) {
t->code_model = KIT_CM_SMALL;
}
-static Compiler* make_compiler(const KitTarget* t) {
+static Compiler* make_compiler(const KitTargetSpec* t) {
memset(&g_ctx, 0, sizeof g_ctx);
g_ctx.heap = &g_heap;
g_ctx.diag = &g_diag;
g_ctx.now = -1;
+ KitTargetOptions opts;
+ memset(&opts, 0, sizeof opts);
+ opts.spec = *t;
+ KitTarget* target = NULL;
+ if (kit_target_new(&g_ctx, &opts, &target) != KIT_OK || !target) return NULL;
KitCompiler* cc = NULL;
- if (kit_compiler_new(*t, &g_ctx, &cc) != KIT_OK || !cc) return NULL;
+ if (kit_compiler_new(target, &g_ctx, &cc) != KIT_OK || !cc) {
+ kit_target_free(target);
+ return NULL;
+ }
return (Compiler*)cc;
}
+static void free_compiler(Compiler* c) {
+ if (!c) return;
+ const KitTarget* target = kit_compiler_target((KitCompiler*)c);
+ kit_compiler_free((KitCompiler*)c);
+ kit_target_free((KitTarget*)target);
+}
+
/* ---- program ObjBuilder builder ----------------------------------- */
static ObjBuilder* build_program(Compiler* c) {
@@ -233,7 +248,7 @@ int main(void) {
return 0;
}
- KitTarget t;
+ KitTargetSpec t;
target_x64_windows(&t);
Compiler* c = make_compiler(&t);
if (!c) {
@@ -244,7 +259,7 @@ int main(void) {
if (setjmp(c->panic)) {
fprintf(stderr, "FAIL: panic during pe-import-mingw\n");
compiler_run_cleanups(c);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
free(ar_bytes);
return 1;
}
@@ -272,7 +287,7 @@ int main(void) {
EXPECT(img != NULL, "link_resolve returned NULL");
if (!img) {
link_free(l);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
free(ar_bytes);
return 1;
}
@@ -303,7 +318,7 @@ int main(void) {
fprintf(stderr, "FAIL: kit_writer_mem\n");
link_image_free(img);
link_free(l);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
free(ar_bytes);
return 1;
}
@@ -362,7 +377,7 @@ int main(void) {
free(dump_p);
}
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
free(ar_bytes);
if (g_failures) {
diff --git a/test/coff/pe-import-smoke.c b/test/coff/pe-import-smoke.c
@@ -105,7 +105,7 @@ static int g_failures;
static KitContext g_ctx;
-static void target_x64_windows(KitTarget* t) {
+static void target_x64_windows(KitTargetSpec* t) {
memset(t, 0, sizeof *t);
t->arch = KIT_ARCH_X86_64;
t->os = KIT_OS_WINDOWS;
@@ -117,16 +117,31 @@ static void target_x64_windows(KitTarget* t) {
t->code_model = KIT_CM_SMALL;
}
-static Compiler* make_compiler(const KitTarget* t) {
+static Compiler* make_compiler(const KitTargetSpec* t) {
memset(&g_ctx, 0, sizeof g_ctx);
g_ctx.heap = &g_heap;
g_ctx.diag = &g_diag;
g_ctx.now = -1;
+ KitTargetOptions opts;
+ memset(&opts, 0, sizeof opts);
+ opts.spec = *t;
+ KitTarget* target = NULL;
+ if (kit_target_new(&g_ctx, &opts, &target) != KIT_OK || !target) return NULL;
KitCompiler* cc = NULL;
- if (kit_compiler_new(*t, &g_ctx, &cc) != KIT_OK || !cc) return NULL;
+ if (kit_compiler_new(target, &g_ctx, &cc) != KIT_OK || !cc) {
+ kit_target_free(target);
+ return NULL;
+ }
return (Compiler*)cc;
}
+static void free_compiler(Compiler* c) {
+ if (!c) return;
+ const KitTarget* target = kit_compiler_target((KitCompiler*)c);
+ kit_compiler_free((KitCompiler*)c);
+ kit_target_free((KitTarget*)target);
+}
+
/* ---- short-import shim builder ------------------------------------ */
static void build_short_import_amd64(uint8_t buf[SHIM_TOTAL_LEN]) {
@@ -226,7 +241,7 @@ int main(void) {
return 0;
}
- KitTarget t;
+ KitTargetSpec t;
target_x64_windows(&t);
Compiler* c = make_compiler(&t);
if (!c) {
@@ -236,7 +251,7 @@ int main(void) {
if (setjmp(c->panic)) {
fprintf(stderr, "FAIL: panic during pe-import-smoke\n");
compiler_run_cleanups(c);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
return 1;
}
@@ -263,7 +278,7 @@ int main(void) {
EXPECT(img != NULL, "link_resolve returned NULL");
if (!img) {
link_free(l);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
return 1;
}
@@ -299,7 +314,7 @@ int main(void) {
fprintf(stderr, "FAIL: kit_writer_mem\n");
link_image_free(img);
link_free(l);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
return 1;
}
link_emit_image_writer(img, w);
@@ -418,7 +433,7 @@ int main(void) {
free(dump_d);
}
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
if (g_failures) {
fprintf(stderr, "FAILED %d assertion(s)\n", g_failures);
diff --git a/test/coff/pe-mixed-archive.c b/test/coff/pe-mixed-archive.c
@@ -106,7 +106,7 @@ static int g_failures;
static KitContext g_ctx;
-static void target_x64_windows(KitTarget* t) {
+static void target_x64_windows(KitTargetSpec* t) {
memset(t, 0, sizeof *t);
t->arch = KIT_ARCH_X86_64;
t->os = KIT_OS_WINDOWS;
@@ -118,16 +118,31 @@ static void target_x64_windows(KitTarget* t) {
t->code_model = KIT_CM_SMALL;
}
-static Compiler* make_compiler(const KitTarget* t) {
+static Compiler* make_compiler(const KitTargetSpec* t) {
memset(&g_ctx, 0, sizeof g_ctx);
g_ctx.heap = &g_heap;
g_ctx.diag = &g_diag;
g_ctx.now = -1;
+ KitTargetOptions opts;
+ memset(&opts, 0, sizeof opts);
+ opts.spec = *t;
+ KitTarget* target = NULL;
+ if (kit_target_new(&g_ctx, &opts, &target) != KIT_OK || !target) return NULL;
KitCompiler* cc = NULL;
- if (kit_compiler_new(*t, &g_ctx, &cc) != KIT_OK || !cc) return NULL;
+ if (kit_compiler_new(target, &g_ctx, &cc) != KIT_OK || !cc) {
+ kit_target_free(target);
+ return NULL;
+ }
return (Compiler*)cc;
}
+static void free_compiler(Compiler* c) {
+ if (!c) return;
+ const KitTarget* target = kit_compiler_target((KitCompiler*)c);
+ kit_compiler_free((KitCompiler*)c);
+ kit_target_free((KitTarget*)target);
+}
+
/* ---- builders ----------------------------------------------------- */
static void build_short_import_amd64(uint8_t buf[SHIM_TOTAL_LEN]) {
@@ -198,7 +213,7 @@ static ObjBuilder* build_program(Compiler* c) {
/* ---- main --------------------------------------------------------- */
int main(void) {
- KitTarget t;
+ KitTargetSpec t;
target_x64_windows(&t);
Compiler* c = make_compiler(&t);
if (!c) {
@@ -208,7 +223,7 @@ int main(void) {
if (setjmp(c->panic)) {
fprintf(stderr, "FAIL: panic during pe-mixed-archive\n");
compiler_run_cleanups(c);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
return 1;
}
@@ -224,7 +239,7 @@ int main(void) {
EXPECT(helper_bytes != NULL && helper_len > 0,
"build_helper_object produced %zu bytes", helper_len);
if (!helper_bytes) {
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
return 1;
}
@@ -244,7 +259,7 @@ int main(void) {
if (kit_writer_mem(&g_heap, &aw) != KIT_OK || !aw) {
fprintf(stderr, "FAIL: writer_mem for archive\n");
free(helper_bytes);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
return 1;
}
KitArWriteOptions opts;
@@ -261,7 +276,7 @@ int main(void) {
"archive empty after kit_ar_write (len=%zu)", ar_len);
if (!ar_bytes) {
free(helper_bytes);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
return 1;
}
@@ -325,7 +340,7 @@ int main(void) {
free(ar_bytes);
free(helper_bytes);
- kit_compiler_free((KitCompiler*)c);
+ free_compiler(c);
if (g_failures) {
fprintf(stderr, "FAILED %d assertion(s)\n", g_failures);
diff --git a/test/compile/run.sh b/test/compile/run.sh
@@ -4,9 +4,9 @@
# output existence, and a few symbol/text markers via the shared kit_* verbs.
#
# Coverage: per-language compile (C / toy / wasm), the emit modes
-# (-S / --emit=c / --emit=ir), check-only, default output naming, the
-# frontend-owned wasm feature flags, and the negative paths that exercise the
-# capability gate, the frontend option parser, and the no-link policy.
+# (-S / --emit=c / --emit=ir), check-only, default output naming, the target
+# feature flag path, and the negative paths that exercise the capability gate,
+# the target/frontend option parsers, and the no-link policy.
set -u
@@ -57,8 +57,9 @@ assert_file_exists toy-obj-exists prog_toy.o
run_ok wasm-compile "$KIT" compile -c prog.wat -o prog_wat.o
assert_file_exists wasm-obj-exists prog_wat.o
-# Frontend-owned option: the wasm parser accepts -m[no-]feature.
-run_ok wasm-feature-flag "$KIT" compile -c -mno-feature=tail-calls prog.wat -o prog_wat2.o
+# Target-owned option: the driver lowers feature flags into KitTargetOptions.
+run_ok wasm-feature-flag "$KIT" compile -target wasm32-none -c \
+ -mattr=-tail-calls prog.wat -o prog_wat2.o
# ---- emit modes ------------------------------------------------------------
run_ok emit-asm "$KIT" compile -S -Iinc hello.c -o hello.s
@@ -79,8 +80,9 @@ else not_ok check-only-no-output; fi
run_fail neg-cpp-on-wasm "$KIT" compile -Iinc -c prog.wat -o x.o
# A frontend with no option parser rejects any leftover flag.
run_fail neg-unknown-toy-flag "$KIT" compile --bogus -c prog.toy -o x.o
-# The wasm parser rejects an unknown feature name.
-run_fail neg-bad-wasm-feature "$KIT" compile -mfeature=nope -c prog.wat -o x.o
+# The target parser rejects an unknown feature name.
+run_fail neg-bad-target-feature "$KIT" compile -target wasm32-none \
+ -mattr=+nope -c prog.wat -o x.o
# compile never links: object/archive inputs are refused.
run_fail neg-link-input "$KIT" compile hello.o
# One language per invocation.
diff --git a/test/debug/cfi_unit.c b/test/debug/cfi_unit.c
@@ -89,7 +89,7 @@ typedef struct CfiExpect {
} CfiExpect;
static void check_arch(const CfiExpect* ex) {
- KitTarget t;
+ KitTargetSpec t;
Compiler* c;
ObjBuilder* ob;
ObjSecId text_sec;
diff --git a/test/debug/roundtrip_unit.c b/test/debug/roundtrip_unit.c
@@ -77,7 +77,7 @@ static u8 byte_at(const Section* s, u32 ofs) {
#define ARCH_NOP_RV64 0x00000013u /* ADDI x0, x0, 0 */
static int run_one(KitArchKind arch, uint32_t nop_word, const char* tag) {
- KitTarget t;
+ KitTargetSpec t;
Compiler* c;
ObjBuilder* ob;
Debug* d;
@@ -304,7 +304,7 @@ static void run_arch_register_checks(void) {
}
static int run_x64_debug_line_check(void) {
- KitTarget xt;
+ KitTargetSpec xt;
Compiler* xc;
ObjBuilder* xob;
Debug* xd;
diff --git a/test/dwarf/dwarf_test.c b/test/dwarf/dwarf_test.c
@@ -1059,7 +1059,7 @@ static void run_tests(KitDebugInfo* di) {
}
int main(void) {
- KitTarget target;
+ KitTargetSpec target;
kit_unit_init(&g_u);
g_u.ctx.now = -1;
target = kit_unit_target(KIT_ARCH_ARM_64, KIT_OS_LINUX, KIT_OBJ_ELF);
diff --git a/test/elf/kit-roundtrip.c b/test/elf/kit-roundtrip.c
@@ -120,7 +120,7 @@ int main(int argc, char** argv) {
return 1;
}
- KitTarget target;
+ KitTargetSpec target;
if (kit_detect_target(in_data, in_len, &target) != KIT_OK ||
target.obj != KIT_OBJ_ELF) {
fprintf(stderr, "error: %s: not a recognized object file\n", in_path);
diff --git a/test/elf/run.sh b/test/elf/run.sh
@@ -65,7 +65,7 @@ command -v readelf >/dev/null 2>&1 && have_llvm_readelf=1
command -v python3 >/dev/null 2>&1 && have_python3=1
# ----- locate kit-roundtrip -------------------------------------------
-# Built as a Make target (test/test.mk) so it picks up libkit.a changes.
+# Built as a Make target (mk/test.mk) so it picks up libkit.a changes.
ROUNDTRIP_BIN="$BUILD_DIR/kit-roundtrip"
roundtrip_ok=0
@@ -92,7 +92,7 @@ fi
# Map (KIT_TEST_ARCH, KIT_TEST_OBJ) (defaults aa64+elf) to the clang
# `--target=` triple the Layer B golden objects are compiled against.
# kit-roundtrip then detects the input's e_machine / Mach-O cputype and
-# constructs a matching KitTarget, so the readelf/objdump diff stays
+# constructs a matching KitTargetSpec, so the readelf/objdump diff stays
# apples-to-apples per target.
case "${KIT_TEST_OBJ:-elf}" in
elf)
diff --git a/test/elf/unit/align_4k.c b/test/elf/unit/align_4k.c
@@ -62,7 +62,7 @@ static const uint8_t TEXT_BYTES[8] = {
#define WANT_ALIGN 4096u
int main(void) {
- KitTarget target;
+ KitTargetSpec target;
if (kit_test_target_init(&target) != 0) {
fprintf(stderr, "FAIL: kit_test_target_init\n");
return 1;
@@ -73,9 +73,18 @@ int main(void) {
.diag = &g_diag,
.metrics = NULL,
.now = -1};
+ KitTargetOptions target_opts;
+ memset(&target_opts, 0, sizeof target_opts);
+ target_opts.spec = target;
+ KitTarget* kt = NULL;
+ if (kit_target_new(&ctx, &target_opts, &kt) != KIT_OK || !kt) {
+ fprintf(stderr, "FAIL: kit_target_new\n");
+ return 1;
+ }
KitCompiler* cc = NULL;
- if (kit_compiler_new(target, &ctx, &cc) != KIT_OK || !cc) {
+ if (kit_compiler_new(kt, &ctx, &cc) != KIT_OK || !cc) {
fprintf(stderr, "FAIL: kit_compiler_new\n");
+ kit_target_free(kt);
return 1;
}
KitObjBuilder* in = NULL;
@@ -140,6 +149,7 @@ int main(void) {
free(roundtrip);
kit_obj_builder_free(in);
kit_compiler_free(cc);
+ kit_target_free(kt);
if (g_failures) {
fprintf(stderr, "%d failure(s)\n", g_failures);
diff --git a/test/elf/unit/groupiter.c b/test/elf/unit/groupiter.c
@@ -66,7 +66,7 @@ static int name_eq(KitSlice s, const char* want) {
}
int main(void) {
- KitTarget target;
+ KitTargetSpec target;
if (kit_test_target_init(&target) != 0) {
fprintf(stderr, "FAIL: kit_test_target_init\n");
return 1;
@@ -77,9 +77,18 @@ int main(void) {
.diag = &g_diag,
.metrics = NULL,
.now = -1};
+ KitTargetOptions target_opts;
+ memset(&target_opts, 0, sizeof target_opts);
+ target_opts.spec = target;
+ KitTarget* kt = NULL;
+ if (kit_target_new(&ctx, &target_opts, &kt) != KIT_OK || !kt) {
+ fprintf(stderr, "FAIL: kit_target_new\n");
+ return 1;
+ }
KitCompiler* cc = NULL;
- if (kit_compiler_new(target, &ctx, &cc) != KIT_OK || !cc) {
+ if (kit_compiler_new(kt, &ctx, &cc) != KIT_OK || !cc) {
fprintf(stderr, "FAIL: kit_compiler_new\n");
+ kit_target_free(kt);
return 1;
}
/* ---- build ---- */
@@ -198,6 +207,7 @@ int main(void) {
free(roundtrip);
kit_obj_builder_free(in);
kit_compiler_free(cc);
+ kit_target_free(kt);
if (g_failures) {
fprintf(stderr, "%d failure(s)\n", g_failures);
diff --git a/test/elf/unit/mutate.c b/test/elf/unit/mutate.c
@@ -66,7 +66,7 @@ static const uint8_t TEXT_BYTES[8] = {
};
int main(void) {
- KitTarget target;
+ KitTargetSpec target;
if (kit_test_target_init(&target) != 0) {
fprintf(stderr, "FAIL: kit_test_target_init\n");
return 1;
@@ -76,9 +76,18 @@ int main(void) {
.diag = &g_diag,
.metrics = NULL,
.now = -1};
+ KitTargetOptions target_opts;
+ memset(&target_opts, 0, sizeof target_opts);
+ target_opts.spec = target;
+ KitTarget* kt = NULL;
+ if (kit_target_new(&ctx, &target_opts, &kt) != KIT_OK || !kt) {
+ fprintf(stderr, "FAIL: kit_target_new\n");
+ return 1;
+ }
KitCompiler* cc = NULL;
- if (kit_compiler_new(target, &ctx, &cc) != KIT_OK || !cc) {
+ if (kit_compiler_new(kt, &ctx, &cc) != KIT_OK || !cc) {
fprintf(stderr, "FAIL: kit_compiler_new\n");
+ kit_target_free(kt);
return 1;
}
/* ---- build ---- */
@@ -272,6 +281,7 @@ int main(void) {
free(roundtrip);
kit_obj_builder_free(ob);
kit_compiler_free(cc);
+ kit_target_free(kt);
if (g_failures) {
fprintf(stderr, "%d failure(s)\n", g_failures);
diff --git a/test/elf/unit/smoke.c b/test/elf/unit/smoke.c
@@ -73,7 +73,7 @@ static const uint8_t TEXT_BYTES[8] = {
0x40, 0x05, 0x80, 0x52, 0xc0, 0x03, 0x5f, 0xd6,
};
-static KitObjBuilder* build_input(KitCompiler* c, KitTarget target) {
+static KitObjBuilder* build_input(KitCompiler* c, KitTargetSpec target) {
KitObjBuilder* ob = NULL;
KitObjSection sec_text = KIT_SECTION_NONE;
KitObjSection sec_data = KIT_SECTION_NONE;
@@ -240,7 +240,7 @@ static void verify_shape(KitObjFile* f) {
/* ---- main ---- */
int main(void) {
- KitTarget target;
+ KitTargetSpec target;
if (kit_test_target_init(&target) != 0) {
fprintf(stderr, "FAIL: kit_test_target_init\n");
return 1;
@@ -252,9 +252,18 @@ int main(void) {
ctx.diag = &g_diag;
ctx.now = -1;
+ KitTargetOptions target_opts;
+ memset(&target_opts, 0, sizeof target_opts);
+ target_opts.spec = target;
+ KitTarget* kt = NULL;
+ if (kit_target_new(&ctx, &target_opts, &kt) != KIT_OK || !kt) {
+ fprintf(stderr, "FAIL: kit_target_new\n");
+ return 1;
+ }
KitCompiler* cc = NULL;
- if (kit_compiler_new(target, &ctx, &cc) != KIT_OK || !cc) {
+ if (kit_compiler_new(kt, &ctx, &cc) != KIT_OK || !cc) {
fprintf(stderr, "FAIL: kit_compiler_new\n");
+ kit_target_free(kt);
return 1;
}
/* Build, emit, read back, inspect. */
@@ -289,6 +298,7 @@ int main(void) {
free(roundtrip);
kit_obj_builder_free(in);
kit_compiler_free(cc);
+ kit_target_free(kt);
if (g_failures) {
fprintf(stderr, "%d failure(s)\n", g_failures);
diff --git a/test/elf/unit/x64_disasm_annotations.c b/test/elf/unit/x64_disasm_annotations.c
@@ -53,8 +53,8 @@ static int g_failures;
} \
} while (0)
-static KitTarget x64_elf_target(void) {
- KitTarget t;
+static KitTargetSpec x64_elf_target(void) {
+ KitTargetSpec t;
memset(&t, 0, sizeof t);
t.arch = KIT_ARCH_X86_64;
t.os = KIT_OS_LINUX;
@@ -64,7 +64,7 @@ static KitTarget x64_elf_target(void) {
return t;
}
-static KitObjBuilder* build_input(KitCompiler* c, KitTarget target) {
+static KitObjBuilder* build_input(KitCompiler* c, KitTargetSpec target) {
KitObjBuilder* ob = NULL;
KitObjSection sec_text = KIT_SECTION_NONE;
CHECK(kit_obj_builder_new(c, &ob) == KIT_OK && ob, "kit_obj_builder_new");
@@ -253,7 +253,7 @@ static void check_disasm_annotations(const KitSlice* bytes,
}
int main(void) {
- KitTarget target = x64_elf_target();
+ KitTargetSpec target = x64_elf_target();
KitContext ctx;
KitCompiler* cc = NULL;
KitObjBuilder* ob;
@@ -267,8 +267,17 @@ int main(void) {
ctx.diag = &g_diag;
ctx.now = -1;
- if (kit_compiler_new(target, &ctx, &cc) != KIT_OK || !cc) {
+ KitTargetOptions target_opts;
+ memset(&target_opts, 0, sizeof target_opts);
+ target_opts.spec = target;
+ KitTarget* kt = NULL;
+ if (kit_target_new(&ctx, &target_opts, &kt) != KIT_OK || !kt) {
+ fprintf(stderr, "FAIL: kit_target_new\n");
+ return 1;
+ }
+ if (kit_compiler_new(kt, &ctx, &cc) != KIT_OK || !cc) {
fprintf(stderr, "FAIL: kit_compiler_new\n");
+ kit_target_free(kt);
return 1;
}
@@ -285,6 +294,7 @@ int main(void) {
kit_writer_close(w);
kit_obj_builder_free(ob);
kit_compiler_free(cc);
+ kit_target_free(kt);
if (g_failures) {
fprintf(stderr, "%d failure(s)\n", g_failures);
diff --git a/test/emu/rv64_interp_smoke_test.c b/test/emu/rv64_interp_smoke_test.c
@@ -197,7 +197,7 @@ static KitCompiler* new_host_compiler(void) {
KitArchKind arch;
KitOSKind os;
KitObjFmt obj;
- KitTarget t;
+ KitTargetSpec t;
KitCompiler* c = NULL;
#if defined(__x86_64__) || defined(_M_X64)
arch = KIT_ARCH_X86_64;
@@ -468,7 +468,7 @@ static int run_guest(const unsigned char* elf, size_t elf_len, KitEmuMode mode,
KitCompiler* c = new_host_compiler();
KitJitHost host;
KitEmuOptions opts;
- KitTarget gt;
+ KitTargetSpec gt;
int exit_code = -1;
KitStatus st;
long ps;
diff --git a/test/emu/rv64_smoke_test.c b/test/emu/rv64_smoke_test.c
@@ -199,7 +199,7 @@ static KitCompiler* new_host_compiler(void) {
KitArchKind arch;
KitOSKind os;
KitObjFmt obj;
- KitTarget t;
+ KitTargetSpec t;
KitCompiler* c = NULL;
#if defined(__x86_64__) || defined(_M_X64)
arch = KIT_ARCH_X86_64;
@@ -1011,7 +1011,7 @@ static void emu_fixture_expect_exit_with_bindings(
KitCompiler* c;
KitJitHost host;
KitEmuOptions opts;
- KitTarget guest_target;
+ KitTargetSpec guest_target;
KitStatus st;
int exit_code = -1;
long ps;
diff --git a/test/emu/rv64_vm_unit_test.c b/test/emu/rv64_vm_unit_test.c
@@ -3,8 +3,9 @@
* These exercise INTERNAL units that have no public API surface — the rv64
* decoder (ArchDecodeOps), the guest address space (EmuAddrSpace), and the
* Linux syscall handler (mmap/mprotect/munmap) — so this binary links the
- * library objects directly (test.mk), unlike rv64_smoke_test.c which drives the
- * emulator end-to-end through the public kit_emu_* API and links the archive.
+ * library objects directly (mk/test.mk), unlike rv64_smoke_test.c which drives
+ * the emulator end-to-end through the public kit_emu_* API and links the
+ * archive.
*/
#include <kit/compile.h>
@@ -27,7 +28,7 @@ static KitUnit g_u;
#define EXPECT(cond, ...) CU_EXPECT(&g_u, cond, __VA_ARGS__)
static KitCompiler* new_compiler(void) {
- KitTarget t = kit_unit_target(KIT_ARCH_RV64, KIT_OS_LINUX, KIT_OBJ_ELF);
+ KitTargetSpec t = kit_unit_target(KIT_ARCH_RV64, KIT_OS_LINUX, KIT_OBJ_ELF);
KitCompiler* c = NULL;
if (kit_unit_compiler_new(&g_u, t, &c) != KIT_OK || !c) {
fprintf(stderr, "compiler_new failed\n");
@@ -40,7 +41,7 @@ static KitCompiler* new_host_compiler(void) {
KitArchKind arch;
KitOSKind os;
KitObjFmt obj;
- KitTarget t;
+ KitTargetSpec t;
KitCompiler* c = NULL;
#if defined(__x86_64__) || defined(_M_X64)
arch = KIT_ARCH_X86_64;
diff --git a/test/interp/interp_smoke_test.c b/test/interp/interp_smoke_test.c
@@ -38,7 +38,7 @@ typedef struct TestCtx {
} TestCtx;
static void tc_init(TestCtx* tc) {
- KitTarget target;
+ KitTargetSpec target;
KitCgBuiltinTypes b;
memset(tc, 0, sizeof *tc);
target = kit_unit_target(KIT_ARCH_ARM_64, KIT_OS_MACOS, KIT_OBJ_MACHO);
diff --git a/test/lib/kit_corpus.sh b/test/lib/kit_corpus.sh
@@ -34,6 +34,10 @@
# KIT_FLUSH_VERIFY optional fn, called per queued-E item after flush: args
# (label, payload, rc); return 0 to keep pass, 1 to fail
#
+# Debugging:
+# KIT_CORPUS_TRACE=1 force serial dispatch and print each item/lane before it
+# runs; deferred exec queues are flushed after each item.
+#
# Per-item vars the engine sets before each kit_lane_<ID> call:
# KIT_BASE KIT_SRC KIT_WORK KIT_OPT KIT_LANE KIT_ARCH KIT_OBJ KIT_TUPLE KIT_EXPECTED
# KIT_NAME (display label "base" or "base/Oopt") KIT_SIDECAR_DIR
@@ -61,6 +65,18 @@ kit_now_ms() {
fi
}
+kit_corpus_trace_enabled() {
+ case "${KIT_CORPUS_TRACE:-0}" in
+ ""|0|false|FALSE|no|NO) return 1 ;;
+ *) return 0 ;;
+ esac
+}
+
+kit_corpus_trace() {
+ kit_corpus_trace_enabled || return 0
+ printf 'TRACE %s\n' "$*" >&2
+}
+
# Deferred-exec bookkeeping (populated ONLY during serial execution / replay,
# never inside a worker — workers merely emit QUEUE_E events).
CFQ_LABELS=(); CFQ_RCS=(); CFQ_EXPS=(); CFQ_PAYLOADS=()
@@ -116,6 +132,7 @@ kit_corpus_item() {
else
KIT_NAME="$KIT_BASE/O$KIT_OPT"; KIT_WORK="$KIT_BUILD_DIR/$KIT_BASE/O$KIT_OPT/$KIT_TUPLE"
fi
+ kit_corpus_trace "item $KIT_NAME tuple=$KIT_TUPLE src=$KIT_SRC"
rm -rf "$KIT_WORK"; mkdir -p "$KIT_WORK"
KIT_EXPECTED=0
@@ -152,8 +169,10 @@ kit_corpus_item() {
esac
# per-lane sidecar skip (.<lane>.skip)
if reason=$(kit_skip_sidecar "$KIT_SIDECAR_DIR" "$KIT_BASE" "" "$lane"); then
+ kit_corpus_trace "lane $KIT_NAME/$lane skip-sidecar"
kit_skip "$KIT_NAME/$lane" "$reason"; continue
fi
+ kit_corpus_trace "lane $KIT_NAME/$lane"
"kit_lane_$lane"
done
}
@@ -198,6 +217,7 @@ kit_corpus_replay() {
# ---- deferred-exec flush + per-case verification ---------------------------
kit_corpus_flush_e() {
[ "${#CFQ_LABELS[@]}" -eq 0 ] && return 0
+ kit_corpus_trace "flush E queued=${#CFQ_LABELS[@]}"
exec_target_flush
local i rc ok
for i in "${!CFQ_LABELS[@]}"; do
@@ -253,12 +273,18 @@ kit_corpus_run() {
done
local jobs; jobs="$(kit_parallel_jobs)" || jobs=1
+ if kit_corpus_trace_enabled; then
+ KIT_PARALLELIZABLE=0
+ jobs=1
+ kit_corpus_trace "dispatch serial items=${#KIT_ITEMS[@]} lanes=${KIT_LANES# }"
+ fi
if [ "$KIT_PARALLELIZABLE" = "1" ] && [ "$jobs" -gt 1 ] && [ "${#KIT_ITEMS[@]}" -gt 4 ]; then
kit_corpus_dispatch_parallel "$jobs"
else
local idx=0
for item in "${KIT_ITEMS[@]}"; do
KIT_EV=; kit_corpus_item "$item"
+ kit_corpus_trace_enabled && kit_corpus_flush_e
idx=$((idx + 1))
done
fi
diff --git a/test/lib/kit_test_target.h b/test/lib/kit_test_target.h
@@ -1,4 +1,4 @@
-/* Shared KitTarget setup for C test runners.
+/* Shared KitTargetSpec setup for C test runners.
*
* Reads two env vars to pick a (arch, os, obj) triple:
*
@@ -32,7 +32,7 @@ static inline const char* kit_test_obj_name(void) {
return o;
}
-static inline int kit_test_target_init(KitTarget* t) {
+static inline int kit_test_target_init(KitTargetSpec* t) {
memset(t, 0, sizeof *t);
t->ptr_size = 8;
t->ptr_align = 8;
diff --git a/test/lib/kit_unit.h b/test/lib/kit_unit.h
@@ -3,8 +3,8 @@
* The unit suite copy-pasted the same prologue into ~18 files: a
* malloc/realloc/free shim wrapping the host allocator into a KitHeap, a
* diagnostic sink that prints to stderr, an EXPECT/CHECK macro, a
- * KitTarget + KitContext + kit_compiler_new dance, and a pass/fail
- * counter checked in main(). This header folds all of that into one
+ * KitTargetSpec + KitTarget + KitContext + kit_compiler_new dance, and a
+ * pass/fail counter checked in main(). This header folds all of that into one
* stack-resident KitUnit context.
*
* Design constraints honored:
@@ -36,10 +36,16 @@
/* One context per test. Zero-initialize with kit_unit_init. The diag sink
* captures the most recent message body into last_diag (before any
* suppression), which expected-panic tests strstr() against. */
+typedef struct KitUnitTargetNode {
+ KitTarget* target;
+ struct KitUnitTargetNode* next;
+} KitUnitTargetNode;
+
typedef struct KitUnit {
KitHeap heap;
KitDiagSink diag;
KitContext ctx;
+ KitUnitTargetNode* targets;
char last_diag[256];
int suppress_fatal; /* when set, FATAL diagnostics are captured but not
* printed — used by tests that drive a deliberate
@@ -102,9 +108,9 @@ static inline void kit_unit_init(KitUnit* u) {
u->ctx.now = 0;
}
-static inline KitTarget kit_unit_target(KitArchKind arch, KitOSKind os,
- KitObjFmt obj) {
- KitTarget t;
+static inline KitTargetSpec kit_unit_target(KitArchKind arch, KitOSKind os,
+ KitObjFmt obj) {
+ KitTargetSpec t;
memset(&t, 0, sizeof t);
t.arch = arch;
t.os = os;
@@ -114,9 +120,44 @@ static inline KitTarget kit_unit_target(KitArchKind arch, KitOSKind os,
return t;
}
-static inline KitStatus kit_unit_compiler_new(KitUnit* u, KitTarget t,
+static inline KitStatus kit_unit_compiler_new(KitUnit* u, KitTargetSpec t,
KitCompiler** out) {
- return kit_compiler_new(t, &u->ctx, out);
+ KitTargetOptions opts;
+ KitTarget* target = NULL;
+ KitUnitTargetNode* node = NULL;
+ KitStatus st;
+ if (out) *out = NULL;
+ memset(&opts, 0, sizeof opts);
+ opts.spec = t;
+ st = kit_target_new(&u->ctx, &opts, &target);
+ if (st != KIT_OK) return st;
+ node = (KitUnitTargetNode*)kit_unit_alloc(&u->heap, sizeof(*node),
+ _Alignof(KitUnitTargetNode));
+ if (!node) {
+ kit_target_free(target);
+ return KIT_NOMEM;
+ }
+ st = kit_compiler_new(target, &u->ctx, out);
+ if (st != KIT_OK) {
+ kit_unit_free(&u->heap, node, sizeof(*node));
+ kit_target_free(target);
+ return st;
+ }
+ node->target = target;
+ node->next = u->targets;
+ u->targets = node;
+ return KIT_OK;
+}
+
+static inline void kit_unit_fini(KitUnit* u) {
+ KitUnitTargetNode* n = u ? u->targets : NULL;
+ while (n) {
+ KitUnitTargetNode* next = n->next;
+ kit_target_free(n->target);
+ kit_unit_free(&u->heap, n, sizeof(*n));
+ n = next;
+ }
+ if (u) u->targets = NULL;
}
/* Byte-substring search, for tests asserting emitted machine code contains a
@@ -140,7 +181,11 @@ static inline void kit_unit_summary(KitUnit* u, const char* name) {
}
}
-static inline int kit_unit_status(KitUnit* u) { return u->fails ? 1 : 0; }
+static inline int kit_unit_status(KitUnit* u) {
+ int rc = u->fails ? 1 : 0;
+ kit_unit_fini(u);
+ return rc;
+}
/* Record one check. `cond` is evaluated EXACTLY ONCE — it may have side
* effects (e.g. EXPECT(kit_ar_iter_next(it, &m), ...) advances an
diff --git a/test/link/harness/jit_runner.c b/test/link/harness/jit_runner.c
@@ -77,6 +77,11 @@ static void diag_fn(KitDiagSink* s, KitDiagKind k, KitSrcLoc loc,
}
static KitDiagSink g_diag = {diag_fn, NULL, 0, 0};
+static void free_compiler_target(KitCompiler* compiler, KitTarget* target) {
+ kit_compiler_free(compiler);
+ kit_target_free(target);
+}
+
/* Mirrors driver/env.c — see that file for the strict-W^X dual-mapping
* rationale. */
#if defined(__APPLE__)
@@ -489,7 +494,7 @@ int main(int argc, char** argv) {
}
}
- KitTarget target;
+ KitTargetSpec target;
if (kit_test_target_init(&target) != 0) {
fprintf(stderr, "jit_runner: kit_test_target_init failed\n");
return 2;
@@ -501,9 +506,18 @@ int main(int argc, char** argv) {
ctx.diag = &g_diag;
ctx.now = -1;
+ KitTargetOptions target_opts;
+ memset(&target_opts, 0, sizeof target_opts);
+ target_opts.spec = target;
+ KitTarget* kt = NULL;
+ if (kit_target_new(&ctx, &target_opts, &kt) != KIT_OK || !kt) {
+ fprintf(stderr, "jit-runner: target_new failed\n");
+ return 2;
+ }
KitCompiler* c = NULL;
- if (kit_compiler_new(target, &ctx, &c) != KIT_OK || !c) {
+ if (kit_compiler_new(kt, &ctx, &c) != KIT_OK || !c) {
fprintf(stderr, "jit-runner: compiler_new failed\n");
+ kit_target_free(kt);
return 2;
}
@@ -530,7 +544,7 @@ int main(int argc, char** argv) {
size_t slen;
if (slurp(script_path, &sbytes, &slen)) {
fprintf(stderr, "jit-runner: cannot read %s\n", script_path);
- kit_compiler_free(c);
+ free_compiler_target(c, kt);
return 2;
}
KitSlice script_text = {.s = (const char*)sbytes, .len = slen};
@@ -539,7 +553,7 @@ int main(int argc, char** argv) {
if (prc != KIT_OK) {
fprintf(stderr, "jit-runner: linker script parse failed: %s\n",
script_path);
- kit_compiler_free(c);
+ free_compiler_target(c, kt);
return 1;
}
opts.linker_script = script;
@@ -557,7 +571,7 @@ int main(int argc, char** argv) {
kit_link_session_free(link);
if (script) kit_link_script_free(&ctx, script);
for (int i = 0; i < nbufs; i++) free(bufs[i]);
- kit_compiler_free(c);
+ free_compiler_target(c, kt);
return 1;
}
kit_link_session_free(link);
@@ -569,7 +583,7 @@ int main(int argc, char** argv) {
fprintf(stderr, "jit-runner: sentinel lookup unexpectedly non-NULL\n");
kit_jit_run_dtors(jit);
kit_jit_free(jit);
- kit_compiler_free(c);
+ free_compiler_target(c, kt);
return 1;
}
@@ -581,7 +595,7 @@ int main(int argc, char** argv) {
check_absent);
kit_jit_run_dtors(jit);
kit_jit_free(jit);
- kit_compiler_free(c);
+ free_compiler_target(c, kt);
return absent_ok ? 0 : 1;
}
@@ -593,7 +607,7 @@ int main(int argc, char** argv) {
check_present);
kit_jit_run_dtors(jit);
kit_jit_free(jit);
- kit_compiler_free(c);
+ free_compiler_target(c, kt);
return present_ok ? 0 : 1;
}
@@ -650,7 +664,7 @@ int main(int argc, char** argv) {
free(instance);
kit_jit_run_dtors(jit);
kit_jit_free(jit);
- kit_compiler_free(c);
+ free_compiler_target(c, kt);
return 1;
}
for (uint32_t i = 0; i < 8u; ++i)
@@ -678,7 +692,7 @@ int main(int argc, char** argv) {
free(instance);
kit_jit_run_dtors(jit);
kit_jit_free(jit);
- kit_compiler_free(c);
+ free_compiler_target(c, kt);
return 1;
}
((WasmRunnerInitFn)wasm_init)(instance);
@@ -714,6 +728,6 @@ int main(int argc, char** argv) {
}
kit_jit_free(jit);
- kit_compiler_free(c);
+ free_compiler_target(c, kt);
return result;
}
diff --git a/test/link/harness/link_exe_runner.c b/test/link/harness/link_exe_runner.c
@@ -53,6 +53,11 @@ static void diag_fn(KitDiagSink* s, KitDiagKind k, KitSrcLoc loc,
}
static KitDiagSink g_diag = {diag_fn, NULL, 0, 0};
+static void free_compiler_target(KitCompiler* compiler, KitTarget* target) {
+ kit_compiler_free(compiler);
+ kit_target_free(target);
+}
+
static int slurp(const char* path, uint8_t** out, size_t* len) {
int fd = open(path, O_RDONLY);
if (fd < 0) return -1;
@@ -176,7 +181,7 @@ int main(int argc, char** argv) {
return 2;
}
- KitTarget target;
+ KitTargetSpec target;
if (kit_test_target_init(&target) != 0) {
fprintf(stderr, "link_exe_runner: kit_test_target_init failed\n");
return 2;
@@ -188,9 +193,18 @@ int main(int argc, char** argv) {
ctx.diag = &g_diag;
ctx.now = -1;
+ KitTargetOptions target_opts;
+ memset(&target_opts, 0, sizeof target_opts);
+ target_opts.spec = target;
+ KitTarget* kt = NULL;
+ if (kit_target_new(&ctx, &target_opts, &kt) != KIT_OK || !kt) {
+ fprintf(stderr, "link-exe-runner: target_new failed\n");
+ return 2;
+ }
KitCompiler* c = NULL;
- if (kit_compiler_new(target, &ctx, &c) != KIT_OK || !c) {
+ if (kit_compiler_new(kt, &ctx, &c) != KIT_OK || !c) {
fprintf(stderr, "link-exe-runner: compiler_new failed\n");
+ kit_target_free(kt);
return 2;
}
@@ -207,7 +221,7 @@ int main(int argc, char** argv) {
size_t slen;
if (slurp(script_path, &sbytes, &slen)) {
fprintf(stderr, "link-exe-runner: cannot read %s\n", script_path);
- kit_compiler_free(c);
+ free_compiler_target(c, kt);
return 2;
}
KitSlice script_text = {.s = (const char*)sbytes, .len = slen};
@@ -216,7 +230,7 @@ int main(int argc, char** argv) {
if (prc != KIT_OK) {
fprintf(stderr, "link-exe-runner: linker script parse failed: %s\n",
script_path);
- kit_compiler_free(c);
+ free_compiler_target(c, kt);
return 1;
}
opts.linker_script = script;
@@ -224,7 +238,7 @@ int main(int argc, char** argv) {
KitWriter* w = NULL;
if (kit_writer_mem(&g_heap, &w) != KIT_OK || !w) {
- kit_compiler_free(c);
+ free_compiler_target(c, kt);
return 2;
}
@@ -244,7 +258,7 @@ int main(int argc, char** argv) {
if (script) kit_link_script_free(&ctx, script);
for (int i = 0; i < nbufs; i++) free(bufs[i]);
kit_writer_close(w);
- kit_compiler_free(c);
+ free_compiler_target(c, kt);
return 1;
}
for (int i = 0; i < nbufs; i++) free(bufs[i]);
@@ -255,7 +269,7 @@ int main(int argc, char** argv) {
kit_link_session_free(link);
if (script) kit_link_script_free(&ctx, script);
kit_writer_close(w);
- kit_compiler_free(c);
+ free_compiler_target(c, kt);
if (wrc) {
fprintf(stderr, "link-exe-runner: write failed\n");
return 2;
diff --git a/test/link/rv64_jit_test.c b/test/link/rv64_jit_test.c
@@ -24,7 +24,7 @@
* the host CPU can't decode them. The test prints "SKIP <reason>" and
* exits 77 (the GNU autotools "skipped" convention) when this happens.
*
- * Wired into test.mk via test-rv64-jit. Always builds; calls only on
+ * Wired into mk/test.mk via test-rv64-jit. Always builds; calls only on
* rv64 Linux. This mirrors the value-proposition outlined in
* doc/RV64_PARITY_CHECKLIST.md: have the code path in place for the day
* someone runs kit on a rv64 dev box. */
@@ -190,7 +190,8 @@ int main(void) {
if (ps > 0) g_execmem.page_size = (size_t)ps;
}
- KitTarget target = kit_unit_target(KIT_ARCH_RV64, KIT_OS_LINUX, KIT_OBJ_ELF);
+ KitTargetSpec target =
+ kit_unit_target(KIT_ARCH_RV64, KIT_OS_LINUX, KIT_OBJ_ELF);
kit_unit_init(&g_u);
g_u.ctx.now = -1;
diff --git a/test/macho/kit-roundtrip-macho.c b/test/macho/kit-roundtrip-macho.c
@@ -113,7 +113,7 @@ int main(int argc, char** argv) {
return 1;
}
- KitTarget target;
+ KitTargetSpec target;
if (kit_detect_target(in_data, in_len, &target) != KIT_OK ||
target.obj != KIT_OBJ_MACHO) {
fprintf(stderr, "error: %s: not a recognized Mach-O object file\n",
diff --git a/test/opt/cg_ir_lower_test.c b/test/opt/cg_ir_lower_test.c
@@ -26,7 +26,7 @@ typedef struct TestCtx {
} TestCtx;
static void tc_init(TestCtx* tc) {
- KitTarget target;
+ KitTargetSpec target;
KitCgBuiltinTypes b;
memset(tc, 0, sizeof *tc);
target = kit_unit_target(KIT_ARCH_ARM_64, KIT_OS_MACOS, KIT_OBJ_MACHO);
diff --git a/test/opt/tiny_inline_test.c b/test/opt/tiny_inline_test.c
@@ -38,7 +38,7 @@ typedef struct TestCtx {
} TestCtx;
static void tc_init(TestCtx* tc) {
- KitTarget target;
+ KitTargetSpec target;
KitCgBuiltinTypes b;
KitCgFuncSig sig;
KitCgFuncParam params[1];
diff --git a/test/parse/harness/parse_runner.c b/test/parse/harness/parse_runner.c
@@ -241,7 +241,7 @@ static KitExecMem g_execmem = {
/* ---- helpers ---- */
-static void target_from_env(KitTarget* t) {
+static void target_from_env(KitTargetSpec* t) {
if (kit_test_target_init(t) != 0) {
fprintf(stderr, "parse-runner: kit_test_target_init failed\n");
exit(2);
@@ -310,6 +310,25 @@ static void ctx_init(KitContext* ctx) {
ctx->now = -1;
}
+static KitStatus compiler_new_for_target(KitTargetSpec spec, KitContext* ctx,
+ KitTarget** target_out,
+ KitCompiler** compiler_out) {
+ KitTargetOptions opts;
+ KitStatus st;
+ if (target_out) *target_out = NULL;
+ if (compiler_out) *compiler_out = NULL;
+ memset(&opts, 0, sizeof opts);
+ opts.spec = spec;
+ st = kit_target_new(ctx, &opts, target_out);
+ if (st != KIT_OK) return st;
+ st = kit_compiler_new(*target_out, ctx, compiler_out);
+ if (st != KIT_OK) {
+ kit_target_free(*target_out);
+ *target_out = NULL;
+ }
+ return st;
+}
+
static int opt_level_from_env(void) {
const char* s = getenv("KIT_OPT_LEVEL");
if (!s || !*s) return 0;
@@ -385,8 +404,9 @@ static int mode_emit_impl(const char* src_path, const char* out_path,
int emit_c) {
uint8_t* src = NULL;
size_t src_len = 0;
- KitTarget tgt;
+ KitTargetSpec tgt;
KitContext ctx;
+ KitTarget* target = NULL;
KitCompiler* c = NULL;
KitSlice in;
KitCCompileOptions opts;
@@ -403,7 +423,7 @@ static int mode_emit_impl(const char* src_path, const char* out_path,
}
target_from_env(&tgt);
ctx_init(&ctx);
- if (kit_compiler_new(tgt, &ctx, &c) != KIT_OK || !c) {
+ if (compiler_new_for_target(tgt, &ctx, &target, &c) != KIT_OK || !c) {
free(src);
return 2;
}
@@ -427,6 +447,7 @@ static int mode_emit_impl(const char* src_path, const char* out_path,
KIT_OK) {
kit_writer_close(w);
kit_compiler_free(c);
+ kit_target_free(target);
free(src);
return 1;
}
@@ -451,6 +472,7 @@ static int mode_emit_impl(const char* src_path, const char* out_path,
}
kit_writer_close(w);
kit_compiler_free(c);
+ kit_target_free(target);
free(src);
return rc;
}
@@ -478,8 +500,9 @@ call_with_aarch64_tls(int (*fn)(void), void* tls_block) {
static int mode_jit(const char* src_path) {
uint8_t* src = NULL;
size_t src_len = 0;
- KitTarget tgt;
+ KitTargetSpec tgt;
KitContext ctx;
+ KitTarget* target = NULL;
KitCompiler* c = NULL;
KitSlice in;
KitCCompileOptions opts;
@@ -500,7 +523,7 @@ static int mode_jit(const char* src_path) {
}
target_from_env(&tgt);
ctx_init(&ctx);
- if (kit_compiler_new(tgt, &ctx, &c) != KIT_OK || !c) {
+ if (compiler_new_for_target(tgt, &ctx, &target, &c) != KIT_OK || !c) {
free(src);
return 2;
}
@@ -516,6 +539,7 @@ static int mode_jit(const char* src_path) {
KIT_OK ||
!ob) {
kit_compiler_free(c);
+ kit_target_free(target);
free(src);
return 1;
}
@@ -530,6 +554,7 @@ static int mode_jit(const char* src_path) {
if (!add_runtime_archive(&rt_archive, &rt_data)) {
kit_compiler_free(c);
+ kit_target_free(target);
free(src);
return 1;
}
@@ -539,6 +564,7 @@ static int mode_jit(const char* src_path) {
kit_link_session_jit(link, &jit) != KIT_OK || !jit) {
kit_link_session_free(link);
kit_compiler_free(c);
+ kit_target_free(target);
free(rt_data);
free(src);
return 1;
@@ -574,6 +600,7 @@ static int mode_jit(const char* src_path) {
kit_jit_free(jit);
kit_compiler_free(c);
+ kit_target_free(target);
free(rt_data);
free(src);
return result;
diff --git a/test/parse/run.sh b/test/parse/run.sh
@@ -57,6 +57,8 @@
# default run in parallel with a capped CPU-count default.
# KIT_TEST_JOBS=N run up to N cases concurrently.
# KIT_PARSE_PARALLEL=0 force serial dispatch.
+# KIT_CORPUS_TRACE=1 force serial dispatch and print each item/lane before
+# running it.
# All lane hooks write only under KIT_WORK and record via kit_*, so the runner is
# parallel-safe by construction.
diff --git a/test/wasm/harness/wasm_tool.c b/test/wasm/harness/wasm_tool.c
@@ -98,7 +98,7 @@ int main(int argc, char** argv) {
return 2;
}
- KitTarget target;
+ KitTargetSpec target;
if (kit_test_target_init(&target) != 0) {
free(src);
return 2;
@@ -109,7 +109,16 @@ int main(int argc, char** argv) {
ctx.diag = &g_diag;
ctx.now = -1;
KitCompiler* c = NULL;
- if (kit_compiler_new(target, &ctx, &c) != KIT_OK || !c) {
+ KitTargetOptions target_opts;
+ KitTarget* kt = NULL;
+ memset(&target_opts, 0, sizeof target_opts);
+ target_opts.spec = target;
+ if (kit_target_new(&ctx, &target_opts, &kt) != KIT_OK || !kt) {
+ free(src);
+ return 2;
+ }
+ if (kit_compiler_new(kt, &ctx, &c) != KIT_OK || !c) {
+ kit_target_free(kt);
free(src);
return 2;
}
@@ -117,6 +126,7 @@ int main(int argc, char** argv) {
KitWriter* w = NULL;
if (kit_writer_mem(&g_heap, &w) != KIT_OK || !w) {
kit_compiler_free(c);
+ kit_target_free(kt);
free(src);
return 2;
}
@@ -130,6 +140,7 @@ int main(int argc, char** argv) {
if (!rc) rc = write_file(argv[3], out, out_len);
kit_writer_close(w);
kit_compiler_free(c);
+ kit_target_free(kt);
free(src);
return rc ? 1 : 0;
}