Skip to content

Commit de292cd

Browse files
committed
Write JIT pack file using same method as native code gen
Fixes #1159
1 parent 63ca234 commit de292cd

File tree

7 files changed

+108
-97
lines changed

7 files changed

+108
-97
lines changed

NEWS.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
of a conversion function (#1171).
3333
- Type marks are now allowed in the prefix of selected names in relaxed
3434
mode (#1173).
35-
- Several other minor bugs were resolved (#1174).
35+
- Several other minor bugs were resolved (#1174, #1159).
3636

3737
## Version 1.15.2 - 2025-03-01
3838
- Fixed invalid LLVM IR generation which could cause a crash with LLVM

src/Makemodule.am

+2-5
Original file line numberDiff line numberDiff line change
@@ -54,16 +54,13 @@ lib_libnvc_a_SOURCES = \
5454
src/driver.h \
5555
src/driver.c \
5656
src/inst.h \
57-
src/inst.c
57+
src/inst.c \
58+
src/cgen.c
5859

5960
if ENABLE_SERVER
6061
lib_libnvc_a_SOURCES += src/server.c src/server.h
6162
endif
6263

63-
if ENABLE_LLVM
64-
lib_libnvc_a_SOURCES += src/cgen.c
65-
endif
66-
6764
bin_nvc_SOURCES = src/nvc.c
6865

6966
EXTRA_bin_nvc_DEPENDENCIES = src/symbols.txt

src/cgen.c

+56-20
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,10 @@ typedef struct {
5656
unit_registry_t *registry;
5757
} discover_args_t;
5858

59+
#ifdef ENABLE_LLVM
5960
static A(char *) link_args;
6061
static A(char *) cleanup_files = AINIT;
62+
#endif
6163

6264
#define UNITS_PER_JOB 25
6365

@@ -163,6 +165,7 @@ static void cgen_walk_hier(unit_list_t *units, hset_t *seen, tree_t block,
163165
}
164166
}
165167

168+
#ifdef ENABLE_LLVM
166169
static void cleanup_temp_dll(void)
167170
{
168171
for (int i = 0; i < cleanup_files.count; i++) {
@@ -305,7 +308,7 @@ static void cgen_async_work(void *context, void *arg)
305308

306309
static void cgen_partition_jobs(unit_list_t *units, workq_t *wq,
307310
const char *base_name, int units_per_job,
308-
tree_t top, obj_list_t *objs)
311+
obj_list_t *objs)
309312
{
310313
int counter = 0;
311314

@@ -337,7 +340,44 @@ static void cgen_partition_jobs(unit_list_t *units, workq_t *wq,
337340
}
338341
}
339342

340-
void cgen(tree_t top, unit_registry_t *ur, mir_context_t *mc, jit_t *jit)
343+
static void cgen_native(ident_t name, jit_t *jit, unit_list_t *units)
344+
{
345+
workq_t *wq = workq_new(jit);
346+
347+
obj_list_t objs = AINIT;
348+
cgen_partition_jobs(units, wq, istr(name), UNITS_PER_JOB, &objs);
349+
350+
workq_start(wq);
351+
workq_drain(wq);
352+
353+
progress("code generation for %d units", units->count);
354+
355+
cgen_link(istr(name), objs.items, objs.count);
356+
357+
for (unsigned i = 0; i < objs.count; i++)
358+
free(objs.items[i]);
359+
ACLEAR(objs);
360+
361+
workq_free(wq);
362+
}
363+
#endif // ENABLE_LLVM
364+
365+
static void cgen_jit_pack(ident_t name, jit_t *jit, unit_list_t *units)
366+
{
367+
const char *fname LOCAL = xasprintf("_%s.pack", istr(name));
368+
369+
FILE *f = lib_fopen(lib_work(), fname, "wb");
370+
if (f == NULL)
371+
fatal_errno("fopen: %s", fname);
372+
373+
jit_write_pack(jit, units->items, units->count, f);
374+
fclose(f);
375+
376+
progress("writing JIT pack");
377+
}
378+
379+
void cgen(tree_t top, unit_registry_t *ur, mir_context_t *mc, jit_t *jit,
380+
cgen_mode_t mode)
341381
{
342382
assert(tree_kind(top) == T_ELAB);
343383

@@ -359,28 +399,23 @@ void cgen(tree_t top, unit_registry_t *ur, mir_context_t *mc, jit_t *jit)
359399
hset_free(seen);
360400
seen = NULL;
361401

362-
workq_t *wq = workq_new(jit);
363-
364-
ident_t name = tree_ident(top);
365-
366-
obj_list_t objs = AINIT;
367-
cgen_partition_jobs(&units, wq, istr(name), UNITS_PER_JOB, top, &objs);
368-
369-
workq_start(wq);
370-
workq_drain(wq);
371-
372-
progress("code generation for %d units", units.count);
373-
374-
cgen_link(istr(name), objs.items, objs.count);
375-
376-
for (unsigned i = 0; i < objs.count; i++)
377-
free(objs.items[i]);
378-
ACLEAR(objs);
402+
switch (mode) {
403+
case CGEN_NATIVE:
404+
#ifdef ENABLE_LLVM
405+
cgen_native(tree_ident(top), jit, &units);
406+
#else
407+
fatal("native code generation not enabled in this build");
408+
#endif
409+
break;
410+
case CGEN_JIT_PACK:
411+
cgen_jit_pack(tree_ident(top), jit, &units);
412+
break;
413+
}
379414

380415
ACLEAR(units);
381-
workq_free(wq);
382416
}
383417

418+
#ifdef ENABLE_LLVM
384419
static void preload_walk_index(lib_t lib, ident_t ident, int kind, void *ctx)
385420
{
386421
discover_args_t *args = ctx;
@@ -578,3 +613,4 @@ void aotgen(const char *outfile, char **argv, int argc)
578613
unit_registry_free(ur);
579614
mir_context_free(mc);
580615
}
616+
#endif // ENABLE_LLVM

src/jit/jit-pack.c

+22-31
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
#include "jit/jit-priv.h"
2424
#include "lib.h"
2525
#include "object.h"
26-
#include "vcode.h"
2726

2827
#include <assert.h>
2928
#include <stdlib.h>
@@ -618,47 +617,39 @@ static void write_fully(const void *buf, size_t size, FILE *f)
618617
fatal_errno("fwrite");
619618
}
620619

621-
static void write_children(jit_t *j, vcode_unit_t vu, pack_writer_t *pw,
622-
FILE *file)
620+
void jit_write_pack(jit_t *j, const ident_t *units, size_t count, FILE *f)
623621
{
624-
ident_t ident = vcode_unit_name(vu);
625-
jit_handle_t handle = jit_compile(j, ident);
622+
pack_writer_t *pw = pack_writer_new();
626623

627-
uint8_t bytes[10];
624+
pack_header_t header = {};
625+
write_fully(&header, sizeof(header), f);
628626

629-
const uint32_t name = pack_writer_get_string(pw, istr(ident));
630-
const int name_nbytes = encode_number(name, bytes);
631-
write_fully(bytes, name_nbytes, file);
627+
for (size_t i = 0; i < count; i++) {
628+
jit_handle_t handle = jit_compile(j, units[i]);
632629

633-
uint8_t *buf;
634-
size_t size;
635-
pack_writer_emit(pw, j, handle, &buf, &size);
630+
uint8_t bytes[10];
636631

637-
const int size_nbytes = encode_number(size, bytes);
638-
write_fully(bytes, size_nbytes, file);
632+
const uint32_t name = pack_writer_get_string(pw, istr(units[i]));
633+
const int name_nbytes = encode_number(name, bytes);
634+
write_fully(bytes, name_nbytes, f);
639635

640-
jit_func_t *f = jit_get_func(j, handle);
636+
uint8_t *buf;
637+
size_t size;
638+
pack_writer_emit(pw, j, handle, &buf, &size);
641639

642-
const int cpool_nbytes = encode_number(f->cpoolsz, bytes);
643-
write_fully(bytes, cpool_nbytes, file);
640+
const int size_nbytes = encode_number(size, bytes);
641+
write_fully(bytes, size_nbytes, f);
644642

645-
write_fully(buf, size, file);
643+
jit_func_t *func = jit_get_func(j, handle);
646644

647-
if (f->cpoolsz > 0)
648-
write_fully(f->cpool, f->cpoolsz, file);
645+
const int cpool_nbytes = encode_number(func->cpoolsz, bytes);
646+
write_fully(bytes, cpool_nbytes, f);
649647

650-
for (vcode_unit_t it = vcode_unit_child(vu); it; it = vcode_unit_next(it))
651-
write_children(j, it, pw, file);
652-
}
648+
write_fully(buf, size, f);
653649

654-
void jit_write_pack(jit_t *j, vcode_unit_t root, FILE *f)
655-
{
656-
pack_writer_t *pw = pack_writer_new();
657-
658-
pack_header_t header = {};
659-
write_fully(&header, sizeof(header), f);
660-
661-
write_children(j, root, pw, f);
650+
if (func->cpoolsz > 0)
651+
write_fully(func->cpool, func->cpoolsz, f);
652+
}
662653

663654
memcpy(header.magic, PACK_MAGIC, sizeof(header.magic));
664655
header.strtab = ftell(f);

src/jit/jit.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ tlab_t jit_null_tlab(jit_t *j);
9696
jit_pack_t *jit_pack_new(void);
9797
void jit_pack_free(jit_pack_t *jp);
9898

99-
void jit_write_pack(jit_t *j, vcode_unit_t root, FILE *f);
99+
void jit_write_pack(jit_t *j, const ident_t *units, size_t count, FILE *f);
100100
jit_pack_t *jit_read_pack(FILE *f);
101101

102102
__attribute__((format(printf, 3, 4)))

src/nvc.c

+19-38
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,16 @@ static int parse_optimise_level(const char *str)
393393
return level;
394394
}
395395

396+
static void load_jit_pack(jit_t *jit, tree_t top)
397+
{
398+
char *name LOCAL = xasprintf("_%s.pack", istr(tree_ident(top)));
399+
FILE *f = lib_fopen(lib_work(), name, "rb");
400+
if (f != NULL) {
401+
jit_load_pack(jit, f);
402+
fclose(f);
403+
}
404+
}
405+
396406
static int elaborate(int argc, char **argv, cmd_state_t *state)
397407
{
398408
static struct option long_options[] = {
@@ -556,8 +566,9 @@ static int elaborate(int argc, char **argv, cmd_state_t *state)
556566
if (error_count() > 0)
557567
return EXIT_FAILURE;
558568

559-
char *pack_name LOCAL = xasprintf("_%s.pack", istr(state->top_level));
560-
char *dll_name LOCAL = xasprintf("_%s." DLL_EXT, istr(tree_ident(top)));
569+
const char *elab_name = istr(tree_ident(top));
570+
char *pack_name LOCAL = xasprintf("_%s.pack", elab_name);
571+
char *dll_name LOCAL = xasprintf("_%s." DLL_EXT, elab_name);
561572

562573
// Delete any existing generated code to avoid accidentally loading
563574
// the wrong version later
@@ -569,25 +580,10 @@ static int elaborate(int argc, char **argv, cmd_state_t *state)
569580
progress("saving library");
570581
}
571582

572-
if (use_jit && !no_save) {
573-
FILE *f = lib_fopen(state->work, pack_name, "wb");
574-
if (f == NULL)
575-
fatal_errno("fopen: %s", pack_name);
576-
577-
ident_t b0 = tree_ident(tree_stmt(top, 0));
578-
ident_t root = ident_prefix(lib_name(state->work), b0, '.');
579-
580-
vcode_unit_t vu = unit_registry_get(state->registry, root);
581-
assert(vu != NULL);
582-
583-
jit_write_pack(state->jit, vu, f);
584-
fclose(f);
585-
586-
progress("writing JIT pack");
587-
}
588-
589583
if (!use_jit)
590-
LLVM_ONLY(cgen(top, state->registry, state->mir, state->jit));
584+
cgen(top, state->registry, state->mir, state->jit, CGEN_NATIVE);
585+
else if (!no_save)
586+
cgen(top, state->registry, state->mir, state->jit, CGEN_JIT_PACK);
591587

592588
if (!use_jit || cover != NULL) {
593589
// Must discard current JIT state to load AOT library later
@@ -949,12 +945,7 @@ static int run_cmd(int argc, char **argv, cmd_state_t *state)
949945
jit_load_dll(state->jit, tree_ident(top));
950946
#endif
951947

952-
char *name LOCAL = xasprintf("_%s.pack", istr(state->top_level));
953-
FILE *f = lib_fopen(state->work, name, "rb");
954-
if (f != NULL) {
955-
jit_load_pack(state->jit, f);
956-
fclose(f);
957-
}
948+
load_jit_pack(state->jit, top);
958949

959950
if (state->cover == NULL)
960951
state->cover = load_coverage(meta, state->jit);
@@ -1483,12 +1474,7 @@ static int do_cmd(int argc, char **argv, cmd_state_t *state)
14831474
jit_load_dll(state->jit, tree_ident(top));
14841475
#endif
14851476

1486-
char *name LOCAL = xasprintf("_%s.pack", istr(state->top_level));
1487-
FILE *f = lib_fopen(state->work, name, "rb");
1488-
if (f != NULL) {
1489-
jit_load_pack(state->jit, f);
1490-
fclose(f);
1491-
}
1477+
load_jit_pack(state->jit, top);
14921478

14931479
shell_reset(sh, top);
14941480
}
@@ -1566,12 +1552,7 @@ static int interact_cmd(int argc, char **argv, cmd_state_t *state)
15661552
jit_load_dll(state->jit, tree_ident(top));
15671553
#endif
15681554

1569-
char *name LOCAL = xasprintf("_%s.pack", istr(state->top_level));
1570-
FILE *f = lib_fopen(state->work, name, "rb");
1571-
if (f != NULL) {
1572-
jit_load_pack(state->jit, f);
1573-
fclose(f);
1574-
}
1555+
load_jit_pack(state->jit, top);
15751556

15761557
shell_reset(sh, top);
15771558
}

src/phase.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,14 @@ tree_t elab(object_t *top, jit_t *jit, unit_registry_t *ur, mir_context_t *mc,
4444
// Set the value of a top-level generic
4545
void elab_set_generic(const char *name, const char *value);
4646

47+
typedef enum {
48+
CGEN_NATIVE,
49+
CGEN_JIT_PACK,
50+
} cgen_mode_t;
51+
4752
// Generate LLVM bitcode for a design unit
48-
void cgen(tree_t top, unit_registry_t *ur, mir_context_t *mc, jit_t *jit);
53+
void cgen(tree_t top, unit_registry_t *ur, mir_context_t *mc, jit_t *jit,
54+
cgen_mode_t mode);
4955

5056
// Generate ahead-of-time preload library
5157
void aotgen(const char *outfile, char **argv, int argc);

0 commit comments

Comments
 (0)