Skip to content

Commit

Permalink
Merge branch 'develop' into eternal_empty_collections
Browse files Browse the repository at this point in the history
  • Loading branch information
dwightguth authored Dec 2, 2024
2 parents 3bf1484 + 1d701f5 commit 51d8878
Show file tree
Hide file tree
Showing 19 changed files with 370 additions and 287 deletions.
10 changes: 5 additions & 5 deletions config/llvm_header.inc
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ declare void @print_configuration(ptr, ptr)
declare i64 @__gmpz_get_ui(ptr)
@exit_int_0 = global %mpz { i32 0, i32 0, ptr getelementptr inbounds ([0 x i64], ptr @exit_int_0_limbs, i32 0, i32 0) }
@exit_int_0_limbs = global [0 x i64] zeroinitializer
@exit_int_0 = constant %mpz { i32 0, i32 0, ptr getelementptr inbounds ([0 x i64], ptr @exit_int_0_limbs, i32 0, i32 0) }
@exit_int_0_limbs = constant [0 x i64] zeroinitializer
define tailcc ptr @"eval_LblgetExitCode{SortGeneratedTopCell{}}"(ptr) {
ret ptr @exit_int_0
Expand All @@ -110,8 +110,8 @@ declare ptr @hook_INT_add(ptr, ptr)
declare ptr @evaluate_function_symbol(i32, ptr)
declare ptr @get_terminated_string(ptr)
@fresh_int_1 = global %mpz { i32 1, i32 1, ptr getelementptr inbounds ([1 x i64], ptr @fresh_int_1_limbs, i32 0, i32 0) }
@fresh_int_1_limbs = global [1 x i64] [i64 1]
@fresh_int_1 = constant %mpz { i32 1, i32 1, ptr getelementptr inbounds ([1 x i64], ptr @fresh_int_1_limbs, i32 0, i32 0) }
@fresh_int_1_limbs = constant [1 x i64] [i64 1]
define ptr @get_fresh_constant(ptr %sort, ptr %top) {
entry:
Expand Down Expand Up @@ -202,7 +202,7 @@ declare void @write_configuration_to_proof_trace(ptr, ptr, i1)
@current_interval = thread_local global i64 0
@GC_THRESHOLD = thread_local global i64 @GC_THRESHOLD@
@gc_roots = global [256 x ptr] zeroinitializer
@gc_roots = thread_local global [256 x ptr] zeroinitializer
define i64 @get_gc_threshold() {
%threshold = load i64, ptr @GC_THRESHOLD
Expand Down
201 changes: 103 additions & 98 deletions include/runtime/arena.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,121 +10,126 @@ extern "C" {

// An arena can be used to allocate objects that can then be deallocated all at
// once.
struct arena {
char *first_block;
char *block;
char *block_start;
char *block_end;
char *first_collection_block;
size_t num_blocks;
size_t num_collection_blocks;
char allocation_semispace_id;
};

using memory_block_header = struct {
char *next_block;
char *next_superblock;
char semispace;
class arena {
public:
arena(char id)
: allocation_semispace_id(id) { }

// Allocates the requested number of bytes as a contiguous region and returns a
// pointer to the first allocated byte.
// If called with requested size greater than the maximun single allocation
// size, the space is allocated in a general (not garbage collected pool).
void *kore_arena_alloc(size_t requested);

// Returns the address of the first byte that belongs in the given arena.
// Returns 0 if nothing has been allocated ever in that arena.
char *arena_start_ptr() const;

// Returns a pointer to a location holding the address of last allocated
// byte in the given arena plus 1.
// This address is 0 if nothing has been allocated ever in that arena.
char **arena_end_ptr();

// return the total number of allocatable bytes currently in the arena in its
// active semispace.
size_t arena_size() const;

// Clears the current allocation space by setting its start back to its first
// block. It is used during garbage collection to effectively collect all of the
// arena.
void arena_clear();

// Resizes the last allocation as long as the resize does not require a new
// block allocation.
// Returns the address of the byte following the last newlly allocated byte when
// the resize succeeds, returns 0 otherwise.
void *arena_resize_last_alloc(ssize_t increase);

// Returns the given arena's current collection semispace ID.
// Each arena has 2 semispace IDs one equal to the arena ID and the other equal
// to the 1's complement of the arena ID. At any time one of these semispaces
// is used for allocation and the other is used for collection.
char get_arena_collection_semispace_id() const;

// Exchanges the current allocation and collection semispaces and clears the new
// current allocation semispace by setting its start back to its first block.
// It is used before garbage collection.
void arena_swap_and_clear();

// Given two pointers to objects allocated in the same arena, return the number
// of bytes they are separated by within the virtual block of memory represented
// by the blocks of that arena. This difference will include blocks containing
// sentinel bytes. Undefined behavior will result if the pointers belong to
// different arenas.
static ssize_t ptr_diff(char *ptr1, char *ptr2);

// Given a starting pointer to an address allocated in an arena and a size in
// bytes, this function returns a pointer to an address allocated in the
// same arena after size bytes from the starting pointer.
//
// 1st argument: the starting pointer
// 2nd argument: the size in bytes to add to the starting pointer
// 3rd argument: the address of last allocated byte in the arena plus 1
// Return value: the address allocated in the arena after size bytes from the
// starting pointer, or 0 if this is equal to the 3rd argument.
static char *move_ptr(char *ptr, size_t size, char const *arena_end_ptr);

// Returns the ID of the semispace where the given address was allocated.
// The behavior is undefined if called with an address that has not been
// allocated within an arena.
static char get_arena_semispace_id_of_object(void *ptr);

private:
struct memory_block_header {
char *next_block;
char semispace;
};

void fresh_block();
static memory_block_header *mem_block_header(void *ptr);

// helper function for `kore_arena_alloc`. Do not call directly.
void *do_alloc_slow(size_t requested);

char *first_block; // beginning of first block
char *block; // where allocations are being made in current block
char *block_start; // start of current block
char *block_end; // 1 past end of current block
char *first_collection_block; // beginning of other semispace
size_t num_blocks; // number of blocks in current semispace
size_t num_collection_blocks; // number of blocks in other semispace
char allocation_semispace_id; // id of current semispace
};

// Macro to define a new arena with the given ID. Supports IDs ranging from 0 to
// 127.
#define REGISTER_ARENA(name, id) \
static struct arena name = {.allocation_semispace_id = (id)}
#define REGISTER_ARENA(name, id) static thread_local arena name(id)

#define MEM_BLOCK_START(ptr) \
((char *)(((uintptr_t)(ptr)-1) & ~(BLOCK_SIZE - 1)))

#ifdef __MACH__
//
// thread_local disabled for Apple
//
extern bool time_for_collection;
#else
extern thread_local bool time_for_collection;
#endif

size_t get_gc_threshold();

// Resets the given arena.
void arena_reset(struct arena *);

// Returns the given arena's current allocation semispace ID.
// Each arena has 2 semispace IDs one equal to the arena ID and the other equal
// to the 1's complement of the arena ID. At any time one of these semispaces
// is used for allocation and the other is used for collection.
char get_arena_allocation_semispace_id(const struct arena *);

// Returns the given arena's current collection semispace ID.
// See above for details.
char get_arena_collection_semispace_id(const struct arena *);

// Returns the ID of the semispace where the given address was allocated.
// The behavior is undefined if called with an address that has not been
// allocated within an arena.
char get_arena_semispace_id_of_object(void *);

// helper function for `kore_arena_alloc`. Do not call directly.
void *do_alloc_slow(size_t, struct arena *);

// Allocates the requested number of bytes as a contiguous region and returns a
// pointer to the first allocated byte.
// If called with requested size greater than the maximun single allocation
// size, the space is allocated in a general (not garbage collected pool).
inline void *kore_arena_alloc(struct arena *arena, size_t requested) {
if (arena->block + requested > arena->block_end) {
return do_alloc_slow(requested, arena);
inline void *arena::kore_arena_alloc(size_t requested) {
if (block + requested > block_end) {
return do_alloc_slow(requested);
}
void *result = arena->block;
arena->block += requested;
void *result = block;
block += requested;
MEM_LOG(
"Allocation at %p (size %zd), next alloc at %p (if it fits)\n", result,
requested, arena->block);
requested, block);
return result;
}

// Resizes the last allocation as long as the resize does not require a new
// block allocation.
// Returns the address of the byte following the last newlly allocated byte when
// the resize succeeds, returns 0 otherwise.
void *arena_resize_last_alloc(struct arena *, ssize_t);

// Exchanges the current allocation and collection semispaces and clears the new
// current allocation semispace by setting its start back to its first block.
// It is used before garbage collection.
void arena_swap_and_clear(struct arena *);

// Clears the current allocation space by setting its start back to its first
// block. It is used during garbage collection to effectively collect all of the
// arena.
void arena_clear(struct arena *);

// Returns the address of the first byte that belongs in the given arena.
// Returns 0 if nothing has been allocated ever in that arena.
char *arena_start_ptr(const struct arena *);

// Returns a pointer to a location holding the address of last allocated
// byte in the given arena plus 1.
// This address is 0 if nothing has been allocated ever in that arena.
char **arena_end_ptr(struct arena *);

// Given a starting pointer to an address allocated in an arena and a size in
// bytes, this function returns a pointer to an address allocated in the
// same arena after size bytes from the starting pointer.
//
// 1st argument: the starting pointer
// 2nd argument: the size in bytes to add to the starting pointer
// 3rd argument: the address of last allocated byte in the arena plus 1
// Return value: the address allocated in the arena after size bytes from the
// starting pointer, or 0 if this is equal to the 3rd argument.
char *move_ptr(char *, size_t, char const *);

// Given two pointers to objects allocated in the same arena, return the number
// of bytes they are separated by within the virtual block of memory represented
// by the blocks of that arena. This difference will include blocks containing
// sentinel bytes. Undefined behavior will result if the pointers belong to
// different arenas.
ssize_t ptr_diff(char *, char *);

// return the total number of allocatable bytes currently in the arena in its
// active semispace.
size_t arena_size(const struct arena *);

// Deallocates all the memory allocated for registered arenas.
void free_all_memory(void);
}

#endif // ARENA_H
4 changes: 2 additions & 2 deletions include/runtime/collect.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ using set_node = set::iterator::node_t;
using set_impl = set::iterator::tree_t;

extern "C" {
extern size_t numBytesLiveAtCollection[1 << AGE_WIDTH];
extern bool collect_old;
extern thread_local size_t numBytesLiveAtCollection[1 << AGE_WIDTH];
extern thread_local bool collect_old;
size_t get_size(uint64_t, uint16_t);
void migrate_static_roots(void);
void migrate(block **block_ptr);
Expand Down
8 changes: 7 additions & 1 deletion include/runtime/header.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,14 @@ size_t hash_k(block *);
void k_hash(block *, void *);
bool hash_enter(void);
void hash_exit(void);

#ifdef __MACH__
//
// thread_local disabled for Apple
//
extern bool gc_enabled;
#else
extern thread_local bool gc_enabled;
#endif
}

class k_elem {
Expand Down
1 change: 1 addition & 0 deletions include/runtime/types.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef RUNTIME_TYPES_H
#define RUNTIME_TYPES_H

#include <cstdint>
#include <gmp.h>
#include <mpfr.h>

Expand Down
7 changes: 7 additions & 0 deletions lib/codegen/CreateStaticTerm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ llvm::Constant *create_static_term::not_injection_case(
llvm::Constant *block
= module_->getOrInsertGlobal(kore_string.str(), block_type);
auto *global_var = llvm::dyn_cast<llvm::GlobalVariable>(block);
// this is technically not a constant because functions which return fresh constants
// will mutate a block in this circumstance. Probably best not to rely on this actually
// being mutable any other way.

if (!global_var->hasInitializer()) {
std::vector<llvm::Constant *> block_vals;
Expand Down Expand Up @@ -151,6 +154,7 @@ create_static_term::create_token(value_type sort, std::string contents) {
"int_" + contents, llvm::StructType::getTypeByName(
module_->getContext(), int_wrapper_struct));
auto *global_var = llvm::dyn_cast<llvm::GlobalVariable>(global);
global_var->setConstant(true);
if (!global_var->hasInitializer()) {
mpz_t value;
char const *data_start
Expand All @@ -163,6 +167,7 @@ create_static_term::create_token(value_type sort, std::string contents) {
llvm::Constant *limbs = module_->getOrInsertGlobal(
"int_" + contents + "_limbs", limbs_type);
auto *limbs_var = llvm::dyn_cast<llvm::GlobalVariable>(limbs);
limbs_var->setConstant(true);
std::vector<llvm::Constant *> allocd_limbs;
for (size_t i = 0; i < size; i++) {
allocd_limbs.push_back(llvm::ConstantInt::get(
Expand Down Expand Up @@ -205,6 +210,7 @@ create_static_term::create_token(value_type sort, std::string contents) {
"float_" + contents, llvm::StructType::getTypeByName(
module_->getContext(), float_wrapper_struct));
auto *global_var = llvm::dyn_cast<llvm::GlobalVariable>(global);
global_var->setConstant(true);
if (!global_var->hasInitializer()) {
size_t prec = 0;
size_t exp = 0;
Expand Down Expand Up @@ -246,6 +252,7 @@ create_static_term::create_token(value_type sort, std::string contents) {
llvm::Constant *limbs = module_->getOrInsertGlobal(
"float_" + contents + "_limbs", limbs_type);
auto *limbs_var = llvm::dyn_cast<llvm::GlobalVariable>(limbs);
limbs_var->setConstant(true);
std::vector<llvm::Constant *> allocd_limbs;
for (size_t i = 0; i < size; i++) {
allocd_limbs.push_back(llvm::ConstantInt::get(
Expand Down
35 changes: 32 additions & 3 deletions lib/codegen/CreateTerm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -782,18 +782,47 @@ llvm::Value *create_term::disable_gc() {
llvm::Constant *global
= module_->getOrInsertGlobal("gc_enabled", llvm::Type::getInt1Ty(ctx_));
auto *global_var = llvm::cast<llvm::GlobalVariable>(global);
#ifdef __MACH__
//
// thread_local disabled for Apple
//
/*
global_var->setThreadLocal(true);
llvm::IRBuilder b(current_block_);
auto *global_var_address = b.CreateThreadLocalAddress(global_var);
*/
auto *global_var_address = global_var;
#else
global_var->setThreadLocal(true);
auto *global_var_address = global_var;
#endif
auto *old_val = new llvm::LoadInst(
llvm::Type::getInt1Ty(ctx_), global_var, "was_enabled", current_block_);
llvm::Type::getInt1Ty(ctx_), global_var_address, "was_enabled",
current_block_);
new llvm::StoreInst(
llvm::ConstantInt::getFalse(ctx_), global_var, current_block_);
llvm::ConstantInt::getFalse(ctx_), global_var_address, current_block_);
return old_val;
}

void create_term::enable_gc(llvm::Value *was_enabled) {
llvm::Constant *global
= module_->getOrInsertGlobal("gc_enabled", llvm::Type::getInt1Ty(ctx_));
auto *global_var = llvm::cast<llvm::GlobalVariable>(global);
new llvm::StoreInst(was_enabled, global_var, current_block_);
#ifdef __MACH__
//
// thread_local disabled for Apple
//
/*
global_var->setThreadLocal(true);
llvm::IRBuilder b(current_block_);
auto *global_var_address = b.CreateThreadLocalAddress(global_var);
*/
auto *global_var_address = global_var;
#else
global_var->setThreadLocal(true);
auto *global_var_address = global_var;
#endif
new llvm::StoreInst(was_enabled, global_var_address, current_block_);
}

// We use tailcc calling convention for apply_rule_* and eval_* functions to
Expand Down
Loading

0 comments on commit 51d8878

Please sign in to comment.