1
0
mirror of https://github.com/exaloop/codon.git synced 2025-06-03 15:03:52 +08:00
codon/codon/compiler/jit.cpp
Ibrahim Numanagić 9c8424275e
Fix broken merge
2021-12-12 11:36:30 -08:00

180 lines
6.1 KiB
C++

#include "jit.h"
#include "codon/parser/peg/peg.h"
#include "codon/parser/visitors/doc/doc.h"
#include "codon/parser/visitors/format/format.h"
#include "codon/parser/visitors/simplify/simplify.h"
#include "codon/parser/visitors/translate/translate.h"
#include "codon/parser/visitors/typecheck/typecheck.h"
#include "codon/runtime/lib.h"
namespace codon {
namespace jit {
namespace {
typedef int MainFunc(int, char **);
typedef void InputFunc();
const std::string JIT_FILENAME = "<jit>";
} // namespace
JIT::JIT(const std::string &argv0, const std::string &mode)
: compiler(std::make_unique<Compiler>(argv0, /*debug=*/true)), mode(mode) {
if (auto e = Engine::create()) {
engine = std::move(e.get());
} else {
engine = {};
seqassert(false, "JIT engine creation error");
}
compiler->getLLVMVisitor()->setJIT(true);
}
llvm::Error JIT::init() {
auto *cache = compiler->getCache();
auto *module = compiler->getModule();
auto *pm = compiler->getPassManager();
auto *llvisitor = compiler->getLLVMVisitor();
auto transformed = ast::SimplifyVisitor::apply(
cache, std::make_shared<ast::SuiteStmt>(), JIT_FILENAME, {});
auto typechecked = ast::TypecheckVisitor::apply(cache, std::move(transformed));
ast::TranslateVisitor::apply(cache, std::move(typechecked));
cache->isJit = true; // we still need main(), so set isJit after it has been set
module->setSrcInfo({JIT_FILENAME, 0, 0, 0});
pm->run(module);
module->accept(*llvisitor);
auto pair = llvisitor->takeModule();
if (auto err = engine->addModule({std::move(pair.first), std::move(pair.second)}))
return err;
auto func = engine->lookup("main");
if (auto err = func.takeError())
return err;
auto *main = (MainFunc *)func->getAddress();
(*main)(0, nullptr);
return llvm::Error::success();
}
llvm::Expected<std::string> JIT::run(const ir::Func *input,
const std::vector<ir::Var *> &newGlobals) {
auto *module = compiler->getModule();
auto *pm = compiler->getPassManager();
auto *llvisitor = compiler->getLLVMVisitor();
pm->run(module);
const std::string name = ir::LLVMVisitor::getNameForFunction(input);
llvisitor->registerGlobal(input);
for (auto *var : newGlobals) {
llvisitor->registerGlobal(var);
}
for (auto *var : newGlobals) {
if (auto *func = ir::cast<ir::Func>(var))
func->accept(*llvisitor);
}
input->accept(*llvisitor);
auto pair = llvisitor->takeModule();
if (auto err = engine->addModule({std::move(pair.first), std::move(pair.second)}))
return std::move(err);
auto func = engine->lookup(name);
if (auto err = func.takeError())
return std::move(err);
auto *repl = (InputFunc *)func->getAddress();
try {
(*repl)();
} catch (const JITError &e) {
std::vector<std::string> backtrace;
for (auto pc : e.getBacktrace()) {
auto line = engine->getDebugListener()->getPrettyBacktrace(pc);
if (line && !line->empty())
backtrace.push_back(*line);
}
return llvm::make_error<error::RuntimeErrorInfo>(e.getOutput(), e.getType(),
e.what(), e.getFile(), e.getLine(),
e.getCol(), backtrace);
}
return getCapturedOutput();
}
llvm::Expected<std::string> JIT::exec(const std::string &code) {
auto *cache = compiler->getCache();
ast::StmtPtr node = ast::parseCode(cache, JIT_FILENAME, code, /*startLine=*/0);
auto sctx = cache->imports[MAIN_IMPORT].ctx;
auto preamble = std::make_shared<ast::SimplifyVisitor::Preamble>();
ast::Cache bCache = *cache;
ast::SimplifyContext bSimplify = *sctx;
ast::TypeContext bType = *(cache->typeCtx);
ast::TranslateContext bTranslate = *(cache->codegenCtx);
try {
auto *e = node->getSuite()
? const_cast<ast::SuiteStmt *>(node->getSuite())->lastInBlock()
: &node;
if (e)
if (auto ex = const_cast<ast::ExprStmt *>((*e)->getExpr())) {
*e = std::make_shared<ast::IfStmt>(
std::make_shared<ast::CallExpr>(std::make_shared<ast::IdExpr>("isinstance"),
ex->expr->clone(),
std::make_shared<ast::IdExpr>("void")),
ex->clone(),
std::make_shared<ast::ExprStmt>(std::make_shared<ast::CallExpr>(
std::make_shared<ast::IdExpr>("_jit_display"), ex->expr->clone(),
std::make_shared<ast::StringExpr>(mode))));
}
auto s = ast::SimplifyVisitor(sctx, preamble).transform(node);
auto simplified = std::make_shared<ast::SuiteStmt>();
for (auto &s : preamble->globals)
simplified->stmts.push_back(s);
for (auto &s : preamble->functions)
simplified->stmts.push_back(s);
simplified->stmts.push_back(s);
// TODO: unroll on errors...
auto *cache = compiler->getCache();
auto typechecked = ast::TypecheckVisitor::apply(cache, simplified);
std::vector<std::string> globalNames;
for (auto &g : cache->globals) {
if (!g.second)
globalNames.push_back(g.first);
}
// add newly realized functions
std::vector<ast::StmtPtr> v;
std::vector<ir::Func **> frs;
v.push_back(typechecked);
for (auto &p : cache->pendingRealizations) {
v.push_back(cache->functions[p.first].ast);
frs.push_back(&cache->functions[p.first].realizations[p.second]->ir);
}
auto func =
ast::TranslateVisitor::apply(cache, std::make_shared<ast::SuiteStmt>(v, false));
cache->jitCell++;
std::vector<ir::Var *> globalVars;
for (auto &g : globalNames) {
seqassert(cache->globals[g], "JIT global {} not set", g);
globalVars.push_back(cache->globals[g]);
}
for (auto &i : frs) {
seqassert(*i, "JIT fn not set");
globalVars.push_back(*i);
}
return run(func, globalVars);
} catch (const exc::ParserException &e) {
*cache = bCache;
*(cache->imports[MAIN_IMPORT].ctx) = bSimplify;
*(cache->typeCtx) = bType;
*(cache->codegenCtx) = bTranslate;
return llvm::make_error<error::ParserErrorInfo>(e);
}
}
} // namespace jit
} // namespace codon