summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--src/mir/from_hir.cpp347
-rw-r--r--src/mir/mir.cpp37
-rw-r--r--src/mir/mir.hpp18
4 files changed, 401 insertions, 3 deletions
diff --git a/Makefile b/Makefile
index 520b8007..6b54750b 100644
--- a/Makefile
+++ b/Makefile
@@ -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,