Skip to content

Commit 561d911

Browse files
committed
compiler: reduce temporaries lifespan
1 parent 6c718be commit 561d911

6 files changed

Lines changed: 95 additions & 56 deletions

File tree

src/compiler/backend/src/FunctionCodegen.cpp

Lines changed: 54 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class ScopeManager {
4646
struct Frame {
4747
enum class Kind : std::uint8_t {
4848
kRegular,
49+
kTemporaries,
4950
kLoop,
5051
};
5152

@@ -57,7 +58,7 @@ class ScopeManager {
5758
Kind kind;
5859
};
5960

60-
void Enter(Frame::Kind kind = Frame::Kind::kRegular) {
61+
void Enter(Frame::Kind kind) {
6162
frame_stack_.emplace_back(Frame{
6263
.begin = u_.builder.GetInsertPoint(),
6364
.kind = kind,
@@ -192,6 +193,17 @@ class ScopeManager {
192193
llvm::Function* fn_;
193194
};
194195

196+
class ScopeGuard {
197+
public:
198+
ScopeGuard(ScopeManager& m) : m_(m) {}
199+
~ScopeGuard() {
200+
m_.Exit();
201+
}
202+
203+
private:
204+
ScopeManager& m_;
205+
};
206+
195207
class FunctionCodegen {
196208
public:
197209
FunctionCodegen(CodegenUnit& u) : u_(u) {}
@@ -251,6 +263,11 @@ class FunctionCodegen {
251263
return u_.sf.Text(n);
252264
}
253265

266+
[[nodiscard]] ScopeGuard EnterStackFrame(ScopeManager::Frame::Kind kind = ScopeManager::Frame::Kind::kRegular) {
267+
scope_->Enter(kind);
268+
return *scope_;
269+
}
270+
254271
void CodegenStmt(const ast::nodes::Stmt*);
255272
void CodegenDecl(const ast::nodes::Decl*);
256273
llvm::Value* CodegenExpr(const ast::nodes::Expr*, llvm::Value* dest = nullptr);
@@ -295,11 +312,10 @@ void FunctionCodegen::CodegenStmt(const ast::nodes::Stmt* n) {
295312
switch (n->nkind) {
296313
case ast::NodeKind::BlockStmt: {
297314
const auto* m = n->As<ast::nodes::BlockStmt>();
298-
scope_->Enter();
315+
auto stack_frame{EnterStackFrame()};
299316
for (const auto* stmt : m->stmts) {
300317
CodegenStmt(stmt);
301318
}
302-
scope_->Exit();
303319
break;
304320
}
305321

@@ -337,7 +353,7 @@ void FunctionCodegen::CodegenStmt(const ast::nodes::Stmt* n) {
337353
case ast::NodeKind::ForStmt: {
338354
const auto* m = n->As<ast::nodes::ForStmt>();
339355

340-
scope_->Enter(); // fake scope to drop loop variable after ForStmt end
356+
auto for_frame{EnterStackFrame()}; // fake scope to drop loop variable after ForStmt end
341357
//
342358
CodegenStmt(m->init);
343359

@@ -355,21 +371,19 @@ void FunctionCodegen::CodegenStmt(const ast::nodes::Stmt* n) {
355371
u_.builder.CreateBr(cond_bb);
356372

357373
u_.builder.SetInsertPoint(body_bb);
358-
scope_->Enter(ScopeManager::Frame::Kind::kLoop);
359374
{
360-
lib::ScopedValue loop_ctx_guard(loop_ctx_, {.post = post_bb, .end = end_bb});
361-
CodegenStmt(m->body);
362-
}
363-
if (!u_.builder.GetInsertBlock()->getTerminator()) {
364-
u_.builder.CreateBr(post_bb);
375+
auto loop_frame{EnterStackFrame(ScopeManager::Frame::Kind::kLoop)};
376+
{
377+
lib::ScopedValue loop_ctx_guard(loop_ctx_, {.post = post_bb, .end = end_bb});
378+
CodegenStmt(m->body);
379+
}
380+
if (!u_.builder.GetInsertBlock()->getTerminator()) {
381+
u_.builder.CreateBr(post_bb);
382+
}
365383
}
366-
scope_->Exit();
367384

368385
u_.builder.SetInsertPoint(end_bb);
369386

370-
//
371-
scope_->Exit();
372-
373387
break;
374388
}
375389

@@ -385,15 +399,16 @@ void FunctionCodegen::CodegenStmt(const ast::nodes::Stmt* n) {
385399
u_.builder.CreateCondBr(CodegenExprAsBool(m->cond), body_bb, end_bb);
386400

387401
u_.builder.SetInsertPoint(body_bb);
388-
scope_->Enter(ScopeManager::Frame::Kind::kLoop);
389402
{
390-
lib::ScopedValue loop_ctx_guard(loop_ctx_, {.post = body_bb, .end = end_bb});
391-
CodegenStmt(m->body);
392-
}
393-
if (!u_.builder.GetInsertBlock()->getTerminator()) {
394-
u_.builder.CreateBr(cond_bb);
403+
auto loop_frame{EnterStackFrame(ScopeManager::Frame::Kind::kLoop)};
404+
{
405+
lib::ScopedValue loop_ctx_guard(loop_ctx_, {.post = body_bb, .end = end_bb});
406+
CodegenStmt(m->body);
407+
}
408+
if (!u_.builder.GetInsertBlock()->getTerminator()) {
409+
u_.builder.CreateBr(cond_bb);
410+
}
395411
}
396-
scope_->Exit();
397412

398413
u_.builder.SetInsertPoint(end_bb);
399414

@@ -408,15 +423,16 @@ void FunctionCodegen::CodegenStmt(const ast::nodes::Stmt* n) {
408423
auto* end_bb = llvm::BasicBlock::Create(u_.ctx, "do.end", fn_);
409424

410425
u_.builder.SetInsertPoint(body_bb);
411-
scope_->Enter(ScopeManager::Frame::Kind::kLoop);
412426
{
413-
lib::ScopedValue loop_ctx_guard(loop_ctx_, {.post = body_bb, .end = end_bb});
414-
CodegenStmt(m->body);
415-
}
416-
if (!u_.builder.GetInsertBlock()->getTerminator()) {
417-
u_.builder.CreateBr(cond_bb);
427+
auto loop_frame{EnterStackFrame(ScopeManager::Frame::Kind::kLoop)};
428+
{
429+
lib::ScopedValue loop_ctx_guard(loop_ctx_, {.post = body_bb, .end = end_bb});
430+
CodegenStmt(m->body);
431+
}
432+
if (!u_.builder.GetInsertBlock()->getTerminator()) {
433+
u_.builder.CreateBr(cond_bb);
434+
}
418435
}
419-
scope_->Exit();
420436

421437
u_.builder.CreateBr(cond_bb);
422438
u_.builder.SetInsertPoint(cond_bb);
@@ -485,7 +501,11 @@ void FunctionCodegen::CodegenDecl(const ast::nodes::Decl* n) {
485501
for (auto* decl : m->decls) {
486502
auto* alloca = scope_->Alloc(Lit(decl->name), itype.sym);
487503
if (decl->value) {
488-
auto* v = CodegenExpr(decl->value, alloca);
504+
llvm::Value* v;
505+
{
506+
auto tmp_frame{EnterStackFrame(ScopeManager::Frame::Kind::kTemporaries)};
507+
v = CodegenExpr(decl->value, alloca);
508+
}
489509
if (IsTrivial(v->getType())) {
490510
u_.builder.CreateStore(v, alloca);
491511
}
@@ -654,6 +674,8 @@ llvm::Value* FunctionCodegen::CodegenExpr(const ast::nodes::Expr* expr, llvm::Va
654674
case ast::NodeKind::CallExpr: {
655675
const auto* m = expr->As<ast::nodes::CallExpr>();
656676

677+
auto tmp_frame{EnterStackFrame(ScopeManager::Frame::Kind::kTemporaries)};
678+
657679
const auto* func_sym = core::checker::ResolveExprSymbol(&u_.sf, u_.sf.module->scope, m->fun).sym;
658680
assert(func_sym->Flags() & core::semantic::SymbolFlags::kFunction);
659681

@@ -695,7 +717,9 @@ llvm::Value* FunctionCodegen::CodegenExpr(const ast::nodes::Expr* expr, llvm::Va
695717
VANADIUM_DEBUG_ASSERT(av != nullptr, "Unknown argument expr type: {}", magic_enum::enum_name(argnode->nkind))
696718
}
697719

698-
return u_.builder.CreateCall(callee, args);
720+
auto* res = u_.builder.CreateCall(callee, args);
721+
722+
return res;
699723
}
700724

701725
case ast::NodeKind::ParenExpr: {

src/compiler/runtime/include/vanadium/runtime/RuntimeInternals.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#include <span>
22

3-
#include "vanadium/runtime/runtime.h" // IWYU pragma: export
3+
#include "vanadium/runtime/runtime.h"
44

55
namespace vanadium::rt {
66
[[nodiscard]] std::span<const vrt_module_t* const> GetModules();

src/compiler/runtime/include/vanadium/runtime/StaticArena.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ class StaticArena {
1919
StaticArena& operator=(const StaticArena&) = delete;
2020
StaticArena& operator=(StaticArena&&) = delete;
2121

22-
void* Alloc(std::size_t bytes, std::size_t alignment) {
22+
void* Alloc(std::size_t size, std::size_t alignment) {
2323
void* ptr = cursor_;
2424
std::size_t space = buf_.end() - cursor_;
2525

26-
if (std::align(alignment, bytes, ptr, space)) {
27-
cursor_ = static_cast<std::byte*>(ptr) + bytes;
26+
if (std::align(alignment, size, ptr, space)) {
27+
cursor_ = static_cast<std::byte*>(ptr) + size;
2828
return ptr;
2929
}
3030

@@ -43,6 +43,10 @@ class StaticArena {
4343
stack_.pop_back();
4444
}
4545

46+
[[nodiscard]] bool Contains(void* p) {
47+
return buf_.begin() <= p && p <= buf_.end();
48+
}
49+
4650
private:
4751
std::byte* cursor_;
4852
std::vector<std::byte*> stack_;

src/compiler/runtime/interface/vanadium/runtime/rt_alloc.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
#pragma once
22

3+
#include <cstddef>
4+
35
struct vrt_typeinfo_t;
46

57
extern "C" {
68
//
79

10+
void* vrt_alloc(std::size_t size, std::size_t alignment);
11+
void* vrt_stackalloc(std::size_t size, std::size_t alignment);
12+
void vrt_unifree(void*);
13+
814
void* vrt_new(const vrt_typeinfo_t*);
915
void vrt_del(const vrt_typeinfo_t*, void*);
1016

src/compiler/runtime/src/rt_alloc.cpp

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "vanadium/runtime/rt_alloc.h"
22

3-
#include <print>
3+
#include <cstddef>
4+
#include <cstdlib>
45

56
#include "vanadium/runtime/StaticArena.h"
67
#include "vanadium/runtime/runtime.h"
@@ -9,24 +10,31 @@ namespace {
910
vanadium::runtime::StaticArena<64 * 1024 * 1024> arena;
1011
}
1112

13+
void* vrt_alloc(std::size_t size, std::size_t alignment) {
14+
return std::aligned_alloc(alignment, size);
15+
}
16+
void* vrt_stackalloc(std::size_t size, std::size_t alignment) {
17+
return arena.Alloc(size, alignment);
18+
}
19+
void vrt_unifree(void* p) {
20+
if (!arena.Contains(p)) {
21+
std::free(p);
22+
}
23+
}
24+
1225
void* vrt_new(const vrt_typeinfo_t* td) {
13-
std::println("vrt_allocate({})", td->name);
14-
std::fflush(stdout);
15-
auto* p = std::malloc(td->bytes);
26+
// TODO: write alignment to typeinfo, use it below
27+
auto* p = vrt_alloc(td->bytes, 8);
1628
td->construct(p);
1729
return p;
1830
}
1931

2032
void vrt_del(const vrt_typeinfo_t* td, void* p) {
21-
std::println("vrt_free({}): {:p}", td->name, p);
22-
std::fflush(stdout);
2333
td->destruct(p);
24-
std::free(p);
34+
vrt_unifree(p);
2535
}
2636

2737
void* vrt_stackalloc_new(const vrt_typeinfo_t* td) {
28-
std::println("vrt_stackalloc_new({})", td->name);
29-
std::fflush(stdout);
3038
auto* p = arena.Alloc(td->bytes, 8);
3139
td->construct(p);
3240
return p;

src/compiler/runtime/src/rt_charstring.cpp

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <utility>
77

88
#include "vanadium/runtime/RuntimeHelpers.h"
9+
#include "vanadium/runtime/rt_alloc.h"
910
#include "vanadium/runtime/rt_reflect.h"
1011
#include "vanadium/runtime/runtime.h"
1112
#include "vanadium/runtime/runtime.hpp"
@@ -21,12 +22,8 @@ inline void AssertIsBound(const vrt_charstring_t* s) {
2122
}
2223
}
2324

24-
// TODO: forward custom alloc
25-
char* charstring_alloc_buf(std::uint32_t len) {
26-
return new char[len];
27-
}
28-
void charstring_free_buf(const char* p) {
29-
delete[] p;
25+
char* vrt_alloc_charbuf(std::uint32_t len) {
26+
return static_cast<char*>(vrt_alloc(len, 1));
3027
}
3128

3229
struct LengthUpdateOpts {
@@ -41,12 +38,12 @@ void charstring_update_length(vrt_charstring_t* s, std::uint32_t len) {
4138
if constexpr (Opts.realloc) {
4239
std::copy_n(ext_buf, s->length, s->value.intl);
4340
}
44-
charstring_free_buf(ext_buf);
41+
vrt_unifree(ext_buf);
4542
s->is_ext = false;
4643
}
4744
} else {
4845
if (!s->is_ext) {
49-
auto* ext_buf = charstring_alloc_buf(len);
46+
auto* ext_buf = vrt_alloc_charbuf(len);
5047
if constexpr (Opts.realloc) {
5148
std::copy_n(s->value.intl, s->length, ext_buf);
5249
}
@@ -55,12 +52,12 @@ void charstring_update_length(vrt_charstring_t* s, std::uint32_t len) {
5552
s->is_ext = true;
5653
} else if (len > s->value.ext.capacity) {
5754
if constexpr (Opts.realloc) {
58-
auto* new_buf = charstring_alloc_buf(len);
55+
auto* new_buf = vrt_alloc_charbuf(len);
5956
std::copy_n(s->value.ext.data, s->length, new_buf);
60-
charstring_free_buf(s->value.ext.data);
57+
vrt_unifree(s->value.ext.data);
6158
} else {
62-
charstring_free_buf(s->value.ext.data);
63-
s->value.ext.data = charstring_alloc_buf(len);
59+
vrt_unifree(s->value.ext.data);
60+
s->value.ext.data = vrt_alloc_charbuf(len);
6461
s->value.ext.capacity = len;
6562
}
6663
}
@@ -86,7 +83,7 @@ void vrt_charstring_ctor(vrt_charstring_t* p) {
8683
}
8784
void vrt_charstring_dtor(vrt_charstring_t* p) {
8885
if (p->is_bound && p->is_ext) {
89-
charstring_free_buf(p->value.ext.data);
86+
vrt_unifree(p->value.ext.data);
9087
}
9188
}
9289

0 commit comments

Comments
 (0)