Jupyter quanto fixes (#22)

* Add methods to check for passes/analyses

* Fix xeus build

* clang-format

* Optimize JIT

* Allow jit mode to take data from file

* Fix OpenMP in JIT mode

* Update JIT main

* Update cloning

Co-authored-by: Ibrahim Numanagić <ibrahimpasa@gmail.com>
pull/27/head
A. R. Shajii 2022-03-19 10:29:41 -04:00 committed by GitHub
parent 8bffbc88a5
commit b47a9a844b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 130 additions and 45 deletions

View File

@ -155,7 +155,8 @@ if(CODON_JUPYTER)
OPTIONS "BUILD_EXAMPLES OFF" OPTIONS "BUILD_EXAMPLES OFF"
"XEUS_BUILD_SHARED_LIBS OFF" "XEUS_BUILD_SHARED_LIBS OFF"
"XEUS_STATIC_DEPENDENCIES ON" "XEUS_STATIC_DEPENDENCIES ON"
"CMAKE_POSITION_INDEPENDENT_CODE ON") "CMAKE_POSITION_INDEPENDENT_CODE ON"
"XEUS_DISABLE_ARCH_NATIVE ON")
if (xeus_ADDED) if (xeus_ADDED)
install(TARGETS nlohmann_json EXPORT xeus-targets) install(TARGETS nlohmann_json EXPORT xeus-targets)
endif() endif()

View File

@ -207,9 +207,26 @@ std::string jitExec(codon::jit::JIT *jit, const std::string &code) {
} }
return *result; return *result;
} }
void jitLoop(codon::jit::JIT *jit, std::istream &fp) {
std::string code;
for (std::string line; std::getline(fp, line);) {
if (line != "#%%") {
code += line + "\n";
} else {
fmt::print("{}[done]\n", jitExec(jit, code));
code = "";
fflush(stdout);
}
}
if (!code.empty())
fmt::print("{}[done]\n", jitExec(jit, code));
}
} // namespace } // namespace
int jitMode(const std::vector<const char *> &args) { int jitMode(const std::vector<const char *> &args) {
llvm::cl::opt<std::string> input(llvm::cl::Positional, llvm::cl::desc("<input file>"),
llvm::cl::init("-"));
llvm::cl::list<std::string> plugins("plugin", llvm::cl::list<std::string> plugins("plugin",
llvm::cl::desc("Load specified plugin")); llvm::cl::desc("Load specified plugin"));
llvm::cl::opt<std::string> log("log", llvm::cl::desc("Enable given log streams")); llvm::cl::opt<std::string> log("log", llvm::cl::desc("Enable given log streams"));
@ -233,18 +250,12 @@ int jitMode(const std::vector<const char *> &args) {
llvm::cantFail(jit.init()); llvm::cantFail(jit.init());
fmt::print(">>> Codon JIT v{} <<<\n", CODON_VERSION); fmt::print(">>> Codon JIT v{} <<<\n", CODON_VERSION);
std::string code; if (input == "-") {
for (std::string line; std::getline(std::cin, line);) { jitLoop(&jit, std::cin);
if (line != "#%%") {
code += line + "\n";
} else { } else {
fmt::print("{}[done]\n", jitExec(&jit, code)); std::ifstream fileInput(input);
code = ""; jitLoop(&jit, fileInput);
fflush(stdout);
} }
}
if (!code.empty())
fmt::print("{}[done]\n", jitExec(&jit, code));
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -15,7 +15,7 @@ llvm::Expected<llvm::orc::ThreadSafeModule>
Engine::optimizeModule(llvm::orc::ThreadSafeModule module, Engine::optimizeModule(llvm::orc::ThreadSafeModule module,
const llvm::orc::MaterializationResponsibility &R) { const llvm::orc::MaterializationResponsibility &R) {
module.withModuleDo([](llvm::Module &module) { module.withModuleDo([](llvm::Module &module) {
ir::optimize(&module, /*debug=*/true, /*jit=*/true); ir::optimize(&module, /*debug=*/false, /*jit=*/true);
}); });
return std::move(module); return std::move(module);
} }

View File

@ -1067,7 +1067,6 @@ void SimplifyVisitor::visit(ClassStmt *stmt) {
seqassert(c, "not a class AST for {}", canonicalName); seqassert(c, "not a class AST for {}", canonicalName);
preamble->globals.push_back(c->clone()); preamble->globals.push_back(c->clone());
c->suite = clone(suite); c->suite = clone(suite);
} }
stmts[0] = N<ClassStmt>(canonicalName, std::vector<Param>{}, N<SuiteStmt>(), stmts[0] = N<ClassStmt>(canonicalName, std::vector<Param>{}, N<SuiteStmt>(),
Attr({Attr::Extend}), std::vector<ExprPtr>{}, Attr({Attr::Extend}), std::vector<ExprPtr>{},

View File

@ -109,6 +109,28 @@ public:
explicit PassManager(bool debug = false, std::vector<std::string> disabled = {}) explicit PassManager(bool debug = false, std::vector<std::string> disabled = {})
: PassManager(debug ? Init::DEBUG : Init::RELEASE, std::move(disabled)) {} : PassManager(debug ? Init::DEBUG : Init::RELEASE, std::move(disabled)) {}
/// Checks if the given pass is included in this manager.
/// @param key the pass key
/// @return true if manager has the given pass
bool hasPass(const std::string &key) {
for (auto &pair : passes) {
if (pair.first == key)
return true;
}
return false;
}
/// Checks if the given analysis is included in this manager.
/// @param key the analysis key
/// @return true if manager has the given analysis
bool hasAnalysis(const std::string &key) {
for (auto &pair : analyses) {
if (pair.first == key)
return true;
}
return false;
}
/// Registers a pass and appends it to the execution order. /// Registers a pass and appends it to the execution order.
/// @param pass the pass /// @param pass the pass
/// @param insertBefore insert pass before the pass with this given key /// @param insertBefore insert pass before the pass with this given key

View File

@ -1,8 +1,61 @@
#include "cloning.h" #include "cloning.h"
#include "codon/sir/util/operator.h"
namespace codon { namespace codon {
namespace ir { namespace ir {
namespace util { namespace util {
namespace {
struct GatherLocals : public util::Operator {
std::vector<Var *> locals;
void preHook(Node *node) override {
for (auto *v : node->getUsedVariables()) {
if (!v->isGlobal())
locals.push_back(v);
}
}
};
} // namespace
Value *CloneVisitor::clone(const Value *other, BodiedFunc *cloneTo) {
if (!other)
return nullptr;
if (cloneTo) {
auto *M = cloneTo->getModule();
GatherLocals gl;
const_cast<Value *>(other)->accept(gl);
for (auto *v : gl.locals) {
auto *clonedVar = M->N<Var>(v, v->getType(), v->isGlobal(), v->getName());
cloneTo->push_back(clonedVar);
forceRemap(v, clonedVar);
}
}
auto id = other->getId();
if (ctx.find(id) == ctx.end()) {
other->accept(*this);
ctx[id] = result;
for (auto it = other->attributes_begin(); it != other->attributes_end(); ++it) {
const auto *attr = other->getAttribute(*it);
if (attr->needsClone()) {
ctx[id]->setAttribute(attr->clone(*this), *it);
}
}
}
return cast<Value>(ctx[id]);
}
Var *CloneVisitor::clone(const Var *other) {
if (!other)
return nullptr;
auto id = other->getId();
if (ctx.find(id) != ctx.end())
return cast<Var>(ctx[id]);
return const_cast<Var *>(other);
}
void CloneVisitor::visit(const Var *v) { void CloneVisitor::visit(const Var *v) {
result = module->N<Var>(v, v->getType(), v->isGlobal(), v->getName()); result = module->N<Var>(v, v->getType(), v->isGlobal(), v->getName());

View File

@ -12,7 +12,7 @@ private:
/// the clone context /// the clone context
std::unordered_map<int, Node *> ctx; std::unordered_map<int, Node *> ctx;
/// the result /// the result
Node *result = nullptr; Node *result;
/// the module /// the module
Module *module; Module *module;
/// true if break/continue loops should be cloned /// true if break/continue loops should be cloned
@ -22,7 +22,8 @@ public:
/// Constructs a clone visitor. /// Constructs a clone visitor.
/// @param module the module /// @param module the module
/// @param cloneLoop true if break/continue loops should be cloned /// @param cloneLoop true if break/continue loops should be cloned
explicit CloneVisitor(Module *module, bool cloneLoop = true) : module(module) {} explicit CloneVisitor(Module *module, bool cloneLoop = true)
: ctx(), result(nullptr), module(module), cloneLoop(cloneLoop) {}
virtual ~CloneVisitor() noexcept = default; virtual ~CloneVisitor() noexcept = default;
@ -69,38 +70,14 @@ public:
/// Clones a value, returning the previous value if other has already been cloned. /// Clones a value, returning the previous value if other has already been cloned.
/// @param other the original /// @param other the original
/// @param cloneTo the function to clone locals to, or null if none
/// @return the clone /// @return the clone
Value *clone(const Value *other) { Value *clone(const Value *other, BodiedFunc *cloneTo = nullptr);
if (!other)
return nullptr;
auto id = other->getId();
if (ctx.find(id) == ctx.end()) {
other->accept(*this);
ctx[id] = result;
for (auto it = other->attributes_begin(); it != other->attributes_end(); ++it) {
const auto *attr = other->getAttribute(*it);
if (attr->needsClone()) {
ctx[id]->setAttribute(attr->clone(*this), *it);
}
}
}
return cast<Value>(ctx[id]);
}
/// Returns the original unless the variable has been force cloned. /// Returns the original unless the variable has been force cloned.
/// @param other the original /// @param other the original
/// @return the original or the previous clone /// @return the original or the previous clone
Var *clone(const Var *other) { Var *clone(const Var *other);
if (!other)
return nullptr;
auto id = other->getId();
if (ctx.find(id) != ctx.end())
return cast<Var>(ctx[id]);
return const_cast<Var *>(other);
}
/// Clones a flow, returning the previous value if other has already been cloned. /// Clones a flow, returning the previous value if other has already been cloned.
/// @param other the original /// @param other the original

View File

@ -113,8 +113,10 @@ VarValue *makeVar(Value *x, SeriesFlow *flow, BodiedFunc *parent, bool prepend)
const bool global = (parent == nullptr); const bool global = (parent == nullptr);
auto *M = x->getModule(); auto *M = x->getModule();
auto *v = M->Nr<Var>(x->getType(), global); auto *v = M->Nr<Var>(x->getType(), global);
if (global) if (global) {
v->setName("_anon_global"); static int counter = 1;
v->setName("_anon_global_" + std::to_string(counter++));
}
auto *a = M->Nr<AssignInstr>(v, x); auto *a = M->Nr<AssignInstr>(v, x);
if (prepend) { if (prepend) {
flow->insert(flow->begin(), a); flow->insert(flow->begin(), a);

View File

@ -323,23 +323,29 @@ def _fork_call(microtask: cobj, args):
def _static_loop_outline_template(gtid_ptr: Ptr[i32], btid_ptr: Ptr[i32], args): def _static_loop_outline_template(gtid_ptr: Ptr[i32], btid_ptr: Ptr[i32], args):
@nonpure
def _loop_step(): def _loop_step():
return 1 return 1
@nonpure
def _loop_loc_and_gtid( def _loop_loc_and_gtid(
loc_ref: Ptr[Ident], reduction_loc_ref: Ptr[Ident], gtid: int loc_ref: Ptr[Ident], reduction_loc_ref: Ptr[Ident], gtid: int
): ):
pass pass
@nonpure
def _loop_body_stub(i, args): def _loop_body_stub(i, args):
pass pass
@nonpure
def _loop_schedule(): def _loop_schedule():
return (1 << 30) | 35 # nonmonotonic, dynamic chunked return (1 << 30) | 35 # nonmonotonic, dynamic chunked
@nonpure
def _loop_shared_updates(args): def _loop_shared_updates(args):
pass pass
@nonpure
def _loop_reductions(args): def _loop_reductions(args):
pass pass
@ -371,23 +377,29 @@ def _static_loop_outline_template(gtid_ptr: Ptr[i32], btid_ptr: Ptr[i32], args):
def _static_chunked_loop_outline_template(gtid_ptr: Ptr[i32], btid_ptr: Ptr[i32], args): def _static_chunked_loop_outline_template(gtid_ptr: Ptr[i32], btid_ptr: Ptr[i32], args):
@nonpure
def _loop_step(): def _loop_step():
return 1 return 1
@nonpure
def _loop_loc_and_gtid( def _loop_loc_and_gtid(
loc_ref: Ptr[Ident], reduction_loc_ref: Ptr[Ident], gtid: int loc_ref: Ptr[Ident], reduction_loc_ref: Ptr[Ident], gtid: int
): ):
pass pass
@nonpure
def _loop_body_stub(i, args): def _loop_body_stub(i, args):
pass pass
@nonpure
def _loop_schedule(): def _loop_schedule():
return (1 << 30) | 35 # nonmonotonic, dynamic chunked return (1 << 30) | 35 # nonmonotonic, dynamic chunked
@nonpure
def _loop_shared_updates(args): def _loop_shared_updates(args):
pass pass
@nonpure
def _loop_reductions(args): def _loop_reductions(args):
pass pass
@ -425,26 +437,33 @@ def _static_chunked_loop_outline_template(gtid_ptr: Ptr[i32], btid_ptr: Ptr[i32]
def _dynamic_loop_outline_template(gtid_ptr: Ptr[i32], btid_ptr: Ptr[i32], args): def _dynamic_loop_outline_template(gtid_ptr: Ptr[i32], btid_ptr: Ptr[i32], args):
@nonpure
def _loop_step(): def _loop_step():
return 1 return 1
@nonpure
def _loop_loc_and_gtid( def _loop_loc_and_gtid(
loc_ref: Ptr[Ident], reduction_loc_ref: Ptr[Ident], gtid: int loc_ref: Ptr[Ident], reduction_loc_ref: Ptr[Ident], gtid: int
): ):
pass pass
@nonpure
def _loop_body_stub(i, args): def _loop_body_stub(i, args):
pass pass
@nonpure
def _loop_schedule(): def _loop_schedule():
return (1 << 30) | 35 # nonmonotonic, dynamic chunked return (1 << 30) | 35 # nonmonotonic, dynamic chunked
@nonpure
def _loop_shared_updates(args): def _loop_shared_updates(args):
pass pass
@nonpure
def _loop_reductions(args): def _loop_reductions(args):
pass pass
@nonpure
def _loop_ordered(): def _loop_ordered():
return False return False
@ -510,6 +529,7 @@ def _spawn_and_run_task(
# spawns a new task for each loop iteration. # spawns a new task for each loop iteration.
def _task_loop_outline_template(gtid_ptr: Ptr[i32], btid_ptr: Ptr[i32], args): def _task_loop_outline_template(gtid_ptr: Ptr[i32], btid_ptr: Ptr[i32], args):
def _routine_stub(gtid: i32, data: cobj, P: type, S: type): def _routine_stub(gtid: i32, data: cobj, P: type, S: type):
@nonpure
def _task_loop_body_stub(priv, shared): def _task_loop_body_stub(priv, shared):
pass pass