global env; alloca locals

kinda messy
main
Clyne 4 months ago
parent c546646cd4
commit 95901f3a5f
Signed by: clyne
GPG Key ID: 3267C8EBF3F9AFC7

@ -20,7 +20,24 @@
#include <charconv> #include <charconv>
#include <iostream> #include <iostream>
extern std::list<ThunkAST> scope;
int ThunkAST::tcount = 0; int ThunkAST::tcount = 0;
int ThunkAST::envidx = 0;
static inline auto loadEnv(LLVMState& llvmState, llvm::Value *index)
{
auto ptrty = llvmState.inttype->getPointerTo();
auto gep = llvmState.builder.CreateGEP(ptrty, scope.back().env, {index});
return llvmState.builder.CreateLoad(ptrty, gep);
}
static inline auto storeEnv(LLVMState& llvmState, llvm::Value *index, llvm::Value *val)
{
auto ptrty = llvmState.inttype->getPointerTo();
auto var = llvmState.builder.CreateGEP(ptrty, scope.back().env, {index});
return llvmState.builder.CreateStore(val, var, false);
}
NumberAST::NumberAST(const std::string& n): BaseAST(n) {} NumberAST::NumberAST(const std::string& n): BaseAST(n) {}
@ -34,7 +51,7 @@ llvm::Value *NumberAST::codegen(LLVMState& llvmState) const
return nullptr; return nullptr;
} else { } else {
auto val = llvmState.createInt(value); auto val = llvmState.createInt(value);
return llvmState.builder.CreateStore(val, llvmState.createPush()); return llvmState.createPush(val);
} }
} }
@ -42,12 +59,16 @@ PushAST::PushAST(const std::string& n): BaseAST(n) {}
llvm::Value *PushAST::codegen(LLVMState& llvmState) const llvm::Value *PushAST::codegen(LLVMState& llvmState) const
{ {
if (auto [var, thunk] = Var::lookup(name); var) { if (auto [var, native] = Var::lookup(name, 1); var) {
auto dsget = llvmState.createPush(); auto index = llvm::ConstantInt::get(llvmState.inttype, ThunkAST::envidx++);
if (!thunk) Var::addLocal(name, index);
var = llvmState.builder.CreateLoad(llvmState.inttype, var); }
if (auto [var, native] = Var::lookupLocal(name); var) {
if (!native)
var = loadEnv(llvmState, var);
return llvmState.builder.CreateStore(var, dsget); return llvmState.createPush(var);
} else { } else {
std::cerr << "error: not defined: " << name << std::endl; std::cerr << "error: not defined: " << name << std::endl;
return nullptr; return nullptr;
@ -58,42 +79,77 @@ PopAST::PopAST(const std::string& n): BaseAST(n) {}
llvm::Value *PopAST::codegen(LLVMState& llvmState) const llvm::Value *PopAST::codegen(LLVMState& llvmState) const
{ {
Var v;
if (name == "self") { if (name == "self") {
extern std::list<ThunkAST> scope; v = {scope.back().func, true};
auto func = scope.back().func;
auto var = llvmState.createVariable(name);
llvmState.builder.CreateStore(func, var, false);
return Var::addLocal(name, var).value;
} else { } else {
auto gep = llvmState.createPop(); auto index = llvm::ConstantInt::get(llvmState.inttype, ThunkAST::envidx++);
auto var = llvmState.createVariable(name); auto pop = llvmState.createPop();
auto load = llvmState.builder.CreateLoad(llvmState.inttype, gep); storeEnv(llvmState, index, pop);
llvmState.builder.CreateStore(load, var, false);
return Var::addLocal(name, var).value; v = index;
} }
return Var::addLocal(name, v).value;
} }
CallAST::CallAST(const std::string& n): BaseAST(n) {} CallAST::CallAST(const std::string& n): BaseAST(n) {}
llvm::Value *CallAST::codegen(LLVMState& llvmState) const llvm::Value *CallAST::codegen(LLVMState& llvmState) const
{ {
if (auto [var, call] = Var::lookup(name); var) { if (auto [var, native] = Var::lookup(name, 1); var && !native) {
if (call) { auto index = llvm::ConstantInt::get(llvmState.inttype, ThunkAST::envidx++);
return llvmState.builder.CreateCall(llvmState.ftype, var); Var::addLocal(name, index);
} else {
auto val = llvmState.builder.CreateLoad(llvmState.inttype, var);
auto cast = llvmState.builder.CreateIntToPtr(val,
llvmState.inttype->getPointerTo());
return llvmState.builder.CreateCall(llvmState.ftype, cast);
} }
llvm::Value *fn;
if (auto [var, native] = Var::lookup(name); var) {
if (!native)
var = loadEnv(llvmState, var);
fn = var;
} else { } else {
std::cerr << "warning: anticipating external function: " std::cerr << "warning: anticipating external function: "
<< name << std::endl; << name << std::endl;
auto func = llvmState.createFunction(name);
Var::addGlobal(name, Var {func, true}); fn = llvmState.createFunction(name);
return llvmState.builder.CreateCall(llvmState.ftype, func); Var::addGlobal(name, Var {fn, true});
}
auto ptrty = llvmState.inttype->getPointerTo();
llvm::Type *type;
llvm::Value *mem;
if (auto sz = Var::vars.back().size(); sz > 0) {
type = llvm::VectorType::get(llvmState.inttype, sz, false);
mem = llvmState.builder.CreateAlloca(type, nullptr);
int i = 0;
for (auto& [_, v] : Var::vars.back()) {
if (!v.native) {
auto index = llvm::ConstantInt::get(llvmState.inttype, i++);
auto m = llvmState.builder.CreateGEP(ptrty, mem, {index});
llvmState.builder.CreateStore(loadEnv(llvmState, v.value), m, false);
}
}
}
auto call = llvmState.builder.CreateCall(llvmState.ftype, fn, llvm::ArrayRef {scope.back().env});
if (auto sz = Var::vars.back().size(); sz > 0) {
int i = 0;
for (auto& [_, v] : Var::vars.back()) {
if (!v.native) {
auto index = llvm::ConstantInt::get(llvmState.inttype, i++);
auto m = llvmState.builder.CreateGEP(ptrty, mem, {index});
auto l = llvmState.builder.CreateLoad(ptrty, m);
storeEnv(llvmState, v.value, l);
}
}
} }
return call;
} }
ThunkAST::ThunkAST(LLVMState& llvmState): ThunkAST::ThunkAST(LLVMState& llvmState):
@ -103,15 +159,30 @@ ThunkAST::ThunkAST(LLVMState& llvmState, std::string n): BaseAST(n)
{ {
parent = llvmState.builder.saveIP(); parent = llvmState.builder.saveIP();
func = llvmState.createFunction(name); func = llvmState.createFunction(name);
auto BB = llvmState.createEntry(func); entry = llvmState.createEntry(func);
llvmState.builder.SetInsertPoint(BB); body = llvm::BasicBlock::Create(llvmState.ctx, "body", func);
env = func->getArg(0);
llvmState.builder.SetInsertPoint(entry);
llvmState.builder.SetInsertPoint(body);
} }
llvm::Value *ThunkAST::codegen(LLVMState& llvmState) const llvm::Value *ThunkAST::codegen(LLVMState& llvmState) const
{ {
llvmState.builder.CreateRetVoid(); llvmState.builder.CreateRetVoid();
llvmState.builder.restoreIP(parent); llvmState.builder.SetInsertPoint(entry);
if (Var::vars.back().size() > 0) {
for (auto& [n, v] : Var::vars.back()) {
if (auto [c, _] = Var::lookup(n, 1); c) {
auto src = loadEnv(llvmState, c);
storeEnv(llvmState, v.value, src);
}
}
}
llvmState.builder.CreateBr(body);
llvmState.builder.restoreIP(parent);
return func; return func;
} }

@ -66,10 +66,12 @@ struct CallAST : public BaseAST
struct ThunkAST : public BaseAST struct ThunkAST : public BaseAST
{ {
static int tcount; static int tcount;
static int envidx;
std::list<std::unique_ptr<BaseAST>> body;
llvm::IRBuilderBase::InsertPoint parent; llvm::IRBuilderBase::InsertPoint parent;
llvm::Function *func; llvm::Function *func;
llvm::BasicBlock *entry, *body;
llvm::Value *env;
explicit ThunkAST(LLVMState& llvmState); explicit ThunkAST(LLVMState& llvmState);
explicit ThunkAST(LLVMState& llvmState, std::string n); explicit ThunkAST(LLVMState& llvmState, std::string n);

@ -0,0 +1,56 @@
(
; core utilities
($x ^x ^x) $dup
($_) $drop
($x $y ^x ^y) $swap
($a $b $c ^b ^a ^c) $rot
(sub) $-
(0 swap - -) $+
(()) $nil
(nil eq) $null?
($x x) $force
(10 emit) $cr
(print) $print
(4 +) $cell+
($a $d 2 alloc $p
^a ^p poke
^d ^p cell+ poke
^p
) $cons
(peek) $car
(cell+ peek) $cdr
; if-stmt
($c $t $f c ^f ^t rot cswap $_ force) $if
($f $t $c $fn ^f ^t ^c fn) $endif
; range
($self $start $end
^if (^start ^end eq)
^nil
(^start ^end ^start 1 + self swap cons)
endif
) $range
; map [$fn $list -> $out-list]
($self $fn $list
^if (^list null?)
^nil
(^list car fn ^list cdr ^fn self swap cons)
endif
) $map
; each [$fn $list]
($fn (fn ^nil) map drop) $each
; implementation
(0 1 ($self $a $b $n
^if (^n 0 eq) (^b) (
^n 1 - ^a ^b + ^b self
) endif
) force) $fibonacci
30 10 range
^fibonacci map
^print each
)

@ -22,8 +22,8 @@ LLVMState::LLVMState():
modul("forsp", ctx), modul("forsp", ctx),
builder(ctx), builder(ctx),
inttype(llvm::Type::getInt32Ty(ctx)), inttype(llvm::Type::getInt32Ty(ctx)),
stacktype(llvm::VectorType::get(inttype, 12, false)), stacktype(llvm::VectorType::get(inttype, 16, false)),
ftype(llvm::FunctionType::get(llvm::Type::getVoidTy(ctx), {}, false)), ftype(llvm::FunctionType::get(llvm::Type::getVoidTy(ctx), llvm::ArrayRef<llvm::Type *> {inttype->getPointerTo()}, false)),
one(llvm::ConstantInt::get(inttype, 1)), one(llvm::ConstantInt::get(inttype, 1)),
zero(llvm::ConstantInt::get(inttype, 0)) zero(llvm::ConstantInt::get(inttype, 0))
{ {
@ -34,13 +34,14 @@ LLVMState::LLVMState():
llvm::GlobalValue::ExternalLinkage, zerovec, "stack"); llvm::GlobalValue::ExternalLinkage, zerovec, "stack");
} }
llvm::Value *LLVMState::createPush() llvm::Value *LLVMState::createPush(llvm::Value *var)
{ {
auto dspval = builder.CreateLoad(inttype, llvmSp); auto dspval = builder.CreateLoad(inttype, llvmSp);
auto inc = builder.CreateAdd(dspval, one); auto inc = builder.CreateAdd(dspval, one);
builder.CreateStore(inc, llvmSp, false); builder.CreateStore(inc, llvmSp, false);
return builder.CreateGEP(stacktype, llvmStack, {zero, dspval}); auto gep = builder.CreateGEP(stacktype, llvmStack, {zero, dspval});
return builder.CreateStore(var, gep);
} }
llvm::Value *LLVMState::createPop() llvm::Value *LLVMState::createPop()
@ -49,13 +50,16 @@ llvm::Value *LLVMState::createPop()
auto dec = builder.CreateSub(dspval, one); auto dec = builder.CreateSub(dspval, one);
builder.CreateStore(dec, llvmSp, false); builder.CreateStore(dec, llvmSp, false);
return builder.CreateGEP(stacktype, llvmStack, {zero, dec}); auto gep = builder.CreateGEP(stacktype, llvmStack, {zero, dec});
return builder.CreateLoad(inttype, gep);
} }
llvm::Function *LLVMState::createFunction(const std::string& name) llvm::Function *LLVMState::createFunction(const std::string& name)
{ {
return llvm::Function::Create(ftype, llvm::Function::ExternalLinkage, auto func = llvm::Function::Create(ftype, llvm::Function::ExternalLinkage,
name.c_str(), modul); name.c_str(), modul);
func->getArg(0)->setName("penv");
return func;
} }
llvm::BasicBlock *LLVMState::createEntry(llvm::Function *func) llvm::BasicBlock *LLVMState::createEntry(llvm::Function *func)

@ -44,7 +44,7 @@ struct LLVMState
LLVMState(); LLVMState();
llvm::Value *createPush(); llvm::Value *createPush(llvm::Value *var);
llvm::Value *createPop(); llvm::Value *createPop();
llvm::Function *createFunction(const std::string& name); llvm::Function *createFunction(const std::string& name);
llvm::BasicBlock *createEntry(llvm::Function *func); llvm::BasicBlock *createEntry(llvm::Function *func);

@ -48,7 +48,17 @@ int main()
} }
} }
auto func = llvmState.createFunction("main");
auto entry = llvmState.createEntry(func);
auto envtype = llvm::VectorType::get(llvmState.inttype, ThunkAST::envidx, false);
auto [t0, _] = Var::lookup("__t0");
llvmState.builder.SetInsertPoint(entry);
auto env = llvmState.builder.CreateAlloca(envtype, nullptr);
llvmState.builder.CreateCall(llvmState.ftype, t0, llvm::ArrayRef<llvm::Value *> {env});
llvmState.builder.CreateRetVoid();
llvmState.output(); llvmState.output();
std::cerr << "envidx: " << ThunkAST::envidx << std::endl;
std::cout << std::endl; std::cout << std::endl;
} }
@ -65,9 +75,6 @@ bool parseString(std::string_view sv)
switch (tok) { switch (tok) {
case Token::ThunkOpen: case Token::ThunkOpen:
if (scope.empty())
scope.emplace_back(llvmState, "main");
else
scope.emplace_back(llvmState); scope.emplace_back(llvmState);
Var::pushScope(); Var::pushScope();
break; break;

@ -10,7 +10,7 @@ void emit()
putchar(*(&stack + --sp)); putchar(*(&stack + --sp));
} }
void print() void _print()
{ {
printf("%d\n", *(&stack + --sp)); printf("%d\n", *(&stack + --sp));
} }

@ -1,56 +1,25 @@
( (
; core utilities ; core utilities
($x ^x ^x) $dup
($_) $drop ($_) $drop
($x $y ^x ^y) $swap ($x $y ^x ^y) $swap
($a $b $c ^b ^a ^c) $rot ($a $b $c ^b ^a ^c) $rot
(sub) $- (sub) $-
(0 swap - -) $+ (0 swap - -) $+
(()) $nil
(nil eq) $null?
($x x) $force ($x x) $force
(32 emit) $bl
(10 emit) $cr (10 emit) $cr
(print) $print
(4 +) $cell+
($a $d 2 alloc $p
^a ^p poke
^d ^p cell+ poke
^p
) $cons
(peek) $car
(cell+ peek) $cdr
; if-stmt ; if-stmt
($c $t $f c ^f ^t rot cswap $_ force) $if ($c $t $f c ^f ^t rot cswap $_ force) $if
($f $t $c $fn ^f ^t ^c fn) $endif ($f $t $c $fn ^f ^t ^c fn) $endif
; range ; range
($self $start $end ($self $fn $start $end
^if (^start ^end eq) ^if (^start ^end eq) ()
^nil (^start fn ^end ^start 1 + ^fn self)
(^start ^end ^start 1 + self swap cons)
endif endif
) $range ) $each
; map [$fn $list -> $out-list] 10 0 ($i 10 0 ($j ^i 48 + emit ^j 48 + emit bl) each) each
($self $fn $list cr
^if (^list null?)
^nil
(^list car fn ^list cdr ^fn self swap cons)
endif
) $map
; each [$fn $list]
($fn (fn ^nil) map drop) $each
; implementation
(0 1 ($self $a $b $n
^if (^n 0 eq) (^b) (
^n 1 - ^a ^b + ^b self
) endif
) force) $fibonacci
10 1 range
^fibonacci map
^print each
) )

@ -17,15 +17,11 @@
*/ */
#include "var.hpp" #include "var.hpp"
#include <list> std::list<std::map<std::string, Var>> Var::vars;
#include <map>
#include <string>
static std::list<std::map<std::string, Var>> llvmVars;
Var Var::lookup(const std::string& name, int skip) Var Var::lookup(const std::string& name, int skip)
{ {
for (auto sc = llvmVars.rbegin(); sc != llvmVars.rend(); ++sc) { for (auto sc = vars.rbegin(); sc != vars.rend(); ++sc) {
if (skip > 0) { if (skip > 0) {
--skip; --skip;
continue; continue;
@ -37,23 +33,28 @@ Var Var::lookup(const std::string& name, int skip)
return {}; return {};
} }
Var Var::lookupLocal(const std::string& name)
{
return vars.back().contains(name) ? vars.back()[name] : Var();
}
void Var::pushScope() void Var::pushScope()
{ {
llvmVars.emplace_back(); vars.emplace_back();
} }
void Var::popScope() void Var::popScope()
{ {
llvmVars.pop_back(); vars.pop_back();
} }
Var& Var::addGlobal(const std::string& name, Var var) Var& Var::addGlobal(const std::string& name, Var var)
{ {
return llvmVars.front().emplace(name, var).first->second; return vars.front().emplace(name, var).first->second;
} }
Var& Var::addLocal(const std::string& name, Var var) Var& Var::addLocal(const std::string& name, Var var)
{ {
return llvmVars.back().emplace(name, var).first->second; return vars.back().emplace(name, var).first->second;
} }

@ -21,14 +21,21 @@
#include <llvm/IR/Type.h> #include <llvm/IR/Type.h>
#include <llvm/IR/DerivedTypes.h> #include <llvm/IR/DerivedTypes.h>
#include <list>
#include <map>
#include <string>
struct Var { struct Var {
llvm::Value *value; llvm::Value *value;
bool callable; bool native;
Var(llvm::Value *v = nullptr, bool n = false):
value(v), native(n) {}
Var(llvm::Value *v = nullptr, bool c = false): static std::list<std::map<std::string, Var>> vars;
value(v), callable(c) {}
static Var lookup(const std::string& name, int skip = 0); static Var lookup(const std::string& name, int skip = 0);
static Var lookupLocal(const std::string& name);
static void pushScope(); static void pushScope();
static void popScope(); static void popScope();
static Var& addGlobal(const std::string& name, Var var); static Var& addGlobal(const std::string& name, Var var);

Loading…
Cancel
Save