summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Hodge <tpg@mutabah.net>2016-12-11 12:17:17 +0800
committerJohn Hodge <tpg@mutabah.net>2016-12-11 12:17:17 +0800
commit5f22f9f6d48411d56d9999d9a7d2c64b1aa31e73 (patch)
treea5513e62de44aa6f0a3ae37fd0ebfa0a50f54a0e /src
parentb556656fc9141c2d157b8da8fc95adaa16683e40 (diff)
downloadmrust-5f22f9f6d48411d56d9999d9a7d2c64b1aa31e73.tar.gz
Trans - Intrinsics (partially complete)
Diffstat (limited to 'src')
-rw-r--r--src/hir/deserialise.cpp5
-rw-r--r--src/hir/serialise.cpp3
-rw-r--r--src/hir_conv/bind.cpp1
-rw-r--r--src/mir/dump.cpp2
-rw-r--r--src/mir/from_hir.cpp30
-rw-r--r--src/mir/mir.cpp2
-rw-r--r--src/mir/mir.hpp5
-rw-r--r--src/trans/codegen_c.cpp137
-rw-r--r--src/trans/monomorphise.cpp5
-rw-r--r--src/trans/trans_list.cpp9
-rw-r--r--src/trans/trans_list.hpp1
11 files changed, 186 insertions, 14 deletions
diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp
index f6b624c7..45a60887 100644
--- a/src/hir/deserialise.cpp
+++ b/src/hir/deserialise.cpp
@@ -997,7 +997,10 @@ namespace {
#define _(x, ...) case ::MIR::CallTarget::TAG_##x: return ::MIR::CallTarget::make_##x( __VA_ARGS__ );
_(Value, deserialise_mir_lvalue() )
_(Path, deserialise_path() )
- _(Intrinsic, m_in.read_string() )
+ _(Intrinsic, {
+ m_in.read_string(),
+ deserialise_pathparams()
+ })
#undef _
default:
throw "";
diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp
index b4e7c6a2..f2394d40 100644
--- a/src/hir/serialise.cpp
+++ b/src/hir/serialise.cpp
@@ -526,7 +526,8 @@ namespace {
serialise_path(e);
),
(Intrinsic,
- m_out.write_string(e);
+ m_out.write_string(e.name);
+ serialise_pathparams(e.params);
)
)
}
diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp
index 66f484ed..f2295ee6 100644
--- a/src/hir_conv/bind.cpp
+++ b/src/hir_conv/bind.cpp
@@ -618,6 +618,7 @@ namespace {
visit_path(e2, ::HIR::Visitor::PathContext::VALUE);
),
(Intrinsic,
+ visit_path_params(e2.params);
)
)
for(auto& arg : te.args)
diff --git a/src/mir/dump.cpp b/src/mir/dump.cpp
index c97a2699..d1fdc503 100644
--- a/src/mir/dump.cpp
+++ b/src/mir/dump.cpp
@@ -206,7 +206,7 @@ namespace {
m_os << e2;
),
(Intrinsic,
- m_os << "\"" << e2 << "\"";
+ m_os << "\"" << e2.name << "\"::" << e2.params;
)
)
m_os << "( ";
diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp
index 75ff1619..258449ef 100644
--- a/src/mir/from_hir.cpp
+++ b/src/mir/from_hir.cpp
@@ -1385,11 +1385,31 @@ namespace {
auto next_block = m_builder.new_bb_unlinked();
auto res = m_builder.new_temporary( node.m_res_type );
- m_builder.end_block(::MIR::Terminator::make_Call({
- next_block, panic_block,
- res.clone(), node.m_path.clone(),
- mv$(values)
- }));
+ // Emit intrinsics as a special call type
+ // TODO: Should the parameters be stored? (trans has get_lvalue_type, so no 100% needed)
+ if( node.m_path.m_data.is_Generic() )
+ {
+ const auto& gpath = node.m_path.m_data.as_Generic();
+ const auto& fcn = m_builder.crate().get_function_by_path(node.span(), gpath.m_path);
+ if( fcn.m_abi == "rust-intrinsic" )
+ {
+ m_builder.end_block(::MIR::Terminator::make_Call({
+ next_block, panic_block,
+ res.clone(), ::MIR::CallTarget::make_Intrinsic({ gpath.m_path.m_components.back(), gpath.m_params.clone() }),
+ mv$(values)
+ }));
+ }
+ }
+
+ // If the call wasn't to an intrinsic, emit it as a path
+ if( m_builder.block_active() )
+ {
+ m_builder.end_block(::MIR::Terminator::make_Call({
+ next_block, panic_block,
+ res.clone(), node.m_path.clone(),
+ mv$(values)
+ }));
+ }
m_builder.set_cur_block(panic_block);
// TODO: Proper panic handling, including scope destruction
diff --git a/src/mir/mir.cpp b/src/mir/mir.cpp
index 95ad81b3..2dd911ec 100644
--- a/src/mir/mir.cpp
+++ b/src/mir/mir.cpp
@@ -171,7 +171,7 @@ namespace MIR {
os << e2;
),
(Intrinsic,
- os << "\"" << e2 << "\"";
+ os << "\"" << e2.name << "\"::" << e2.params;
)
)
os << "( ";
diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp
index 4f4d70b0..1ac8ff78 100644
--- a/src/mir/mir.hpp
+++ b/src/mir/mir.hpp
@@ -164,7 +164,10 @@ extern ::std::ostream& operator<<(::std::ostream& os, const RValue& x);
TAGGED_UNION(CallTarget, Intrinsic,
(Value, LValue),
(Path, ::HIR::Path),
- (Intrinsic, ::std::string)
+ (Intrinsic, struct {
+ ::std::string name;
+ ::HIR::PathParams params;
+ })
);
TAGGED_UNION(Terminator, Incomplete,
diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp
index 9e29d7bf..a8fe0b0b 100644
--- a/src/trans/codegen_c.cpp
+++ b/src/trans/codegen_c.cpp
@@ -41,6 +41,7 @@ namespace {
<< "#include <stddef.h>\n"
<< "#include <stdint.h>\n"
<< "#include <stdbool.h>\n"
+ << "#include <string.h>\n"
<< "typedef uint32_t CHAR;\n"
<< "typedef struct { } tUNIT;\n"
<< "typedef struct { } tBANG;\n"
@@ -263,6 +264,7 @@ namespace {
void emit_function_ext(const ::HIR::Path& p, const ::HIR::Function& item, const Trans_Params& params) override
{
+ m_of << "// extern \"" << item.m_abi << "\" " << p << "\n";
m_of << "extern ";
emit_function_header(p, item, params);
m_of << ";\n";
@@ -576,6 +578,7 @@ namespace {
}
mir_res.set_cur_stmt_term(i);
+ DEBUG("- " << code->blocks[i].terminator);
TU_MATCHA( (code->blocks[i].terminator), (e),
(Incomplete,
m_of << "\tfor(;;);\n";
@@ -603,6 +606,138 @@ namespace {
),
(Call,
m_of << "\t";
+ if( e.fcn.is_Intrinsic() )
+ {
+ const auto& name = e.fcn.as_Intrinsic().name;
+ const auto& params = e.fcn.as_Intrinsic().params;
+
+ struct H {
+ static const char* get_atomic_ordering(const ::MIR::TypeResolve& mir_res, const ::std::string& name, size_t prefix_len) {
+ if( name.size() < prefix_len )
+ return "memory_order_seq_cst";
+ const char* suffix = name.c_str() + prefix_len;
+ if( ::std::strcmp(suffix, "acq") == 0 ) {
+ return "memory_order_acquire";
+ }
+ else if( ::std::strcmp(suffix, "rel") == 0 ) {
+ return "memory_order_release";
+ }
+ else if( ::std::strcmp(suffix, "relaxed") == 0 ) {
+ return "memory_order_relaxed";
+ }
+ else if( ::std::strcmp(suffix, "acqrel") == 0 ) {
+ return "memory_order_acq_rel";
+ }
+ else {
+ MIR_BUG(mir_res, "Unknown atomic ordering suffix - '" << suffix << "'");
+ }
+ }
+ };
+ auto emit_atomic_cxchg = [&](const auto& e, const char* o_succ, const char* o_fail) {
+ emit_lvalue(e.ret_val); m_of << " = atomic_compare_exchange_strong_explicit(";
+ emit_lvalue(e.args.at(0));
+ m_of << ", &"; emit_lvalue(e.args.at(1));
+ m_of << ", "; emit_lvalue(e.args.at(2));
+ m_of << ", "<<o_succ<<", "<<o_fail<<")";
+ };
+ if( name == "size_of" ) {
+ emit_lvalue(e.ret_val); m_of << " = sizeof("; emit_ctype(params.m_types.at(0)); m_of << ")";
+ }
+ else if( name == "min_align_of" ) {
+ //emit_lvalue(e.ret_val); m_of << " = alignof("; emit_ctype(params.m_types.at(0)); m_of << ")";
+ emit_lvalue(e.ret_val); m_of << " = __alignof__("; emit_ctype(params.m_types.at(0)); m_of << ")";
+ }
+ else if( name == "transmute" ) {
+ m_of << "memcpy( &"; emit_lvalue(e.ret_val); m_of << ", &"; emit_lvalue(e.args.at(0)); m_of << ", sizeof("; emit_ctype(params.m_types.at(0)); m_of << "))";
+ }
+ else if( name == "copy_nonoverlapping" ) {
+ m_of << "memcpy( "; emit_lvalue(e.args.at(0)); m_of << ", "; emit_lvalue(e.args.at(1)); m_of << ", "; emit_lvalue(e.args.at(2)); m_of << ")";
+ }
+ else if( name == "forget" ) {
+ // Nothing needs to be done, this just stops the destructor from running.
+ }
+ else if( name == "uninit" ) {
+ // Do nothing, leaves the destination undefined
+ }
+ else if( name == "init" ) {
+ m_of << "memset( &"; emit_lvalue(e.ret_val); m_of << ", 0, sizeof("; emit_ctype(params.m_types.at(0)); m_of << "))";
+ }
+ else if( name == "move_val_init" ) {
+ m_of << "*"; emit_lvalue(e.args.at(0)); m_of << " = "; emit_lvalue(e.args.at(1));
+ }
+ else if( name == "abort" ) {
+ m_of << "abort()";
+ }
+ // Overflowing Arithmatic
+ // HACK: Uses GCC intrinsics
+ else if( name == "add_with_overflow" ) {
+ emit_lvalue(e.ret_val); m_of << "._1 = __builtin_add_overflow("; emit_lvalue(e.args.at(0));
+ m_of << ", "; emit_lvalue(e.args.at(1));
+ m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)";
+ }
+ else if( name == "sub_with_overflow" ) {
+ emit_lvalue(e.ret_val); m_of << "._1 = __builtin_sub_overflow("; emit_lvalue(e.args.at(0));
+ m_of << ", "; emit_lvalue(e.args.at(1));
+ m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)";
+ }
+ else if( name == "mul_with_overflow" ) {
+ emit_lvalue(e.ret_val); m_of << "._1 = __builtin_mul_overflow("; emit_lvalue(e.args.at(0));
+ m_of << ", "; emit_lvalue(e.args.at(1));
+ m_of << ", &"; emit_lvalue(e.ret_val); m_of << "._0)";
+ }
+ else if( name == "overflowing_add" ) {
+ m_of << "__builtin_add_overflow("; emit_lvalue(e.args.at(0));
+ m_of << ", "; emit_lvalue(e.args.at(1));
+ m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")";
+ }
+ else if( name == "overflowing_sub" ) {
+ m_of << "__builtin_sub_overflow("; emit_lvalue(e.args.at(0));
+ m_of << ", "; emit_lvalue(e.args.at(1));
+ m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")";
+ }
+ else if( name == "overflowing_mul" ) {
+ m_of << "__builtin_mul_overflow("; emit_lvalue(e.args.at(0));
+ m_of << ", "; emit_lvalue(e.args.at(1));
+ m_of << ", &"; emit_lvalue(e.ret_val); m_of << ")";
+ }
+ // --- Atomics!
+ // > Single-ordering atomics
+ else if( name == "atomic_xadd" || name.compare(0, 7+4+1, "atomic_xadd_") == 0 ) {
+ auto ordering = H::get_atomic_ordering(mir_res, name, 7+4+1);
+ emit_lvalue(e.ret_val); m_of << " = atomic_fetch_add_explicit("; emit_lvalue(e.args.at(0)); m_of << ", "; emit_lvalue(e.args.at(1)); m_of << ", " << ordering << ")";
+ }
+ else if( name == "atomic_load" || name.compare(0, 7+4+1, "atomic_load_") == 0 ) {
+ auto ordering = H::get_atomic_ordering(mir_res, name, 7+4+1);
+ emit_lvalue(e.ret_val); m_of << " = atomic_load_explicit("; emit_lvalue(e.args.at(0)); m_of << ", " << ordering << ")";
+ }
+ else if( name == "atomic_store" || name.compare(0, 7+5+1, "atomic_store_") == 0 ) {
+ auto ordering = H::get_atomic_ordering(mir_res, name, 7+5+1);
+ m_of << "atomic_store_explicit("; emit_lvalue(e.args.at(0)); m_of << ", "; emit_lvalue(e.args.at(1)); m_of << ", " << ordering << ")";
+ }
+ // Comare+Exchange (has two orderings)
+ else if( name == "atomic_cxchg_acq_failrelaxed" ) {
+ emit_atomic_cxchg(e, "memory_order_acquire", "memory_order_relaxed");
+ }
+ else if( name == "atomic_cxchg_acqrel_failrelaxed" ) {
+ emit_atomic_cxchg(e, "memory_order_acq_rel", "memory_order_relaxed");
+ }
+ else if( name.compare(0, 7+6+4, "atomic_cxchg_fail") == 0 ) {
+ auto fail_ordering = H::get_atomic_ordering(mir_res, name, 7+6+4);
+ emit_atomic_cxchg(e, "memory_order_seq_cst", fail_ordering);
+ }
+ else if( name == "atomic_cxchg" || name.compare(0, 7+6, "atomic_cxchg_") == 0 ) {
+ auto ordering = H::get_atomic_ordering(mir_res, name, 7+6);
+ emit_atomic_cxchg(e, ordering, ordering);
+
+ }
+ else {
+ MIR_BUG(mir_res, "Unknown intrinsic '" << name << "'");
+ }
+ m_of << ";\n";
+ m_of << "\tgoto bb" << e.ret_block << ";\n";
+ break ;
+ }
+
TU_MATCHA( (e.fcn), (e2),
(Value,
{
@@ -809,7 +944,7 @@ namespace {
m_of << "struct e_" << Trans_Mangle(te.path);
),
(Unbound,
- BUG(Span(), "Unbound path in trans - " << ty);
+ BUG(Span(), "Unbound type path in trans - " << ty);
),
(Opaque,
BUG(Span(), "Opaque path in trans - " << ty);
diff --git a/src/trans/monomorphise.cpp b/src/trans/monomorphise.cpp
index 24bf34d1..d129eae9 100644
--- a/src/trans/monomorphise.cpp
+++ b/src/trans/monomorphise.cpp
@@ -91,6 +91,7 @@ namespace {
if( stmt.is_Drop() )
{
const auto& e = stmt.as_Drop();
+ DEBUG("- DROP " << e.slot);
statements.push_back( ::MIR::Statement::make_Drop({
e.kind,
monomorph_LValue(crate, params, e.slot)
@@ -99,6 +100,7 @@ namespace {
else
{
const auto& e = stmt.as_Assign();
+ DEBUG("- " << e.dst << " = " << e.src);
::MIR::RValue rval;
TU_MATCHA( (e.src), (se),
@@ -221,6 +223,7 @@ namespace {
::MIR::Terminator terminator;
+ DEBUG("> " << block.terminator);
TU_MATCHA( (block.terminator), (e),
(Incomplete,
//BUG(sp, "Incomplete block");
@@ -261,7 +264,7 @@ namespace {
return params.monomorph(crate, e);
),
(Intrinsic,
- return e;
+ return ::MIR::CallTarget::make_Intrinsic({ e.name, params.monomorph(crate, e.params) });
)
)
throw "";
diff --git a/src/trans/trans_list.cpp b/src/trans/trans_list.cpp
index 38e80468..f6a14c7e 100644
--- a/src/trans/trans_list.cpp
+++ b/src/trans/trans_list.cpp
@@ -78,9 +78,14 @@ t_cb_generic Trans_Params::get_cb() const
::HIR::GenericPath Trans_Params::monomorph(const ::HIR::Crate& crate, const ::HIR::GenericPath& p) const
{
- auto rv = monomorphise_genericpath_with(sp, p, this->get_cb(), false);
+ return ::HIR::GenericPath( p.m_path, this->monomorph(crate, p.m_params) );
+}
+
+::HIR::PathParams Trans_Params::monomorph(const ::HIR::Crate& crate, const ::HIR::PathParams& p) const
+{
+ auto rv = monomorphise_path_params_with(sp, p, this->get_cb(), false);
::StaticTraitResolve resolve { crate };
- for(auto& arg : rv.m_params.m_types)
+ for(auto& arg : rv.m_types)
resolve.expand_associated_types(sp, arg);
return rv;
}
diff --git a/src/trans/trans_list.hpp b/src/trans/trans_list.hpp
index 1297d2c2..bca75dac 100644
--- a/src/trans/trans_list.hpp
+++ b/src/trans/trans_list.hpp
@@ -33,6 +33,7 @@ struct Trans_Params
::HIR::TypeRef monomorph(const ::HIR::Crate& crate, const ::HIR::TypeRef& p) const;
::HIR::Path monomorph(const ::HIR::Crate& crate, const ::HIR::Path& p) const;
::HIR::GenericPath monomorph(const ::HIR::Crate& crate, const ::HIR::GenericPath& p) const;
+ ::HIR::PathParams monomorph(const ::HIR::Crate& crate, const ::HIR::PathParams& p) const;
bool has_types() const {
return pp_method.m_types.size() > 0 || pp_impl.m_types.size() > 0;