From 30579afc6d8d2c482089612423f952d1c0bae181 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Thu, 6 Feb 2020 10:05:17 -0800 Subject: [PATCH] Track allocated nodes using a G-machine struct in compiler series. --- 09/instruction.cpp | 8 ++-- 09/llvm_context.cpp | 100 ++++++++++++++++++++++++----------------- 09/llvm_context.hpp | 12 +++-- 09/runtime.c | 107 +++++++++++++++++++++++++++++--------------- 09/runtime.h | 29 ++++++++---- 5 files changed, 163 insertions(+), 93 deletions(-) diff --git a/09/instruction.cpp b/09/instruction.cpp index 79c8a2f..c2b050a 100644 --- a/09/instruction.cpp +++ b/09/instruction.cpp @@ -15,7 +15,7 @@ void instruction_pushint::print(int indent, std::ostream& to) const { } void instruction_pushint::gen_llvm(llvm_context& ctx, Function* f) const { - ctx.create_push(f, ctx.create_num(ctx.create_i32(value))); + ctx.create_push(f, ctx.create_num(f, ctx.create_i32(value))); } void instruction_pushglobal::print(int indent, std::ostream& to) const { @@ -26,7 +26,7 @@ void instruction_pushglobal::print(int indent, std::ostream& to) const { void instruction_pushglobal::gen_llvm(llvm_context& ctx, Function* f) const { auto& global_f = ctx.custom_functions.at("f_" + name); auto arity = ctx.create_i32(global_f->arity); - ctx.create_push(f, ctx.create_global(global_f->function, arity)); + ctx.create_push(f, ctx.create_global(f, global_f->function, arity)); } void instruction_push::print(int indent, std::ostream& to) const { @@ -55,7 +55,7 @@ void instruction_mkapp::print(int indent, std::ostream& to) const { void instruction_mkapp::gen_llvm(llvm_context& ctx, Function* f) const { auto left = ctx.create_pop(f); auto right = ctx.create_pop(f); - ctx.create_push(f, ctx.create_app(left, right)); + ctx.create_push(f, ctx.create_app(f, left, right)); } void instruction_update::print(int indent, std::ostream& to) const { @@ -146,7 +146,7 @@ void instruction_binop::gen_llvm(llvm_context& ctx, Function* f) const { case TIMES: result = ctx.builder.CreateMul(left_int, right_int); break; case DIVIDE: result = ctx.builder.CreateSDiv(left_int, right_int); break; } - ctx.create_push(f, ctx.create_num(result)); + ctx.create_push(f, ctx.create_num(f, result)); } void instruction_eval::print(int indent, std::ostream& to) const { diff --git a/09/llvm_context.cpp b/09/llvm_context.cpp index 18ce6e4..99ab480 100644 --- a/09/llvm_context.cpp +++ b/09/llvm_context.cpp @@ -5,7 +5,9 @@ using namespace llvm; void llvm_context::create_types() { stack_type = StructType::create(ctx, "stack"); + gmachine_type = StructType::create(ctx, "gmachine"); stack_ptr_type = PointerType::getUnqual(stack_type); + gmachine_ptr_type = PointerType::getUnqual(gmachine_type); tag_type = IntegerType::getInt8Ty(ctx); struct_types["node_base"] = StructType::create(ctx, "node_base"); struct_types["node_app"] = StructType::create(ctx, "node_app"); @@ -14,10 +16,16 @@ void llvm_context::create_types() { struct_types["node_ind"] = StructType::create(ctx, "node_ind"); struct_types["node_data"] = StructType::create(ctx, "node_data"); node_ptr_type = PointerType::getUnqual(struct_types.at("node_base")); - function_type = FunctionType::get(Type::getVoidTy(ctx), { stack_ptr_type }, false); + function_type = FunctionType::get(Type::getVoidTy(ctx), { gmachine_ptr_type }, false); + gmachine_type->setBody( + stack_ptr_type, + node_ptr_type + ); struct_types.at("node_base")->setBody( - IntegerType::getInt32Ty(ctx) + IntegerType::getInt32Ty(ctx), + IntegerType::getInt8Ty(ctx), + node_ptr_type ); struct_types.at("node_app")->setBody( struct_types.at("node_base"), @@ -82,34 +90,40 @@ void llvm_context::create_functions() { "stack_popn", &module ); - functions["stack_slide"] = Function::Create( - FunctionType::get(void_type, { stack_ptr_type, sizet_type }, false), + functions["gmachine_slide"] = Function::Create( + FunctionType::get(void_type, { gmachine_ptr_type, sizet_type }, false), Function::LinkageTypes::ExternalLinkage, - "stack_slide", + "gmachine_slide", &module ); - functions["stack_update"] = Function::Create( - FunctionType::get(void_type, { stack_ptr_type, sizet_type }, false), + functions["gmachine_update"] = Function::Create( + FunctionType::get(void_type, { gmachine_ptr_type, sizet_type }, false), Function::LinkageTypes::ExternalLinkage, - "stack_update", + "gmachine_update", &module ); - functions["stack_alloc"] = Function::Create( - FunctionType::get(void_type, { stack_ptr_type, sizet_type }, false), + functions["gmachine_alloc"] = Function::Create( + FunctionType::get(void_type, { gmachine_ptr_type, sizet_type }, false), Function::LinkageTypes::ExternalLinkage, - "stack_alloc", + "gmachine_alloc", &module ); - functions["stack_pack"] = Function::Create( - FunctionType::get(void_type, { stack_ptr_type, sizet_type, tag_type }, false), + functions["gmachine_pack"] = Function::Create( + FunctionType::get(void_type, { gmachine_ptr_type, sizet_type, tag_type }, false), Function::LinkageTypes::ExternalLinkage, - "stack_pack", + "gmachine_pack", &module ); - functions["stack_split"] = Function::Create( - FunctionType::get(node_ptr_type, { stack_ptr_type, sizet_type }, false), + functions["gmachine_split"] = Function::Create( + FunctionType::get(void_type, { gmachine_ptr_type, sizet_type }, false), Function::LinkageTypes::ExternalLinkage, - "stack_split", + "gmachine_split", + &module + ); + functions["gmachine_track"] = Function::Create( + FunctionType::get(node_ptr_type, { gmachine_ptr_type, node_ptr_type }, false), + Function::LinkageTypes::ExternalLinkage, + "gmachine_track", &module ); @@ -139,14 +153,8 @@ void llvm_context::create_functions() { &module ); - functions["eval"] = Function::Create( - FunctionType::get(node_ptr_type, { node_ptr_type }, false), - Function::LinkageTypes::ExternalLinkage, - "eval", - &module - ); functions["unwind"] = Function::Create( - FunctionType::get(void_type, { stack_ptr_type }, false), + FunctionType::get(void_type, { gmachine_ptr_type }, false), Function::LinkageTypes::ExternalLinkage, "unwind", &module @@ -165,40 +173,44 @@ ConstantInt* llvm_context::create_size(size_t i) { Value* llvm_context::create_pop(Function* f) { auto pop_f = functions.at("stack_pop"); - return builder.CreateCall(pop_f, { f->arg_begin() }); + return builder.CreateCall(pop_f, { unwrap_gmachine_stack_ptr(f->arg_begin()) }); } Value* llvm_context::create_peek(Function* f, Value* off) { auto peek_f = functions.at("stack_peek"); - return builder.CreateCall(peek_f, { f->arg_begin(), off }); + return builder.CreateCall(peek_f, { unwrap_gmachine_stack_ptr(f->arg_begin()), off }); } void llvm_context::create_push(Function* f, Value* v) { auto push_f = functions.at("stack_push"); - builder.CreateCall(push_f, { f->arg_begin(), v }); + builder.CreateCall(push_f, { unwrap_gmachine_stack_ptr(f->arg_begin()), v }); } void llvm_context::create_popn(Function* f, Value* off) { auto popn_f = functions.at("stack_popn"); - builder.CreateCall(popn_f, { f->arg_begin(), off }); + builder.CreateCall(popn_f, { unwrap_gmachine_stack_ptr(f->arg_begin()), off }); } void llvm_context::create_update(Function* f, Value* off) { - auto update_f = functions.at("stack_update"); + auto update_f = functions.at("gmachine_update"); builder.CreateCall(update_f, { f->arg_begin(), off }); } void llvm_context::create_pack(Function* f, Value* c, Value* t) { - auto pack_f = functions.at("stack_pack"); + auto pack_f = functions.at("gmachine_pack"); builder.CreateCall(pack_f, { f->arg_begin(), c, t }); } void llvm_context::create_split(Function* f, Value* c) { - auto split_f = functions.at("stack_split"); + auto split_f = functions.at("gmachine_split"); builder.CreateCall(split_f, { f->arg_begin(), c }); } void llvm_context::create_slide(Function* f, Value* off) { - auto slide_f = functions.at("stack_slide"); + auto slide_f = functions.at("gmachine_slide"); builder.CreateCall(slide_f, { f->arg_begin(), off }); } void llvm_context::create_alloc(Function* f, Value* n) { - auto alloc_f = functions.at("stack_alloc"); + auto alloc_f = functions.at("gmachine_alloc"); builder.CreateCall(alloc_f, { f->arg_begin(), n }); } +Value* llvm_context::create_track(Function* f, Value* v) { + auto track_f = functions.at("gmachine_track"); + return builder.CreateCall(track_f, { f->arg_begin(), v }); +} Value* llvm_context::create_eval(Value* e) { auto eval_f = functions.at("eval"); @@ -210,6 +222,11 @@ void llvm_context::create_unwind(Function* f) { builder.CreateCall(unwind_f, { f->args().begin() }); } +Value* llvm_context::unwrap_gmachine_stack_ptr(Value* g) { + auto offset_0 = create_i32(0); + return builder.CreateGEP(g, { offset_0, offset_0 }); +} + Value* llvm_context::unwrap_num(Value* v) { auto num_ptr_type = PointerType::getUnqual(struct_types.at("node_num")); auto cast = builder.CreatePointerCast(v, num_ptr_type); @@ -218,9 +235,10 @@ Value* llvm_context::unwrap_num(Value* v) { auto int_ptr = builder.CreateGEP(cast, { offset_0, offset_1 }); return builder.CreateLoad(int_ptr); } -Value* llvm_context::create_num(Value* v) { +Value* llvm_context::create_num(Function* f, Value* v) { auto alloc_num_f = functions.at("alloc_num"); - return builder.CreateCall(alloc_num_f, { v }); + auto alloc_num_call = builder.CreateCall(alloc_num_f, { v }); + return create_track(f, alloc_num_call); } Value* llvm_context::unwrap_data_tag(Value* v) { @@ -232,20 +250,20 @@ Value* llvm_context::unwrap_data_tag(Value* v) { return builder.CreateLoad(tag_ptr); } -Value* llvm_context::create_global(Value* f, Value* a) { +Value* llvm_context::create_global(Function* f, Value* gf, Value* a) { auto alloc_global_f = functions.at("alloc_global"); - return builder.CreateCall(alloc_global_f, { f, a }); + auto alloc_global_call = builder.CreateCall(alloc_global_f, { gf, a }); + return create_track(f, alloc_global_call); } -Value* llvm_context::create_app(Value* l, Value* r) { +Value* llvm_context::create_app(Function* f, Value* l, Value* r) { auto alloc_app_f = functions.at("alloc_app"); - return builder.CreateCall(alloc_app_f, { l, r }); + auto alloc_app_call = builder.CreateCall(alloc_app_f, { l, r }); + return create_track(f, alloc_app_call); } llvm::Function* llvm_context::create_custom_function(std::string name, int32_t arity) { auto void_type = llvm::Type::getVoidTy(ctx); - auto function_type = - llvm::FunctionType::get(void_type, { stack_ptr_type }, false); auto new_function = llvm::Function::Create( function_type, llvm::Function::LinkageTypes::ExternalLinkage, diff --git a/09/llvm_context.hpp b/09/llvm_context.hpp index 7c9a6a6..89e145e 100644 --- a/09/llvm_context.hpp +++ b/09/llvm_context.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include struct llvm_context { @@ -23,7 +24,9 @@ struct llvm_context { std::map struct_types; llvm::StructType* stack_type; + llvm::StructType* gmachine_type; llvm::PointerType* stack_ptr_type; + llvm::PointerType* gmachine_ptr_type; llvm::PointerType* node_ptr_type; llvm::IntegerType* tag_type; llvm::FunctionType* function_type; @@ -50,18 +53,21 @@ struct llvm_context { void create_split(llvm::Function*, llvm::Value*); void create_slide(llvm::Function*, llvm::Value*); void create_alloc(llvm::Function*, llvm::Value*); + llvm::Value* create_track(llvm::Function*, llvm::Value*); llvm::Value* create_eval(llvm::Value*); void create_unwind(llvm::Function*); + llvm::Value* unwrap_gmachine_stack_ptr(llvm::Value*); + llvm::Value* unwrap_num(llvm::Value*); - llvm::Value* create_num(llvm::Value*); + llvm::Value* create_num(llvm::Function*, llvm::Value*); llvm::Value* unwrap_data_tag(llvm::Value*); - llvm::Value* create_global(llvm::Value*, llvm::Value*); + llvm::Value* create_global(llvm::Function*, llvm::Value*, llvm::Value*); - llvm::Value* create_app(llvm::Value*, llvm::Value*); + llvm::Value* create_app(llvm::Function*, llvm::Value*, llvm::Value*); llvm::Function* create_custom_function(std::string name, int32_t arity); }; diff --git a/09/runtime.c b/09/runtime.c index ebae7ae..c5f855f 100644 --- a/09/runtime.c +++ b/09/runtime.c @@ -25,7 +25,7 @@ struct node_num* alloc_num(int32_t n) { return node; } -struct node_global* alloc_global(void (*f)(struct stack*), int32_t a) { +struct node_global* alloc_global(void (*f)(struct gmachine*), int32_t a) { struct node_global* node = (struct node_global*) alloc_node(); node->base.tag = NODE_GLOBAL; node->arity = a; @@ -40,6 +40,12 @@ struct node_ind* alloc_ind(struct node_base* n) { return node; } +void free_node_direct(struct node_base* n) { + if(n->tag == NODE_DATA) { + free(((struct node_data*) n)->array); + } +} + void stack_init(struct stack* s) { s->size = 4; s->count = 0; @@ -74,49 +80,81 @@ void stack_popn(struct stack* s, size_t n) { s->count -= n; } -void stack_slide(struct stack* s, size_t n) { - assert(s->count > n); - s->data[s->count - n - 1] = s->data[s->count - 1]; - s->count -= n; +void gmachine_init(struct gmachine* g) { + stack_init(&g->stack); + g->nodes = NULL; } -void stack_update(struct stack* s, size_t o) { - assert(s->count > o + 1); - struct node_ind* ind = (struct node_ind*) s->data[s->count - o - 2]; - ind->base.tag = NODE_IND; - ind->next = s->data[s->count -= 1]; -} +void gmachine_free(struct gmachine* g) { + stack_free(&g->stack); + struct node_base* to_free = g->nodes; + struct node_base* next; -void stack_alloc(struct stack* s, size_t o) { - while(o--) { - stack_push(s, (struct node_base*) alloc_ind(NULL)); + while(to_free) { + next = to_free->gc_next; + free_node_direct(to_free); + free(to_free); + to_free = next; } } -void stack_pack(struct stack* s, size_t n, int8_t t) { - assert(s->count >= n); +void gmachine_slide(struct gmachine* g, size_t n) { + assert(g->stack.count > n); + g->stack.data[g->stack.count - n - 1] = g->stack.data[g->stack.count - 1]; + g->stack.count -= n; +} + +void gmachine_update(struct gmachine* g, size_t o) { + assert(g->stack.count > o + 1); + struct node_ind* ind = + (struct node_ind*) g->stack.data[g->stack.count - o - 2]; + ind->base.tag = NODE_IND; + ind->next = g->stack.data[g->stack.count -= 1]; +} + +void gmachine_alloc(struct gmachine* g, size_t o) { + while(o--) { + stack_push(&g->stack, + gmachine_track(g, (struct node_base*) alloc_ind(NULL))); + } +} + +void gmachine_pack(struct gmachine* g, size_t n, int8_t t) { + assert(g->stack.count >= n); struct node_base** data = malloc(sizeof(*data) * n); assert(data != NULL); - memcpy(data, &s->data[s->count - n], n * sizeof(*data)); + memcpy(data, &g->stack.data[g->stack.count - n], n * sizeof(*data)); struct node_data* new_node = (struct node_data*) alloc_node(); new_node->array = data; new_node->base.tag = NODE_DATA; new_node->tag = t; - stack_popn(s, n); - stack_push(s, (struct node_base*) new_node); + stack_popn(&g->stack, n); + stack_push(&g->stack, gmachine_track(g, (struct node_base*) new_node)); } -void stack_split(struct stack* s, size_t n) { - struct node_data* node = (struct node_data*) stack_pop(s); +void gmachine_split(struct gmachine* g, size_t n) { + struct node_data* node = (struct node_data*) stack_pop(&g->stack); for(size_t i = 0; i < n; i++) { - stack_push(s, node->array[i]); + stack_push(&g->stack, node->array[i]); } } -void unwind(struct stack* s) { +struct node_base* gmachine_track(struct gmachine* g, struct node_base* b) { + b->gc_next = g->nodes; + g->nodes = b; + return b; +} + +void gmachine_gc(struct gmachine* g) { + +} + +void unwind(struct gmachine* g) { + struct stack* s = &g->stack; + while(1) { struct node_base* peek = stack_peek(s, 0); if(peek->tag == NODE_APP) { @@ -131,7 +169,7 @@ void unwind(struct stack* s) { = ((struct node_app*) s->data[s->count - i - 1])->right; } - n->function(s); + n->function(g); } else if(peek->tag == NODE_IND) { struct node_ind* n = (struct node_ind*) peek; stack_pop(s); @@ -142,17 +180,7 @@ void unwind(struct stack* s) { } } -struct node_base* eval(struct node_base* n) { - struct stack program_stack; - stack_init(&program_stack); - stack_push(&program_stack, n); - unwind(&program_stack); - struct node_base* result = stack_pop(&program_stack); - stack_free(&program_stack); - return result; -} - -extern void f_main(struct stack* s); +extern void f_main(struct gmachine* s); void print_node(struct node_base* n) { if(n->tag == NODE_APP) { @@ -174,10 +202,17 @@ void print_node(struct node_base* n) { } int main(int argc, char** argv) { + struct gmachine gmachine; struct node_global* first_node = alloc_global(f_main, 0); - struct node_base* result = eval((struct node_base*) first_node); + struct node_base* result; + gmachine_init(&gmachine); + gmachine_track(&gmachine, (struct node_base*) first_node); + stack_push(&gmachine.stack, (struct node_base*) first_node); + unwind(&gmachine); + result = stack_pop(&gmachine.stack); printf("Result: "); print_node(result); putchar('\n'); + gmachine_free(&gmachine); } diff --git a/09/runtime.h b/09/runtime.h index baaaaae..c1f9dee 100644 --- a/09/runtime.h +++ b/09/runtime.h @@ -1,7 +1,7 @@ #pragma once #include -struct stack; +struct gmachine; enum node_tag { NODE_APP, @@ -13,6 +13,8 @@ enum node_tag { struct node_base { enum node_tag tag; + int8_t gc_color; + struct node_base* gc_next; }; struct node_app { @@ -29,7 +31,7 @@ struct node_num { struct node_global { struct node_base base; int32_t arity; - void (*function)(struct stack*); + void (*function)(struct gmachine*); }; struct node_ind { @@ -46,8 +48,9 @@ struct node_data { struct node_base* alloc_node(); struct node_app* alloc_app(struct node_base* l, struct node_base* r); struct node_num* alloc_num(int32_t n); -struct node_global* alloc_global(void (*f)(struct stack*), int32_t a); +struct node_global* alloc_global(void (*f)(struct gmachine*), int32_t a); struct node_ind* alloc_ind(struct node_base* n); +void free_node_direct(struct node_base*); struct stack { size_t size; @@ -61,10 +64,18 @@ void stack_push(struct stack* s, struct node_base* n); struct node_base* stack_pop(struct stack* s); struct node_base* stack_peek(struct stack* s, size_t o); void stack_popn(struct stack* s, size_t n); -void stack_slide(struct stack* s, size_t n); -void stack_update(struct stack* s, size_t o); -void stack_alloc(struct stack* s, size_t o); -void stack_pack(struct stack* s, size_t n, int8_t t); -void stack_split(struct stack* s, size_t n); -struct node_base* eval(struct node_base* n); +struct gmachine { + struct stack stack; + struct node_base* nodes; +}; + +void gmachine_init(struct gmachine* g); +void gmachine_free(struct gmachine* g); +void gmachine_slide(struct gmachine* g, size_t n); +void gmachine_update(struct gmachine* g, size_t o); +void gmachine_alloc(struct gmachine* g, size_t o); +void gmachine_pack(struct gmachine* g, size_t n, int8_t t); +void gmachine_split(struct gmachine* g, size_t n); +struct node_base* gmachine_track(struct gmachine* g, struct node_base* b); +void gmachine_gc(struct gmachine* g);