#include <charconv>
#include <iostream>
+extern std::list<ThunkAST> scope;
+
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) {}
return nullptr;
} else {
auto val = llvmState.createInt(value);
- return llvmState.builder.CreateStore(val, llvmState.createPush());
+ return llvmState.createPush(val);
}
}
llvm::Value *PushAST::codegen(LLVMState& llvmState) const
{
- if (auto [var, thunk] = Var::lookup(name); var) {
- auto dsget = llvmState.createPush();
- if (!thunk)
- var = llvmState.builder.CreateLoad(llvmState.inttype, var);
+ if (auto [var, native] = Var::lookup(name, 1); var) {
+ auto index = llvm::ConstantInt::get(llvmState.inttype, ThunkAST::envidx++);
+ Var::addLocal(name, index);
+ }
+
+ 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 {
std::cerr << "error: not defined: " << name << std::endl;
return nullptr;
llvm::Value *PopAST::codegen(LLVMState& llvmState) const
{
+ Var v;
+
if (name == "self") {
- extern std::list<ThunkAST> scope;
- auto func = scope.back().func;
- auto var = llvmState.createVariable(name);
- llvmState.builder.CreateStore(func, var, false);
- return Var::addLocal(name, var).value;
+ v = {scope.back().func, true};
} else {
- auto gep = llvmState.createPop();
- auto var = llvmState.createVariable(name);
- auto load = llvmState.builder.CreateLoad(llvmState.inttype, gep);
- llvmState.builder.CreateStore(load, var, false);
+ auto index = llvm::ConstantInt::get(llvmState.inttype, ThunkAST::envidx++);
+ auto pop = llvmState.createPop();
+ storeEnv(llvmState, index, pop);
- return Var::addLocal(name, var).value;
+ v = index;
}
+
+ return Var::addLocal(name, v).value;
}
CallAST::CallAST(const std::string& n): BaseAST(n) {}
llvm::Value *CallAST::codegen(LLVMState& llvmState) const
{
- if (auto [var, call] = Var::lookup(name); var) {
- if (call) {
- return llvmState.builder.CreateCall(llvmState.ftype, var);
- } 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);
- }
+ if (auto [var, native] = Var::lookup(name, 1); var && !native) {
+ auto index = llvm::ConstantInt::get(llvmState.inttype, ThunkAST::envidx++);
+ Var::addLocal(name, index);
+ }
+
+ llvm::Value *fn;
+ if (auto [var, native] = Var::lookup(name); var) {
+ if (!native)
+ var = loadEnv(llvmState, var);
+
+ fn = var;
} else {
std::cerr << "warning: anticipating external function: "
<< name << std::endl;
- auto func = llvmState.createFunction(name);
- Var::addGlobal(name, Var {func, true});
- return llvmState.builder.CreateCall(llvmState.ftype, func);
+
+ fn = llvmState.createFunction(name);
+ 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):
{
parent = llvmState.builder.saveIP();
func = llvmState.createFunction(name);
- auto BB = llvmState.createEntry(func);
- llvmState.builder.SetInsertPoint(BB);
+ entry = llvmState.createEntry(func);
+ 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
{
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;
}
modul("forsp", ctx),
builder(ctx),
inttype(llvm::Type::getInt32Ty(ctx)),
- stacktype(llvm::VectorType::get(inttype, 12, false)),
- ftype(llvm::FunctionType::get(llvm::Type::getVoidTy(ctx), {}, false)),
+ stacktype(llvm::VectorType::get(inttype, 16, false)),
+ ftype(llvm::FunctionType::get(llvm::Type::getVoidTy(ctx), llvm::ArrayRef<llvm::Type *> {inttype->getPointerTo()}, false)),
one(llvm::ConstantInt::get(inttype, 1)),
zero(llvm::ConstantInt::get(inttype, 0))
{
llvm::GlobalValue::ExternalLinkage, zerovec, "stack");
}
-llvm::Value *LLVMState::createPush()
+llvm::Value *LLVMState::createPush(llvm::Value *var)
{
auto dspval = builder.CreateLoad(inttype, llvmSp);
auto inc = builder.CreateAdd(dspval, one);
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()
auto dec = builder.CreateSub(dspval, one);
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)
{
- return llvm::Function::Create(ftype, llvm::Function::ExternalLinkage,
+ auto func = llvm::Function::Create(ftype, llvm::Function::ExternalLinkage,
name.c_str(), modul);
+ func->getArg(0)->setName("penv");
+ return func;
}
llvm::BasicBlock *LLVMState::createEntry(llvm::Function *func)