From e5e3724046655286bf04d21b6dbdd58f33375ad9 Mon Sep 17 00:00:00 2001 From: Thomas Voss Date: Sun, 23 Jun 2024 18:17:56 +0200 Subject: Implement a temporary allocator --- src/alloc.h | 14 ++++++++++++++ src/codegen.c | 18 +++++++----------- src/scratch.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 11 deletions(-) create mode 100644 src/scratch.c (limited to 'src') diff --git a/src/alloc.h b/src/alloc.h index 2c67fb7..79d7c0b 100644 --- a/src/alloc.h +++ b/src/alloc.h @@ -7,12 +7,26 @@ #include "common.h" typedef struct _arena *arena_t; +typedef struct { + void *p; + size_t sz; +} scratch_t; /* Allocate a buffer of NMEMB elements of size SIZE. If PTR is non-null then reallocate the buffer it points to. Aborts on out-of-memory or overflow. */ void *bufalloc(void *ptr, size_t nmemb, size_t size) __attribute__((returns_nonnull, warn_unused_result, alloc_size(2, 3))); +/* Alloc a buffer of NMEMB elements of size SIZE for one time use. Each + time this function is invoked previous allocations are overwritten. */ +void *tmpalloc(scratch_t *s, size_t nmemb, size_t size) + __attribute__((returns_nonnull, warn_unused_result, nonnull, + alloc_size(2, 3))); + +/* Reallocate all memory associated with S */ +void tmpfree(scratch_t *s) + __attribute__((nonnull)); + /* Allocate a buffer of NMEMB elements of size SIZE with alignment ALIGN using the arena-allocator A. */ void *arena_alloc(arena_t *a, size_t nmemb, size_t size, size_t align) diff --git a/src/codegen.c b/src/codegen.c index 08f5ab5..1431693 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -21,6 +21,7 @@ have easy access to everything */ struct cgctx { arena_t a; + scratch_t *s; LLVMContextRef ctx; LLVMModuleRef mod; LLVMBuilderRef bob; @@ -43,6 +44,7 @@ codegen(const char *file, mpq_t *folds, scope_t *scps, type_t *types, struct cgctx ctx; ctx.a = NULL; + ctx.s = &(scratch_t){0}; ctx.namespace.p = NULL; ctx.ctx = LLVMContextCreate(); ctx.mod = LLVMModuleCreateWithNameInContext("oryx", ctx.ctx); @@ -54,6 +56,7 @@ codegen(const char *file, mpq_t *folds, scope_t *scps, type_t *types, codegenast(ctx, folds, types, ast, aux, toks); arena_free(&ctx.a); + tmpfree(ctx.s); LLVMDisposeBuilder(ctx.bob); @@ -188,12 +191,9 @@ codegendecl(struct cgctx ctx, mpq_t *folds, type_t *types, ast_t ast, aux_t aux, strview_t sv = toks.strs[ast.lexemes[i]]; /* TODO: Namespace the name */ - /* TODO: Temporary allocator */ - char *name = bufalloc(NULL, sv.len + 1, 1); + char *name = tmpalloc(ctx.s, sv.len + 1, 1); svtocstr(name, sv); - i = codegenfunc(ctx, folds, types, ast, aux, toks, p.rhs, name); - free(name); - return i; + return codegenfunc(ctx, folds, types, ast, aux, toks, p.rhs, name); } assert(ast.kinds[i] == ASTDECL); @@ -201,11 +201,9 @@ codegendecl(struct cgctx ctx, mpq_t *folds, type_t *types, ast_t ast, aux_t aux, if (!types[i].isfloat && aux.buf[p.lhs].decl.isstatic) { strview_t sv = toks.strs[ast.lexemes[i]]; /* TODO: Namespace the name */ - /* TODO: Temporary allocator */ - char *name = bufalloc(NULL, sv.len + 1, 1); + char *name = tmpalloc(ctx.s, sv.len + 1, 1); LLVMTypeRef t = type2llvm(ctx, types[i]); LLVMValueRef globl = LLVMAddGlobal(ctx.mod, t, svtocstr(name, sv)); - free(name); LLVMValueRef v; i = codegentypedexpr(ctx, folds, types, ast, aux, toks, p.rhs, types[i], &v); @@ -216,12 +214,10 @@ codegendecl(struct cgctx ctx, mpq_t *folds, type_t *types, ast_t ast, aux_t aux, if (!types[i].isfloat /* && !aux.buf[p.lhs].decl.isstatic */) { strview_t sv = toks.strs[ast.lexemes[i]]; /* TODO: Namespace the name */ - /* TODO: Temporary allocator */ - char *name = bufalloc(NULL, sv.len + 1, 1); + char *name = tmpalloc(ctx.s, sv.len + 1, 1); LLVMTypeRef t = type2llvm(ctx, types[i]); LLVMValueRef var, val; var = LLVMBuildAlloca(ctx.bob, t, svtocstr(name, sv)); - free(name); i = codegentypedexpr(ctx, folds, types, ast, aux, toks, p.rhs, types[i], &val); LLVMBuildStore(ctx.bob, val, var); return i; diff --git a/src/scratch.c b/src/scratch.c new file mode 100644 index 0000000..ae48ff6 --- /dev/null +++ b/src/scratch.c @@ -0,0 +1,59 @@ +#include + +#include +#include + +#include "alloc.h" +#include "common.h" +#include "errors.h" + +/* TODO: Support malloc() backend for systems without MAP_ANON */ +#ifndef MAP_ANON +# error "System not supported (missing MAP_ANON)" +#endif + +#if DEBUG +# define TMP_DFLT_BUFSZ (8) +#else /* Probably super overkill, but that’s fine */ +# define TMP_DFLT_BUFSZ (1 * 1024) +#endif + +#define MAX(x, y) ((x) > (y) ? (x) : (y)) + +void * +tmpalloc(scratch_t *s, size_t nmemb, size_t size) +{ + if (unlikely(size > SIZE_MAX / nmemb)) { + errno = ENOMEM; + err("%s:", __func__); + } + size *= nmemb; + + if (s->p == NULL) { +#if !__linux__ +do_mmap: +#endif + s->sz = MAX(size, TMP_DFLT_BUFSZ); + s->p = mmap(s->p, s->sz, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + if (s->p == MAP_FAILED) + err("mmap:"); + } else if (size > s->sz) { +#if __linux__ + if ((s->p = mremap(s->p, s->sz, size, MREMAP_MAYMOVE)) == MAP_FAILED) + err("mremap:"); + s->sz = size; +#else + munmap(s->p, s->sz); + goto do_mmap; +#endif + } + + return s->p; +} + +void +tmpfree(scratch_t *s) +{ + munmap(s->p, s->sz); +} -- cgit v1.2.3