diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | src/mir/from_hir.cpp | 347 | ||||
-rw-r--r-- | src/mir/mir.cpp | 37 | ||||
-rw-r--r-- | src/mir/mir.hpp | 18 |
4 files changed, 401 insertions, 3 deletions
@@ -55,7 +55,7 @@ OBJ += hir_typeck/expr_visit.o OBJ += hir_typeck/expr_simple.o hir_typeck/expr_cs.o OBJ += hir_typeck/expr_check.o OBJ += hir_expand/closures.o hir_expand/ufcs_everything.o -OBJ += mir/mir_ptr.o mir/from_hir.o +OBJ += mir/mir.o mir/mir_ptr.o mir/from_hir.o PCHS := ast/ast.hpp diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index d7c7992c..25fd4295 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -9,6 +9,7 @@ #include "mir.hpp" #include "mir_ptr.hpp" #include <hir/expr.hpp> +#include <hir/hir.hpp> #include <algorithm> namespace { @@ -416,6 +417,340 @@ namespace { this->push_stmt_assign(mv$(dst), mv$(val)); } } + + void visit(::HIR::ExprNode_BinOp& node) override + { + this->visit_node_ptr(node.m_left); + auto left = this->lvalue_or_temp( node.m_left->m_res_type, this->get_result(node.m_left->span()) ); + + this->visit_node_ptr(node.m_right); + auto right = this->lvalue_or_temp( node.m_right->m_res_type, this->get_result(node.m_right->span()) ); + + auto res = this->new_temporary(node.m_res_type); + ::MIR::eBinOp op; + switch(node.m_op) + { + case ::HIR::ExprNode_BinOp::Op::CmpEqu: op = ::MIR::eBinOp::EQ; if(0) + case ::HIR::ExprNode_BinOp::Op::CmpNEqu:op = ::MIR::eBinOp::NE; if(0) + case ::HIR::ExprNode_BinOp::Op::CmpLt: op = ::MIR::eBinOp::LT; if(0) + case ::HIR::ExprNode_BinOp::Op::CmpLtE: op = ::MIR::eBinOp::LE; if(0) + case ::HIR::ExprNode_BinOp::Op::CmpGt: op = ::MIR::eBinOp::GT; if(0) + case ::HIR::ExprNode_BinOp::Op::CmpGtE: op = ::MIR::eBinOp::GE; + this->push_stmt_assign(res.as_Temporary(), ::MIR::RValue::make_BinOp({ mv$(left), op, mv$(right) })); + break; + + case ::HIR::ExprNode_BinOp::Op::Xor: op = ::MIR::eBinOp::BIT_XOR; if(0) + case ::HIR::ExprNode_BinOp::Op::Or : op = ::MIR::eBinOp::BIT_OR ; if(0) + case ::HIR::ExprNode_BinOp::Op::And: op = ::MIR::eBinOp::BIT_AND; + this->push_stmt_assign(res.as_Temporary(), ::MIR::RValue::make_BinOp({ mv$(left), op, mv$(right) })); + break; + + case ::HIR::ExprNode_BinOp::Op::Shr: op = ::MIR::eBinOp::BIT_SHR; if(0) + case ::HIR::ExprNode_BinOp::Op::Shl: op = ::MIR::eBinOp::BIT_SHL; + // TODO: Overflow checks + this->push_stmt_assign(res.as_Temporary(), ::MIR::RValue::make_BinOp({ mv$(left), op, mv$(right) })); + break; + + case ::HIR::ExprNode_BinOp::Op::BoolAnd: + TODO(node.span(), "&&"); + break; + case ::HIR::ExprNode_BinOp::Op::BoolOr: + TODO(node.span(), "||"); + break; + + case ::HIR::ExprNode_BinOp::Op::Add: op = ::MIR::eBinOp::ADD; if(0) + case ::HIR::ExprNode_BinOp::Op::Sub: op = ::MIR::eBinOp::SUB; if(0) + case ::HIR::ExprNode_BinOp::Op::Mul: op = ::MIR::eBinOp::MUL; if(0) + case ::HIR::ExprNode_BinOp::Op::Div: op = ::MIR::eBinOp::DIV; if(0) + case ::HIR::ExprNode_BinOp::Op::Mod: op = ::MIR::eBinOp::MOD; + // TODO: Overflow checks + this->push_stmt_assign(res.as_Temporary(), ::MIR::RValue::make_BinOp({ mv$(left), op, mv$(right) })); + break; + } + this->set_result( node.span(), mv$(res) ); + } + + void visit(::HIR::ExprNode_UniOp& node) override + { + this->visit_node_ptr(node.m_value); + auto val = this->lvalue_or_temp( node.m_value->m_res_type, this->get_result(node.m_value->span()) ); + + auto res = this->new_temporary(node.m_res_type); + switch(node.m_op) + { + case ::HIR::ExprNode_UniOp::Op::Ref: + this->push_stmt_assign(res.as_Temporary(), ::MIR::RValue::make_Borrow({ 0, ::HIR::BorrowType::Shared, mv$(val) })); + break; + case ::HIR::ExprNode_UniOp::Op::RefMut: + this->push_stmt_assign(res.as_Temporary(), ::MIR::RValue::make_Borrow({ 0, ::HIR::BorrowType::Unique, mv$(val) })); + break; + case ::HIR::ExprNode_UniOp::Op::Invert: + this->push_stmt_assign(res.as_Temporary(), ::MIR::RValue::make_UniOp({ mv$(val), ::MIR::eUniOp::INV })); + break; + case ::HIR::ExprNode_UniOp::Op::Negate: + this->push_stmt_assign(res.as_Temporary(), ::MIR::RValue::make_UniOp({ mv$(val), ::MIR::eUniOp::NEG })); + break; + } + this->set_result( node.span(), mv$(res) ); + } + void visit(::HIR::ExprNode_Cast& node) override + { + this->visit_node_ptr(node.m_value); + TODO(node.span(), "MIR _Cast"); + } + void visit(::HIR::ExprNode_Unsize& node) override + { + this->visit_node_ptr(node.m_value); + TODO(node.span(), "MIR _Unsize"); + } + void visit(::HIR::ExprNode_Index& node) override + { + this->visit_node_ptr(node.m_index); + auto index = this->lvalue_or_temp( node.m_index->m_res_type, this->get_result(node.m_index->span()) ); + + this->visit_node_ptr(node.m_value); + auto value = this->lvalue_or_temp( node.m_value->m_res_type, this->get_result(node.m_value->span()) ); + + if( false ) + { + ::MIR::RValue limit_val; + TU_MATCH_DEF(::HIR::TypeRef::Data, (node.m_value->m_res_type.m_data), (e), + ( + BUG(node.span(), "Indexing unsupported type " << node.m_value->m_res_type); + ), + (Array, + limit_val = ::MIR::Constant( e.size_val ); + ), + (Slice, + limit_val = ::MIR::RValue::make_DstMeta({ value.clone() }); + ) + ) + + auto limit_lval = this->lvalue_or_temp(node.m_index->m_res_type, mv$(limit_val)); + + auto cmp_res = this->new_temporary( ::HIR::CoreType::Bool ); + this->push_stmt_assign(cmp_res.clone(), ::MIR::RValue::make_BinOp({ index.clone(), ::MIR::eBinOp::GE, mv$(limit_lval) })); + auto arm_panic = this->new_bb_unlinked(); + auto arm_continue = this->new_bb_unlinked(); + this->end_block( ::MIR::Terminator::make_If({ mv$(cmp_res), arm_panic, arm_continue }) ); + + this->set_cur_block( arm_panic ); + // TODO: Call an "index fail" method which always panics. + //this->end_block( ::MIR::Terminator::make_Panic({}) ); + this->end_block( ::MIR::Terminator::make_Diverge({}) ); + + this->set_cur_block( arm_continue ); + } + + this->set_result( node.span(), ::MIR::LValue::make_Index({ box$(index), box$(value) }) ); + } + + void visit(::HIR::ExprNode_Deref& node) override + { + this->visit_node_ptr(node.m_value); + auto val = this->lvalue_or_temp( node.m_value->m_res_type, this->get_result(node.m_value->span()) ); + + this->set_result( node.span(), ::MIR::LValue::make_Deref({ box$(val) }) ); + } + + void visit(::HIR::ExprNode_TupleVariant& node) override + { + ::std::vector< ::MIR::LValue> values; + values.reserve( node.m_args.size() ); + for(auto& arg : node.m_args) + { + this->visit_node_ptr(arg); + values.push_back( this->lvalue_or_temp( arg->m_res_type, this->get_result(arg->span()) ) ); + } + + this->set_result( node.span(), ::MIR::RValue::make_Struct({ + node.m_path.clone(), + mv$(values) + }) ); + } + + void visit(::HIR::ExprNode_CallPath& node) override + { + ::std::vector< ::MIR::LValue> values; + values.reserve( node.m_args.size() ); + for(auto& arg : node.m_args) + { + this->visit_node_ptr(arg); + values.push_back( this->lvalue_or_temp( arg->m_res_type, this->get_result(arg->span()) ) ); + } + + // TODO: Obtain function type for this function + auto fcn_val = this->new_temporary( ::HIR::TypeRef(::HIR::FunctionType { + } ) ); + + auto panic_block = this->new_bb_unlinked(); + auto next_block = this->new_bb_unlinked(); + auto res = this->new_temporary( node.m_res_type ); + this->end_block(::MIR::Terminator::make_Call({ + next_block, panic_block, + res.clone(), mv$(fcn_val), + mv$(values) + })); + + this->set_cur_block(panic_block); + // TODO: Proper panic handling + this->end_block( ::MIR::Terminator::make_Diverge({}) ); + + this->set_cur_block( next_block ); + this->set_result( node.span(), mv$(res) ); + } + + void visit(::HIR::ExprNode_CallValue& node) override + { + BUG(node.span(), "Leftover _CallValue"); + } + void visit(::HIR::ExprNode_CallMethod& node) override + { + BUG(node.span(), "Leftover _CallValue"); + } + void visit(::HIR::ExprNode_Field& node) override + { + this->visit_node_ptr(node.m_value); + auto val = this->get_result_lvalue(node.m_value->span()); + + unsigned int idx; + if( '0' <= node.m_field[0] && node.m_field[0] <= '9' ) { + ::std::stringstream(node.m_field) >> idx; + } + else { + const auto& str = *node.m_value->m_res_type.m_data.as_Path().binding.as_Struct(); + const auto& fields = str.m_data.as_Named(); + idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto& x){ return x.first == node.m_field; } ) - fields.begin(); + } + this->set_result( node.span(), ::MIR::LValue::make_Field({ box$(val), idx }) ); + } + void visit(::HIR::ExprNode_Literal& node) override + { + TODO(node.span(), "Primitive literals"); + } + void visit(::HIR::ExprNode_UnitVariant& node) override + { + this->set_result( node.span(), ::MIR::RValue::make_Struct({ + node.m_path.clone(), + {} + }) ); + } + void visit(::HIR::ExprNode_PathValue& node) override + { + this->set_result( node.span(), ::MIR::LValue::make_Static(node.m_path.clone()) ); + } + void visit(::HIR::ExprNode_Variable& node) override + { + this->set_result( node.span(), ::MIR::LValue::make_Variable(node.m_slot) ); + } + + void visit(::HIR::ExprNode_StructLiteral& node) override + { + ::MIR::LValue base_val; + if( node.m_base_value ) + { + this->visit_node_ptr(node.m_base_value); + base_val = this->get_result_lvalue(node.m_base_value->span()); + } + + const ::HIR::t_struct_fields* fields_ptr = nullptr; + TU_MATCH(::HIR::TypeRef::TypePathBinding, (node.m_res_type.m_data.as_Path().binding), (e), + (Unbound, ), + (Opaque, ), + (Enum, + const auto& var_name = node.m_path.m_path.m_components.back(); + const auto& enm = *e; + auto it = ::std::find_if(enm.m_variants.begin(), enm.m_variants.end(), [&](const auto&v)->auto{ return v.first == var_name; }); + assert(it != enm.m_variants.end()); + fields_ptr = &it->second.as_Struct(); + ), + (Struct, + fields_ptr = &e->m_data.as_Named(); + ) + ) + assert(fields_ptr); + const ::HIR::t_struct_fields& fields = *fields_ptr; + + ::std::vector<bool> values_set; + ::std::vector< ::MIR::LValue> values; + values.resize( fields.size() ); + values_set.resize( fields.size() ); + + for(auto& ent : node.m_values) + { + auto idx = ::std::find_if(fields.begin(), fields.end(), [&](const auto&x){ return x.first == ent.first; }) - fields.begin(); + assert( !values_set[idx] ); + values_set[idx] = true; + this->visit_node_ptr(ent.second); + values.at(idx) = this->lvalue_or_temp( ent.second->m_res_type, this->get_result(ent.second->span()) ); + } + for(unsigned int i = 0; i < values.size(); i ++) + { + if( !values_set[i] ) { + if( !node.m_base_value) { + ERROR(node.span(), E0000, "Field '" << fields[i].first << "' not specified"); + } + values[i] = ::MIR::LValue::make_Field({ box$( base_val.clone() ), i }); + } + else { + // Drop unused part of the base + if( node.m_base_value) { + this->push_stmt_drop( ::MIR::LValue::make_Field({ box$( base_val.clone() ), i }) ); + } + } + } + + this->set_result( node.span(), ::MIR::RValue::make_Struct({ + node.m_path.clone(), + mv$(values) + }) ); + } + + void visit(::HIR::ExprNode_Tuple& node) override + { + ::std::vector< ::MIR::LValue> values; + values.reserve( node.m_vals.size() ); + for(auto& arg : node.m_vals) + { + this->visit_node_ptr(arg); + values.push_back( this->lvalue_or_temp( arg->m_res_type, this->get_result(arg->span()) ) ); + } + + this->set_result( node.span(), ::MIR::RValue::make_Tuple({ + mv$(values) + }) ); + } + + void visit(::HIR::ExprNode_ArrayList& node) override + { + ::std::vector< ::MIR::LValue> values; + values.reserve( node.m_vals.size() ); + for(auto& arg : node.m_vals) + { + this->visit_node_ptr(arg); + values.push_back( this->lvalue_or_temp( arg->m_res_type, this->get_result(arg->span()) ) ); + } + + this->set_result( node.span(), ::MIR::RValue::make_Array({ + mv$(values) + }) ); + } + + void visit(::HIR::ExprNode_ArraySized& node) override + { + this->visit_node_ptr( node.m_val ); + auto value = this->lvalue_or_temp( node.m_val->m_res_type, this->get_result(node.m_val->span()) ); + + this->set_result( node.span(), ::MIR::RValue::make_SizedArray({ + mv$(value), + static_cast<unsigned int>(node.m_size_val) + }) ); + } + + void visit(::HIR::ExprNode_Closure& node) override + { + TODO(node.span(), "_Closure"); + } }; } @@ -424,9 +759,19 @@ namespace { { ::MIR::Function fcn; + ExprVisitor_Conv ev { fcn }; + // 1. Apply destructuring to arguments + unsigned int i = 0; + for( const auto& arg : args ) + { + ev.destructure_from(ptr->span(), arg.first, ::MIR::LValue::make_Argument({i})); + } + // 2. Destructure code + ::HIR::ExprNode& root_node = const_cast<::HIR::ExprNode&>(*ptr); + root_node.visit( ev ); - return ::MIR::FunctionPointer(); + return ::MIR::FunctionPointer(new ::MIR::Function(mv$(fcn))); } diff --git a/src/mir/mir.cpp b/src/mir/mir.cpp new file mode 100644 index 00000000..28410c3c --- /dev/null +++ b/src/mir/mir.cpp @@ -0,0 +1,37 @@ +/* + * MRustC - Rust Compiler + * - By John Hodge (Mutabah/thePowersGang) + * + * mir/mir.cpp + * - MIR (Middle Intermediate Representation) definitions + */ +#include <mir/mir.hpp> + +::MIR::LValue MIR::LValue::clone() const +{ + TU_MATCHA( (*this), (e), + (Variable, return LValue(e); ), + (Temporary, return LValue(e); ), + (Argument, return LValue(e); ), + (Static, return LValue(e.clone()); ), + (Return, return LValue(e); ), + (Field, return LValue::make_Field({ + box$( e.val->clone() ), + e.field_index + }); ), + (Deref, return LValue::make_Deref({ + box$( e.val->clone() ) + }); ), + (Index, return LValue::make_Index({ + box$( e.val->clone() ), + box$( e.idx->clone() ) + }); ), + (Downcast, return LValue::make_Downcast({ + box$( e.val->clone() ), + e.variant_index + }); ) + ) + throw ""; +} + + diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp index 750a1ec9..59e2b316 100644 --- a/src/mir/mir.hpp +++ b/src/mir/mir.hpp @@ -17,7 +17,7 @@ typedef unsigned int RegionId; typedef unsigned int BasicBlockId; // "LVALUE" - Assignable values -TAGGED_UNION(LValue, Variable, +TAGGED_UNION_EX(LValue, (), Variable, ( // User-named variable (Variable, unsigned int), // Temporary with no user-defined name @@ -36,13 +36,22 @@ TAGGED_UNION(LValue, Variable, ::std::unique_ptr<LValue> val; unsigned int field_index; }), + // Dereference a value (Deref, struct { ::std::unique_ptr<LValue> val; }), + // Index an array or slice (typeof(val) == [T; n] or [T]) + (Index, struct { + ::std::unique_ptr<LValue> val; + ::std::unique_ptr<LValue> idx; + }), (Downcast, struct { ::std::unique_ptr<LValue> val; unsigned int variant_index; }) + ), (),(), ( + LValue clone() const; + ) ); enum class eBinOp @@ -53,6 +62,13 @@ enum class eBinOp DIV, DIV_OV, MOD, MOD_OV, + BIT_OR, + BIT_AND, + BIT_XOR, + + BIT_SHR, + BIT_SHL, + EQ, NE, GT, GE, LT, LE, |