From dd5213fe94ad848f63912d423df35fe5321e5906 Mon Sep 17 00:00:00 2001 From: Chuta Sano Date: Sun, 29 Apr 2018 01:20:55 -0400 Subject: [PATCH] Rough version of closures working! Need to fix some hacky implementations and do further testing --- compile.cpp | 2 + rep/c0.cpp | 63 ++++++++----- rep/c0.h | 34 +++---- rep/r0.cpp | 255 ++++++++++++++++++++++++++++++++------------------ rep/r0.h | 50 ++++++---- rep/type.h | 15 +++ rep/x0.cpp | 4 +- runtime/lib.c | 7 +- test.cpp | 129 +++++++++++++------------ 9 files changed, 332 insertions(+), 227 deletions(-) diff --git a/compile.cpp b/compile.cpp index 4cb7aea..91068df 100644 --- a/compile.cpp +++ b/compile.cpp @@ -28,6 +28,8 @@ static string to_asm(r0::P &p) { p.uniquify(); p.type_check(); + p.lambda_lift(); + p.type_check(true); c0::P c = p.flatten(); x0s::P xs = c.select(); x0::P x0 = xs.assign(); diff --git a/rep/c0.cpp b/rep/c0.cpp index 9b64129..70d4797 100644 --- a/rep/c0.cpp +++ b/rep/c0.cpp @@ -9,7 +9,26 @@ using namespace std; using namespace c0; -static unordered_map count; +// figures out whether to use movq or leaq depending on the type of src +// note that src is a c0::Arg while dst is x0s::Dst +static inline x0s::ISrcDst* x0s_move(const unordered_map &vmap, const Arg* src, x0s::Dst* dst) +{ + bool is_ref; + if (typeid(*src) == typeid(Var)) + { + //is_ref = false; + is_ref = type_is_func(vmap.at(static_cast(src)->name)); + } + else if (typeid(*src) == typeid(GlobalVar)) + { + is_ref = true; + } + else + { + is_ref = false; + } + return new x0s::ISrcDst(is_ref ? LEAQ : MOVQ, src->to_arg(), dst); +} x0s::Arg* Var::to_arg() const { @@ -26,26 +45,19 @@ x0s::Arg* Num::to_arg() const return new x0s::Con(this->value); } -list Arg::select(x0s::Var* var) +list Arg::select(const unordered_map &vmap, x0s::Var* var) { // moving globals should be done as lea because globals are always // memory locations - if (typeid(*this) == typeid(GlobalVar)) - { - return { new x0s::ISrcDst(LEAQ, this->to_arg(), var) }; - } - else - { - return { new x0s::ISrcDst(MOVQ, this->to_arg(), var) }; - } + return { x0s_move(vmap, this, var) }; } -list Read::select(x0s::Var* var) +list Read::select(const unordered_map &vmap, x0s::Var* var) { return { new x0s::ICall(new x0s::Global("_lang_read_num"), { }, var) }; } -list Binop::select(x0s::Var* var) +list Binop::select(const unordered_map &vmap, x0s::Var* var) { switch(this->op) { @@ -83,7 +95,7 @@ list Binop::select(x0s::Var* var) } } -list Unop::select(x0s::Var* var) +list Unop::select(const unordered_map &vmap, x0s::Var* var) { switch(this->op) { @@ -99,7 +111,7 @@ list Unop::select(x0s::Var* var) }; } -list FunCall::select(x0s::Var* var) +list FunCall::select(const unordered_map &vmap, x0s::Var* var) { vector x0sargs; for (auto a : args) @@ -109,7 +121,7 @@ list FunCall::select(x0s::Var* var) return { new x0s::ICall(func->to_arg(), x0sargs, var) }; } -list Alloc::select(x0s::Var* var) +list Alloc::select(const unordered_map &vmap, x0s::Var* var) { int total_size = 8*(1+size); // TODO abstractify this a bit more to reuse code @@ -126,27 +138,26 @@ list Alloc::select(x0s::Var* var) new x0s::ISrcDst(ADDQ, new x0s::Con(total_size), new x0s::Reg("r15")) }; } -list VecRef::select(x0s::Var* var) +list VecRef::select(const unordered_map &vmap, x0s::Var* var) { return { new x0s::ISrcDst(MOVQ, vec->to_arg(), new x0s::Reg("r8")), new x0s::ISrcDst(MOVQ, new x0s::Deref(new x0s::Reg("r8"), 8*(1+index)), var) }; } -list VecSet::select(x0s::Var* var) +list VecSet::select(const unordered_map &vmap, x0s::Var* var) { return { new x0s::ISrcDst(MOVQ, vec->to_arg(), new x0s::Reg("r8")), - new x0s::ISrcDst(MOVQ, asg->to_arg(), - new x0s::Deref(new x0s::Reg("r8"), 8*(1+index))), + x0s_move(vmap, asg, new x0s::Deref(new x0s::Reg("r8"), 8*(1+index))), + //new x0s::ISrcDst(MOVQ, asg->to_arg(), new x0s::ISrcDst(MOVQ, new x0s::Con(TV_VOID), var) }; } -list S::select() +list S::select(const unordered_map &vmap) { - return this->e->select(new x0s::Var(this->v)); + return this->e->select(vmap, new x0s::Var(this->v)); } - -list If::select() +list If::select(const unordered_map &vmap) { x0s::Dst* var = new x0s::Reg("rax"); // TODO? x0s::Var* tv = new x0s::Var(this->v); @@ -179,7 +190,7 @@ list If::select() list elsei; for (auto s : elses) { - list is = s->select(); + list is = s->select(vmap); elsei.splice(elsei.end(), is); } elsei.push_back(new x0s::ISrcDst(MOVQ, elsev->to_arg(), tv)); @@ -189,7 +200,7 @@ list If::select() list theni; for (auto s : thens) { - list is = s->select(); + list is = s->select(vmap); theni.splice(theni.end(), is); } theni.push_back(new x0s::ISrcDst(MOVQ, thenv->to_arg(), tv)); @@ -202,7 +213,7 @@ x0s::F F::select() const list instrs; for (auto s : this->stmts) { - list is = s->select(); + list is = s->select(vars); instrs.splice(instrs.end(), is); } instrs.push_back(new x0s::IRet(this->arg->to_arg())); diff --git a/rep/c0.h b/rep/c0.h index 84fe387..30f371e 100644 --- a/rep/c0.h +++ b/rep/c0.h @@ -3,6 +3,7 @@ #include #include #include +#include #include "operators.h" #include "type.h" @@ -13,13 +14,13 @@ namespace c0 struct E { virtual ~E() { } - virtual std::list select(x0s::Var*) = 0; + virtual std::list select(const std::unordered_map&, x0s::Var*) = 0; }; struct Arg : E { virtual ~Arg() { } - std::list select(x0s::Var*); + std::list select(const std::unordered_map&, x0s::Var*) override; virtual x0s::Arg* to_arg() const = 0; }; @@ -44,25 +45,18 @@ namespace c0 x0s::Arg* to_arg() const; }; - struct Global : Arg - { - Global(std::string varname) : name(varname) { } - std::string name; - x0s::Arg* to_arg() const; - }; - // abstract statement either contains an if or a statement struct AS { virtual ~AS() { } - virtual std::list select() = 0; + virtual std::list select(const std::unordered_map&) = 0; }; struct Read : E { Read() { } - std::list select(x0s::Var*); + std::list select(const std::unordered_map&, x0s::Var*) override; }; struct Binop : E @@ -72,7 +66,7 @@ namespace c0 b_ops op; Arg* l; Arg* r; - std::list select(x0s::Var*); + std::list select(const std::unordered_map&, x0s::Var*) override; }; struct Unop : E @@ -81,7 +75,7 @@ namespace c0 ~Unop() { delete v; } u_ops op; Arg* v; - std::list select(x0s::Var*); + std::list select(const std::unordered_map&, x0s::Var*) override; }; struct FunCall : E @@ -90,7 +84,7 @@ namespace c0 ~FunCall() { for (auto a : args) delete a; } Arg* func; std::vector args; - std::list select(x0s::Var*); + std::list select(const std::unordered_map&, x0s::Var*) override; }; struct Alloc : E @@ -98,7 +92,7 @@ namespace c0 Alloc(int size, int tag) : size(size), tag(tag) { } int size; int tag; - std::list select(x0s::Var*); + std::list select(const std::unordered_map&, x0s::Var*) override; }; struct VecRef : E @@ -107,7 +101,7 @@ namespace c0 ~VecRef() { delete vec; } Var* vec; int index; - std::list select(x0s::Var*); + std::list select(const std::unordered_map&, x0s::Var*) override; }; struct VecSet : E @@ -117,7 +111,7 @@ namespace c0 Var* vec; int index; Arg* asg; - std::list select(x0s::Var*); + std::list select(const std::unordered_map&, x0s::Var*) override; }; //stmt @@ -127,7 +121,7 @@ namespace c0 ~S() { delete e; } std::string v; E* e; - std::list select(); + std::list select(const std::unordered_map&); }; struct If : AS @@ -141,7 +135,7 @@ namespace c0 std::vector elses; Arg* thenv; Arg* elsev; - std::list select(); + std::list select(const std::unordered_map&); }; struct F @@ -159,7 +153,7 @@ namespace c0 Arg* arg; //ret int t; x0s::F select() const; - }; + }; struct P { diff --git a/rep/r0.cpp b/rep/r0.cpp index 522ec23..6b69cd4 100644 --- a/rep/r0.cpp +++ b/rep/r0.cpp @@ -238,6 +238,14 @@ bool P::is_unique() const return true; } +void P::lambda_lift() +{ + for (F &f : funcs) + { + f.lambda_lift(); + } +} + c0::P P::flatten() const { vector cfs; @@ -250,14 +258,17 @@ c0::P P::flatten() const return c0::P(cfs, to_run, heap_size); } -void P::type_check() +void P::type_check(bool force) { - if (t == TUNKNOWN) + if ((t == TUNKNOWN) || force) { - vec_type.clear(); - fun_type.clear(); - vec_type[TVEC] = { }; - fun_type[TFUN] = { }; + if (t == TUNKNOWN) + { + vec_type.clear(); + fun_type.clear(); + vec_type[TVEC] = { }; + fun_type[TFUN] = { }; + } unordered_map vmap; for (F &f : funcs) { @@ -265,8 +276,11 @@ void P::type_check() } for (F &f : funcs) { - f.type_check(vmap); - t = fun_type.at(f.t).back(); + f.type_check(vmap, force); + if (f.name == to_run) + { + t = fun_type.at(f.t).back(); + } } } } @@ -326,6 +340,11 @@ bool F::is_unique() const return varnames.size() == uniquenames.size(); } +void F::lambda_lift() +{ + e = e->lambda_lift(v2type); +} + // P is expected to feed in an empty vector void F::flatten(vector &c0fs) const { @@ -365,29 +384,30 @@ void F::generate_fun_type(unordered_map &vars) } ftype.push_back(t); t = add_ftype(ftype); - vars[name] = t; } + vars[name] = t; } -void F::type_check(unordered_map vars) +void F::type_check(unordered_map vars, bool force) { + vars[name] = t; for (const Var &v : args) { vars[v.name] = v.t; } - int t_expected = e->t_check(vars); - if (fun_type.at(t).back() == TUNKNOWN) + int t_expected = e->t_check(vars, force); + if (fun_type.at(t).back() == TUNKNOWN || force) { vector ftype_cpy = fun_type.at(t); ftype_cpy.back() = t_expected; t = add_ftype(ftype_cpy); - vars[name] = t; } - else if (fun_type.at(t).back() != t_expected) + if (fun_type.at(t).back() != t_expected) { cerr << "F::type_check: expected return type mismatch with calculated type\n"; exit(1); } + v2type = vars; } void F::desugar() @@ -405,7 +425,7 @@ c0::Arg* Num::to_c0(unordered_map &vars, vector &stmts, ve return new c0::Num(this->value); } -int Num::t_check(unordered_map &vmap) +int Num::t_check(unordered_map &vmap, bool force) { t = TNUM; return TNUM; @@ -421,7 +441,7 @@ c0::Arg* Bool::to_c0(unordered_map &vars, vector &stmts, v return new c0::Num(static_cast(this->value)); } -int Bool::t_check(unordered_map &vmap) +int Bool::t_check(unordered_map &vmap, bool force) { t = TBOOL; return TBOOL; @@ -440,7 +460,7 @@ c0::Arg* Read::to_c0(unordered_map &vars, vector &stmts, v return new c0::Var(s); } -int Read::t_check(unordered_map &vmap) +int Read::t_check(unordered_map &vmap, bool force) { t = TNUM; return TNUM; @@ -461,12 +481,12 @@ c0::Arg* Binop::to_c0(unordered_map &vars, vector &stmts, return new c0::Var(s); } -int Binop::t_check(unordered_map &vmap) +int Binop::t_check(unordered_map &vmap, bool force) { - if (t == TUNKNOWN) + if ((t == TUNKNOWN) || force) { - int lt = this->l->t_check(vmap); - int rt = this->r->t_check(vmap); + int lt = this->l->t_check(vmap, force); + int rt = this->r->t_check(vmap, force); if (lt == TERROR || lt == TUNKNOWN || rt == TERROR || rt == TUNKNOWN) { @@ -529,11 +549,11 @@ c0::Arg* Unop::to_c0(unordered_map &vars, vector &stmts, v return new c0::Var(s); } -int Unop::t_check(unordered_map &vmap) +int Unop::t_check(unordered_map &vmap, bool force) { - if (t == TUNKNOWN) + if ((t == TUNKNOWN) || force) { - int vt = this->v->t_check(vmap); + int vt = this->v->t_check(vmap, force); int vt_expected; if (vt == TERROR || vt ==TUNKNOWN) { @@ -588,7 +608,7 @@ void Var::uniquify(unordered_map m) else { cerr << "Uniquify var: var ref DNE: " << this->name << "\n"; - exit(1); + assert(0); } } @@ -597,9 +617,9 @@ c0::Arg* Var::to_c0(unordered_map &vars, vector &stmts, ve return new c0::Var(this->name); } -int Var::t_check(unordered_map &vmap) +int Var::t_check(unordered_map &vmap, bool force) { - if (t == TUNKNOWN) + if ((t == TUNKNOWN) || force) { t = vmap.at(this->name); } @@ -632,9 +652,9 @@ c0::Arg* GlobalVar::to_c0(unordered_map &vars, vector &stm return new c0::GlobalVar(this->name); } -int GlobalVar::t_check(unordered_map &vmap) +int GlobalVar::t_check(unordered_map &vmap, bool force) { - if (t == TUNKNOWN) + if ((t == TUNKNOWN) || force) { if (vmap.find(name) != vmap.end()) { @@ -668,13 +688,37 @@ c0::Arg* Call::to_c0(unordered_map &vars, vector &stmts, v { c0args.push_back(e->to_c0(vars, stmts, c0fs)); } - stmts.push_back(new c0::S(s, new c0::FunCall(func->to_c0(vars, stmts, c0fs), c0args))); + int ft = func->t_check(vars); + if (type_is_func(ft)) + { + stmts.push_back(new c0::S(s, new c0::FunCall(func->to_c0(vars, stmts, c0fs), c0args))); + } + else if (type_is_vec(ft)) + { + // TODO hacky way, let lambda_lift magically handle this case + // TODO super hack to make c0 destructors not double delete. fix properly + c0::Arg* vec = func->to_c0(vars, stmts, c0fs); + c0::Arg* vec2 = func->to_c0(vars, stmts, c0fs); + c0::Arg* vec3 = func->to_c0(vars, stmts, c0fs); + c0args.insert(c0args.begin(), vec); + string svec = gensym("r0CallVec"); + string sfref = gensym("r0CallVecFunRef"); + vars[svec] = func->t; + vars[sfref] = vec_type.at(ft).front(); + stmts.push_back(new c0::S(svec, vec2)); + stmts.push_back(new c0::S(sfref, new c0::VecRef(static_cast(vec3), 0))); + stmts.push_back(new c0::S(s, new c0::FunCall(new c0::Var(sfref), c0args))); + } + else + { + assert(0); + } return new c0::Var(s); } -int Call::t_check(unordered_map &vmap) +int Call::t_check(unordered_map &vmap, bool force) { - if (t == TUNKNOWN) + if ((t == TUNKNOWN) || force) { // no type specifier means that function must exist in our context // (ie: not a function from somewhere else like the runtime library) @@ -683,12 +727,18 @@ int Call::t_check(unordered_map &vmap) { int i = 0; //auto t_vec = fun_type.at(vmap.at(name)); - const auto &t_vec = fun_type.at(func->t_check(vmap)); - assert(args.size() == t_vec.size()-1); + int ft = func->t_check(vmap, force); + bool is_vec = type_is_vec(ft); + if (is_vec) // vecs are OK + { + ft = vec_type.at(func->t_check(vmap, force)).front(); + } + const auto &t_vec = fun_type.at(ft); + assert(args.size() == t_vec.size()-1 - (is_vec? 1 : 0)); for (E* e : args) { - int t_arg = e->t_check(vmap); - assert(t_arg == t_vec.at(i)); + int t_arg = e->t_check(vmap, force); + assert(t_arg == t_vec.at(i + (is_vec? 1 : 0))); i++; } t = t_vec.back(); @@ -697,7 +747,7 @@ int Call::t_check(unordered_map &vmap) { for (E* e : args) { - e->t_check(vmap); + e->t_check(vmap, force); } t = t_tentative; } @@ -731,12 +781,12 @@ c0::Arg* Let::to_c0(unordered_map &vars, vector &stmts, ve return this->be->to_c0(vars, stmts, c0fs); } -int Let::t_check(unordered_map &vmap) +int Let::t_check(unordered_map &vmap, bool force) { - if (t == TUNKNOWN) + if ((t == TUNKNOWN) || force) { - vmap[this->name] = this->ve->t_check(vmap); - t = this->be->t_check(vmap); + vmap[this->name] = this->ve->t_check(vmap, force); + t = this->be->t_check(vmap, force); } return t; } @@ -772,17 +822,17 @@ c0::Arg* If::to_c0(unordered_map &vars, vector &stmts, vec return new c0::Var(s); } -int If::t_check(unordered_map &vmap) +int If::t_check(unordered_map &vmap, bool force) { - if (t == TUNKNOWN) + if ((t == TUNKNOWN) || force) { - if (conde->t_check(vmap) != TBOOL) + if (conde->t_check(vmap, force) != TBOOL) { cerr << "If: cond expression does not have type bool\n"; t = TERROR; } - int thent = thene->t_check(vmap); - int elset = elsee->t_check(vmap); + int thent = thene->t_check(vmap, force); + int elset = elsee->t_check(vmap, force); if (thent == elset) { t = thent; // if both are TERROR, we'll catch it from the ret anyway @@ -822,25 +872,25 @@ c0::Arg* Vector::to_c0(unordered_map &vars, vector &stmts, return new c0::Var(s); } -int Vector::t_check(unordered_map &vmap) +int Vector::t_check(unordered_map &vmap, bool force) { - if (t == TUNKNOWN) + if ((t == TUNKNOWN) || force) { vector types; for (E* e : elist) { - types.push_back(e->t_check(vmap)); + types.push_back(e->t_check(vmap, force)); } t = add_vtype(types); } return t; } -int VectorRef::t_check(unordered_map &vmap) +int VectorRef::t_check(unordered_map &vmap, bool force) { - if (t == TUNKNOWN) + if ((t == TUNKNOWN) || force) { - int t_vec = vec->t_check(vmap); + int t_vec = vec->t_check(vmap, force); vector types = vec_type[t_vec]; t = types[index]; } @@ -856,13 +906,13 @@ c0::Arg* VectorRef::to_c0(unordered_map &vars, vector &stm return new c0::Var(s); } -int VectorSet::t_check(unordered_map &vmap) +int VectorSet::t_check(unordered_map &vmap, bool force) { - if (t == TUNKNOWN) + if ((t == TUNKNOWN) || force) { - int t_vec = vec->t_check(vmap); + int t_vec = vec->t_check(vmap, force); vector types = vec_type[t_vec]; - if(types[index] == asg->t_check(vmap)) + if(types[index] == asg->t_check(vmap, force)) { t = TVOID; } @@ -887,46 +937,55 @@ c0::Arg* VectorSet::to_c0(unordered_map &vars, vector &stm void Lambda::uniquify(unordered_map m) { // manually uniquify function args - for (auto &s : args) + for (Var &v : args) { // overwrite if exists - m[s] = gensym(s); - s = m[s]; + m[v.name] = gensym(v.name); + v.name = m[v.name]; } body->uniquify(m); } -int Lambda::t_check(unordered_map &vmap) +int Lambda::t_check(unordered_map &vmap, bool force) { - if (t == TUNKNOWN) + if ((t == TUNKNOWN) || force) { - for (const string &s : args) + for (const Var &v : args) { - vmap[s] = TTRUSTME; + vmap[v.name] = (v.t == TUNKNOWN) ? TTRUSTME : v.t; } - int ret_t = body->t_check(vmap); + int ret_t = body->t_check(vmap, force); vector this_ftype; - for (const string &s : args) + for (const Var &v : args) { - this_ftype.push_back(vmap.at(s)); + this_ftype.push_back(vmap.at(v.name)); } this_ftype.push_back(ret_t); t = add_ftype(this_ftype); + for (Var &v : args) + { + v.t = vmap.at(v.name); + } } return t; } E* Lambda::lambda_lift(const unordered_map &vars) { - /* // TODO maybe use set in get_vars? + body = body->lambda_lift(vars); list all_vars = body->get_vars(); - sort(all_vars.begin(), all_vars.end()); + vector arg_names; + for(const Var &v : args) + { + arg_names.push_back(v.name); + } + all_vars.sort(); all_vars.erase(unique(all_vars.begin(), all_vars.end()), all_vars.end()); all_vars.erase(remove_if(all_vars.begin(), all_vars.end(), - [this](string s) { - return find(args.begin(), args.end(), s) - != args.end(); }), + [arg_names](string s) { + return find(arg_names.begin(), arg_names.end(), s) + != arg_names.end(); }), all_vars.end()); bool enable_closure = all_vars.size() > 0; //all_vars contain all variables that need to be captured in f @@ -937,7 +996,6 @@ E* Lambda::lambda_lift(const unordered_map &vars) ft.insert(ft.begin(), TTRUSTME); int new_t = add_ftype(ft); // reserve a spot in ftype // to_c0 is post type check so TTRUSTME must be unique - // vector should consist of (Func, capture1, capture2, ...) vector vt = {new_t}; for (const string &s : all_vars) @@ -945,26 +1003,38 @@ E* Lambda::lambda_lift(const unordered_map &vars) vt.push_back(vars.at(s)); } int new_vec_t = add_vtype(vt); - fun_at.at(new_t).front() = new_vec_t; - // TODO NOT CONST - // fix up to_c0 - string vector_name = gensym(s+"closure_vec"); - Var* v_local_vector = new Vector(vector_name, new_vec_t); - fargs.insert(fargs.begin(), *v_local_vector); - fargs.emplace(fargs.begin(), vector_name, new_vec_t); - E* prev_ref = body; - int i=0; - // note: the vector_refs will be in reverse order, but - // it shouldn't matter?? maybe revisit this - for (const string &s : all_vars) + fun_type.at(new_t).front() = new_vec_t; + t = new_t; + { + // types are now complete, we need to now modify the current function + // and wrap it with lets to capture the variables + // arbitrary new function arg name + string vector_name = gensym("r0Lambdaclosure_vec"); + Var* vec_var = new Var(vector_name, new_vec_t); + args.insert(args.begin(), Var(vector_name, new_vec_t)); + E* prev_ref = body; + int i=1; + for (const string &s : all_vars) + { + // note: the vector_refs will be in reverse order, but + // it shouldn't matter?? maybe revisit this + prev_ref = new Let(s, new VectorRef(vec_var, i), prev_ref); + i++; + } + body = prev_ref; + } { - prev_ref = new Let(s, new VectorRef(v_local_vector, i), prev_ref); - i++; + // lambda is called after uniquify, so we can't have conflicting names + list vec_elements = { this }; + for (const string &s : all_vars) + { + vec_elements.push_back(new Var(s, vars.at(s))); + } + Vector* v = new Vector(vec_elements); + v->t = new_vec_t; + return v; } - body = prev_ref; - int new_type = add_ftype(ft); } - */ return this; } @@ -972,15 +1042,14 @@ c0::Arg* Lambda::to_c0(unordered_map &vars, vector &stmts, { string s = gensym("r0Lambda"); - vars[s] = t; std::vector fargs; const vector &ft = fun_type.at(t); int i=0; - for (const string &s : args) + for (const Var &v : args) { - fargs.emplace_back(s, ft.at(i)); + fargs.emplace_back(v.name, ft.at(i)); i++; } F f(s, fargs, t, body); @@ -995,7 +1064,7 @@ void Sugar::uniquify(unordered_map a) exit(10); } -int Sugar::t_check(unordered_map &a) +int Sugar::t_check(unordered_map &a, bool force) { cerr << "Call desugar before using any r0->c0 functionality\n"; exit(10); diff --git a/rep/r0.h b/rep/r0.h index f50d7ff..8407aad 100644 --- a/rep/r0.h +++ b/rep/r0.h @@ -19,7 +19,7 @@ namespace r0 virtual std::list > get_childs() = 0; virtual std::list get_vars(); virtual void uniquify(std::unordered_map); - virtual int t_check(std::unordered_map&) = 0; + virtual int t_check(std::unordered_map&, bool force = false) = 0; virtual E* lambda_lift(const std::unordered_map&); virtual c0::Arg* to_c0(std::unordered_map &vars, std::vector &stmts, @@ -36,7 +36,7 @@ namespace r0 Num(int64_t v) { value = v; } int64_t value; std::list > get_childs() { return {}; } - int t_check(std::unordered_map&); + int t_check(std::unordered_map&, bool force = false); c0::Arg* to_c0(std::unordered_map &vars, std::vector &stmts, std::vector &c0fs) const; @@ -48,7 +48,7 @@ namespace r0 Bool(tbool v) { value = v; } tbool value; std::list > get_childs() { return {}; } - int t_check(std::unordered_map&); + int t_check(std::unordered_map&, bool force = false); c0::Arg* to_c0(std::unordered_map &vars, std::vector &stmts, std::vector &c0fs) const; @@ -59,7 +59,7 @@ namespace r0 { Read() { } std::list > get_childs() { return {}; } - int t_check(std::unordered_map&); + int t_check(std::unordered_map&, bool force = false); c0::Arg* to_c0(std::unordered_map &vars, std::vector &stmts, std::vector &c0fs) const; @@ -73,7 +73,7 @@ namespace r0 E* l; E* r; std::list > get_childs() { return {l, r}; } - int t_check(std::unordered_map&); + int t_check(std::unordered_map&, bool force = false); c0::Arg* to_c0(std::unordered_map &vars, std::vector &stmts, std::vector &c0fs) const; @@ -86,7 +86,7 @@ namespace r0 u_ops op; E* v; std::list > get_childs() { return {v}; } - int t_check(std::unordered_map&); + int t_check(std::unordered_map&, bool force = false); c0::Arg* to_c0(std::unordered_map &vars, std::vector &stmts, std::vector &c0fs) const; @@ -101,7 +101,7 @@ namespace r0 std::list > get_childs() { return {}; } std::list get_vars() override { return {name}; } void uniquify(std::unordered_map) override; - int t_check(std::unordered_map&); + int t_check(std::unordered_map&, bool force = false); c0::Arg* to_c0(std::unordered_map &vars, std::vector &stmts, std::vector &c0fs) const; @@ -115,7 +115,7 @@ namespace r0 std::string name; std::list > get_childs() { return {}; } void uniquify(std::unordered_map) override; - int t_check(std::unordered_map&); + int t_check(std::unordered_map&, bool force = false); c0::Arg* to_c0(std::unordered_map &vars, std::vector &stmts, std::vector &c0fs) const; @@ -144,7 +144,7 @@ namespace r0 // initialization on type_check, so t has to remain TUNKNOWN until // type_check runs at least once type t_tentative; - int t_check(std::unordered_map&); + int t_check(std::unordered_map&, bool force = false); c0::Arg* to_c0(std::unordered_map &vars, std::vector &stmts, std::vector &c0fs) const; @@ -159,7 +159,7 @@ namespace r0 E* be; std::list > get_childs() { return {ve, be}; } void uniquify(std::unordered_map) override; - int t_check(std::unordered_map&); + int t_check(std::unordered_map&, bool force = false); c0::Arg* to_c0(std::unordered_map &vars, std::vector &stmts, std::vector &c0fs) const; @@ -173,7 +173,7 @@ namespace r0 E* thene; E* elsee; std::list > get_childs() { return { conde, thene, elsee}; } - int t_check(std::unordered_map&); + int t_check(std::unordered_map&, bool force = false); c0::Arg* to_c0(std::unordered_map &vars, std::vector &stmts, std::vector &c0fs) const; @@ -186,7 +186,7 @@ namespace r0 std::list elist; std::list > get_childs() { return std::list >(elist.begin(), elist.end()); } - int t_check(std::unordered_map&); + int t_check(std::unordered_map&, bool force = false); c0::Arg* to_c0(std::unordered_map &vars, std::vector &stmts, std::vector &c0fs) const; @@ -201,7 +201,7 @@ namespace r0 E* vec; int index; std::list > get_childs() { return { vec }; } - int t_check(std::unordered_map&); + int t_check(std::unordered_map&, bool force = false); c0::Arg* to_c0(std::unordered_map &vars, std::vector &stmts, std::vector &c0fs) const; @@ -215,7 +215,7 @@ namespace r0 int index; E* asg; std::list > get_childs() { return { vec, asg }; } - int t_check(std::unordered_map&); + int t_check(std::unordered_map&, bool force = false); c0::Arg* to_c0(std::unordered_map &vars, std::vector &stmts, std::vector &c0fs) const; @@ -224,12 +224,19 @@ namespace r0 struct Lambda : E { - Lambda(std::vector args, E* body) : args(args), body(body) { } - std::vector args; + Lambda(std::vector args, E* body) : args(args), body(body) { } + Lambda(std::vector args, E* body) : body(body) + { + for (const std::string &s : args) + { + this->args.emplace_back(s); + } + } + std::vector args; E* body; std::list > get_childs() { return { body }; } void uniquify(std::unordered_map m) override; - int t_check(std::unordered_map&); + int t_check(std::unordered_map&, bool force = false); E* lambda_lift(const std::unordered_map&) override; c0::Arg* to_c0(std::unordered_map &vars, std::vector &stmts, @@ -242,7 +249,7 @@ namespace r0 struct Sugar : E { void uniquify(std::unordered_map) override; - int t_check(std::unordered_map&) override; + int t_check(std::unordered_map&, bool force = false) override; E* lambda_lift(const std::unordered_map&) override; c0::Arg* to_c0(std::unordered_map &vars, std::vector &stmts, @@ -265,14 +272,16 @@ namespace r0 F(const F &obj); std::string name; std::vector args; + std::unordered_map v2type; int t; E* e; F clone() const; void deep_delete() { this->e->deep_delete(); delete this->e; } bool is_unique() const; void uniquify(std::unordered_map); - void type_check(std::unordered_map vars); + void type_check(std::unordered_map vars, bool force = false); void generate_fun_type(std::unordered_map &vars); + void lambda_lift(); void flatten(std::vector &c0fs) const; void desugar(); }; @@ -289,7 +298,8 @@ namespace r0 void deep_delete(); bool is_unique() const; void uniquify(); - void type_check(); + void type_check(bool force = false); + void lambda_lift(); c0::P flatten() const; void desugar(); }; diff --git a/rep/type.h b/rep/type.h index e94fc87..95bbd70 100644 --- a/rep/type.h +++ b/rep/type.h @@ -31,6 +31,21 @@ enum tvoid TV_VOID = 0 }; +inline bool type_is_func(int t) +{ + return t > TFUN; +} + +inline bool type_is_vec(int t) +{ + return (t < TFUN) && (t > TVEC); +} + +inline bool type_is_ref(int t) +{ + return type_is_func(t) || type_is_vec(t); +} + inline std::string type2name(int n) { switch(n) diff --git a/rep/x0.cpp b/rep/x0.cpp index e11b8be..0f1b6df 100644 --- a/rep/x0.cpp +++ b/rep/x0.cpp @@ -179,7 +179,7 @@ void P::fix() i->dst = new Reg("rax"); it = this->instr.insert(++it, new ISrcDst(MOVQ, i->dst, local_dst)); } - if (i->instr == LEAQ && + else if (i->instr == LEAQ && typeid(*(i->src)) == typeid(Global) && typeid(*(i->dst)) == typeid(Mem)) { @@ -189,7 +189,7 @@ void P::fix() it = this->instr.insert(it, leaq); } // we need to fix two args both being memory references - else if (typeid(*(i->src)) == typeid(Mem) && + else if ((typeid(*(i->src)) == typeid(Mem) || typeid(*(i->src)) == typeid(Global)) && typeid(*(i->dst)) == typeid(Mem)) { ISrcDst* movq = new ISrcDst(MOVQ, i->src, new Reg("rax")); diff --git a/runtime/lib.c b/runtime/lib.c index eebed47..97635a2 100644 --- a/runtime/lib.c +++ b/runtime/lib.c @@ -12,6 +12,7 @@ extern int64_t _LANG_NUM_T; extern int64_t _LANG_BOOL_T; extern int64_t _LANG_VOID_T; extern int64_t _LANG_VEC_T; +extern int64_t _LANG_FUN_T; void* _LANG_HEAP_END; static void* buf; @@ -188,10 +189,14 @@ void _lang_print_vec(int64_t* start) { _lang_print_void_impl(start[i], 0); } - else + else if ((tag[i] > _LANG_VEC_T) && (tag[i] < _LANG_FUN_T)) { _lang_print_vec(start+i); } + else + { + printf("func "); + } printf(" "); } printf("\n"); diff --git a/test.cpp b/test.cpp index 0e2e147..183b0ba 100644 --- a/test.cpp +++ b/test.cpp @@ -101,9 +101,9 @@ static r0::E* letchain(int chaincount) else { return new r0::Let("chaincount" + to_string(chaincount), - new r0::Num(0), - new r0::Binop(B_PLUS, new r0::Var("chaincount" + to_string(chaincount)), - letchain(chaincount-1))); + new r0::Num(0), + new r0::Binop(B_PLUS, new r0::Var("chaincount" + to_string(chaincount)), + letchain(chaincount-1))); } } @@ -472,70 +472,69 @@ void test_all(bool run_only_last = false) t(v1let, 64, 128); } - } - - ts("Simple Fibonacci w/ Recursion"); - { - NUM(0); - NUM(1); - NNUM(2); - r0::Var n = r0::Var("n", TNUM); - auto nref = &n; - EQ(nref, n0); - EQ(nref, n1); - PLUS(nref, nn2); - PLUS(nref, nn1); - UPTR(r0::Call, fibsub2, "simple_fib", { bplus_nref_nn2 }); - UPTR(r0::Call, fibsub1, "simple_fib", { bplus_nref_nn1 }); - PLUS(fibsub2, fibsub1); - IF(fib_eq1, beq_nref_n1, n1, bplus_fibsub2_fibsub1); - IF(fib_body, beq_nref_n0, n0, fib_eq1); - r0::F fib = r0::F("simple_fib", {n}, TNUM, fib_body); - NUM(10); - UPTR (r0::Call, callfib, "simple_fib", { n10 }); - r0::F main = r0::F("main", { }, callfib); - r0::P prog = r0::P({fib, main }, "main", 2048); - t(prog, 55); - } + ts("Simple Fibonacci w/ Recursion"); + { + NUM(0); + NUM(1); + NNUM(2); + r0::Var n = r0::Var("n", TNUM); + auto nref = &n; + EQ(nref, n0); + EQ(nref, n1); + PLUS(nref, nn2); + PLUS(nref, nn1); + UPTR(r0::Call, fibsub2, "simple_fib", { bplus_nref_nn2 }); + UPTR(r0::Call, fibsub1, "simple_fib", { bplus_nref_nn1 }); + PLUS(fibsub2, fibsub1); + IF(fib_eq1, beq_nref_n1, n1, bplus_fibsub2_fibsub1); + IF(fib_body, beq_nref_n0, n0, fib_eq1); + r0::F fib = r0::F("simple_fib", {n}, TNUM, fib_body); + NUM(10); + UPTR (r0::Call, callfib, "simple_fib", { n10 }); + r0::F main = r0::F("main", { }, callfib); + r0::P prog = r0::P({fib, main }, "main", 2048); + t(prog, 55); + } - ts("Function with lots of args"); - { - r0::Var n0 = r0::Var("n0", TNUM); r0::Var n1 = r0::Var("n1", TNUM); - r0::Var n2 = r0::Var("n2", TNUM); r0::Var n3 = r0::Var("n3", TNUM); - r0::Var n4 = r0::Var("n4", TNUM); r0::Var n5 = r0::Var("n5", TNUM); - r0::Var n6 = r0::Var("n6", TNUM); r0::Var n7 = r0::Var("n7", TNUM); - r0::Var n8 = r0::Var("n8", TNUM); r0::Var n9 = r0::Var("n9", TNUM); - r0::Var n10 = r0::Var("n10", TNUM); r0::Var n11 = r0::Var("n11", TNUM); - r0::Var n12 = r0::Var("n12", TNUM); - auto rn0 = &n0; auto rn1 = &n1; auto rn2 = &n2; auto rn3 = &n3; - auto rn4 = &n4; auto rn5 = &n5; auto rn6 = &n6; auto rn7 = &n7; - auto rn8 = &n8; auto rn9 = &n9; auto rn10 = &n10; auto rn11 = &n11; - auto rn12 = &n12; - PLUSN(p01, rn0, rn1); PLUSN(p02, p01, rn2); PLUSN(p03, p02, rn3); - PLUSN(p04, p03, rn4); PLUSN(p05, p04, rn5); PLUSN(p06, p05, rn6); - PLUSN(p07, p06, rn7); PLUSN(p08, p07, rn8); PLUSN(p09, p08, rn9); - PLUSN(p010, p09, rn10); PLUSN(p011, p010, rn11); PLUSN(p012, p011, rn12); - r0::F add_12_nums = r0::F("add_12_nums", - {n0,n1,n2,n3,n4,n5,n6,n7,n8,n9,n10,n11,n12}, - TNUM, p012); - NUM(20); - UPTR(r0::Call, call_12_nums, "add_12_nums", {n20,n20,n20,n20,n20,n20,n20,n20,n20,n20,n20,n20, n20}); - r0::F main = r0::F("main", { }, call_12_nums); - r0::P prog = r0::P({add_12_nums, main }, "main", 2048); - t(prog, 20*13); - } + ts("Function with lots of args"); + { + r0::Var n0 = r0::Var("n0", TNUM); r0::Var n1 = r0::Var("n1", TNUM); + r0::Var n2 = r0::Var("n2", TNUM); r0::Var n3 = r0::Var("n3", TNUM); + r0::Var n4 = r0::Var("n4", TNUM); r0::Var n5 = r0::Var("n5", TNUM); + r0::Var n6 = r0::Var("n6", TNUM); r0::Var n7 = r0::Var("n7", TNUM); + r0::Var n8 = r0::Var("n8", TNUM); r0::Var n9 = r0::Var("n9", TNUM); + r0::Var n10 = r0::Var("n10", TNUM); r0::Var n11 = r0::Var("n11", TNUM); + r0::Var n12 = r0::Var("n12", TNUM); + auto rn0 = &n0; auto rn1 = &n1; auto rn2 = &n2; auto rn3 = &n3; + auto rn4 = &n4; auto rn5 = &n5; auto rn6 = &n6; auto rn7 = &n7; + auto rn8 = &n8; auto rn9 = &n9; auto rn10 = &n10; auto rn11 = &n11; + auto rn12 = &n12; + PLUSN(p01, rn0, rn1); PLUSN(p02, p01, rn2); PLUSN(p03, p02, rn3); + PLUSN(p04, p03, rn4); PLUSN(p05, p04, rn5); PLUSN(p06, p05, rn6); + PLUSN(p07, p06, rn7); PLUSN(p08, p07, rn8); PLUSN(p09, p08, rn9); + PLUSN(p010, p09, rn10); PLUSN(p011, p010, rn11); PLUSN(p012, p011, rn12); + r0::F add_12_nums = r0::F("add_12_nums", + {n0,n1,n2,n3,n4,n5,n6,n7,n8,n9,n10,n11,n12}, + TNUM, p012); + NUM(20); + UPTR(r0::Call, call_12_nums, "add_12_nums", {n20,n20,n20,n20,n20,n20,n20,n20,n20,n20,n20,n20, n20}); + r0::F main = r0::F("main", { }, call_12_nums); + r0::P prog = r0::P({add_12_nums, main }, "main", 2048); + t(prog, 20*13); + } - ts("Lambda (no closure)"); - { - NUM(123); NUM(321); NUM(111); - VAR(x1); VAR(x2); VAR(x3); - PLUS(vx2, vx3); - PLUSN(sum3, vx1, bplus_vx2_vx3); - LAMBDA(add3num, {"x1","x2","x3"}, sum3); - VAR(r0add3num); - UPTR(r0::Call, calladd3, vr0add3num, {n123, n321, n111}); - LET(main_test, r0add3num, add3num, calladd3); - t(main_test, 123+321+111); + ts("Lambda (no closure)"); + { + NUM(123); NUM(321); NUM(111); + VAR(x1); VAR(x2); VAR(x3); + PLUS(vx2, vx3); + PLUSN(sum3, vx1, bplus_vx2_vx3); + LAMBDA(add3num, {"x1","x2","x3"}, sum3); + VAR(r0add3num); + UPTR(r0::Call, calladd3, vr0add3num, {n123, n321, n111}); + LET(main_test, r0add3num, add3num, calladd3); + t(main_test, 123+321+111); + } } ts("Lambda (closure)");