diff options
Diffstat (limited to 'src/trans/codegen_c.cpp')
-rw-r--r-- | src/trans/codegen_c.cpp | 109 |
1 files changed, 102 insertions, 7 deletions
diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 0ced3150..86bbdddc 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -308,6 +308,18 @@ namespace { << "\treturn ((v&0xFFFFFFFF) == 0 ? __builtin_ctz(v>>32) + 32 : __builtin_ctz(v));\n" << "}\n" ; + // Atomic hackery + for(int sz = 8; sz <= 64; sz *= 2) + { + m_of + << "static inline uint"<<sz<<"_t __mrustc_atomicloop"<<sz<<"(volatile uint"<<sz<<"_t* slot, uint"<<sz<<"_t param, int ordering, uint"<<sz<<"_t (*cb)(uint"<<sz<<"_t, uint"<<sz<<"_t)) {" + << " for(;;) {" + << " uint"<<sz<<"_t v = atomic_load_explicit((_Atomic uint"<<sz<<"_t*)slot, ordering);" + << " if( atomic_compare_exchange_strong_explicit((_Atomic uint"<<sz<<"_t*)slot, &v, cb(v, param), ordering, ordering) ) return v;" + << " }" + << "}\n" + ; + } break; case Compiler::Msvc: m_of @@ -564,7 +576,32 @@ namespace { << "\t}\n" << "\treturn SIZE_MAX;\n" << "}\n" + // Map of reversed nibbles 0 1 2 3 4 5 6 7 8 9 10 11 12 14 15 + << "static const uint8_t __mrustc_revmap[16] = { 0, 8, 4,12, 2,10, 6,14, 1, 9, 5,13, 3, 7,15};\n" + << "static inline uint8_t __mrustc_bitrev8(uint8_t v) { if(v==0||v==0xFF) return v; uint8_t rv = __mrustc_revmap[v>>4]|(__mrustc_revmap[v&15]<<4); }\n" + << "static inline uint16_t __mrustc_bitrev16(uint16_t v) { if(v==0) return 0; uint16_t rv = ((uint16_t)__mrustc_bitrev8(v>>8))|((uint16_t)__mrustc_bitrev8(v)<<8); }\n" + << "static inline uint32_t __mrustc_bitrev32(uint32_t v) { if(v==0) return 0; uint32_t rv = ((uint32_t)__mrustc_bitrev16(v>>16))|((uint32_t)__mrustc_bitrev16(v)<<16); }\n" + << "static inline uint64_t __mrustc_bitrev64(uint64_t v) { if(v==0) return 0; uint64_t rv = ((uint64_t)__mrustc_bitrev32(v>>32))|((uint64_t)__mrustc_bitrev32(v)<<32); }\n" + // TODO: 128 ; + if( m_options.emulated_i128 ) + { + m_of << "static inline uint128_t __mrustc_bitrev128(uint128_t v) { uint128_t rv = { __mrustc_bitrev64(v>>64)), __mrustc_bitrev64(v) }; return rv; }\n"; + } + else + { + m_of << "static inline uint128_t __mrustc_bitrev128(uint128_t v) { if(v==0) return 0; uint128_t rv = ((uint128_t)__mrustc_bitrev64(v>>64))|((uint128_t)__mrustc_bitrev64(v)<<64); }\n"; + } + for(int sz = 8; sz <= 64; sz *= 2) + { + m_of + << "static inline uint"<<sz<<"_t __mrustc_op_umax"<<sz<<"(uint"<<sz<<"_t a, uint"<<sz<<"_t b) { return (a > b ? a : b); }\n" + << "static inline uint"<<sz<<"_t __mrustc_op_umin"<<sz<<"(uint"<<sz<<"_t a, uint"<<sz<<"_t b) { return (a < b ? a : b); }\n" + << "static inline uint"<<sz<<"_t __mrustc_op_imax"<<sz<<"(uint"<<sz<<"_t a, uint"<<sz<<"_t b) { return ((int"<<sz<<"_t)a > (int"<<sz<<"_t)b ? a : b); }\n" + << "static inline uint"<<sz<<"_t __mrustc_op_imin"<<sz<<"(uint"<<sz<<"_t a, uint"<<sz<<"_t b) { return ((int"<<sz<<"_t)a < (int"<<sz<<"_t)b ? a : b); }\n" + << "static inline uint"<<sz<<"_t __mrustc_op_and_not"<<sz<<"(uint"<<sz<<"_t a, uint"<<sz<<"_t b) { return ~(a & b); }\n" + ; + } } ~CodeGenerator_C() {} @@ -4209,8 +4246,8 @@ namespace { emit_lvalue(e.ret_val); m_of << ".META = " << s.size() << ""; } else if( name == "transmute" ) { - const auto& ty_dst = params.m_types.at(0); - const auto& ty_src = params.m_types.at(1); + const auto& ty_src = params.m_types.at(0); + const auto& ty_dst = params.m_types.at(1); auto is_ptr = [](const ::HIR::TypeRef& ty){ return ty.m_data.is_Borrow() || ty.m_data.is_Pointer(); }; if( this->type_is_bad_zst(ty_dst) ) { @@ -4218,7 +4255,7 @@ namespace { } else if( e.args.at(0).is_Constant() ) { - m_of << "{ "; emit_ctype(ty_src, FMT_CB(s, s << "v";)); m_of << " = "; emit_param(e.args.at(0)); m_of << ";"; + m_of << "{ "; emit_ctype(ty_src, FMT_CB(s, s << "v";)); m_of << " = "; emit_param(e.args.at(0)); m_of << "; "; m_of << "memcpy( &"; emit_lvalue(e.ret_val); m_of << ", &v, sizeof("; emit_ctype(ty_dst); m_of << ")); "; m_of << "}"; } @@ -4250,7 +4287,7 @@ namespace { } else { - m_of << "memcpy( &"; emit_lvalue(e.ret_val); m_of << ", &"; emit_param(e.args.at(0)); m_of << ", sizeof("; emit_ctype(params.m_types.at(0)); m_of << "))"; + m_of << "memcpy( &"; emit_lvalue(e.ret_val); m_of << ", &"; emit_param(e.args.at(0)); m_of << ", sizeof("; emit_ctype(ty_src); m_of << "))"; } } else if( name == "copy_nonoverlapping" || name == "copy" ) { @@ -4410,6 +4447,22 @@ namespace { m_of << "("; emit_param(e.args.at(0)); m_of << ")"; } } + else if( name == "bitreverse" ) { + const auto& ty = params.m_types.at(0); + MIR_ASSERT(mir_res, ty.m_data.is_Primitive(), "Invalid type passed to bitreverse. Must be a primitive, got " << ty); + emit_lvalue(e.ret_val); m_of << " = "; + switch(get_prim_size(ty)) + { + case 8: m_of << "__mrustc_bitrev8"; break; + case 16: m_of << "__mrustc_bitrev16"; break; + case 32: m_of << "__mrustc_bitrev32"; break; + case 64: m_of << "__mrustc_bitrev64"; break; + case 128: m_of << "__mrustc_bitrev128"; break; + default: + MIR_TODO(mir_res, "bswap<" << ty << ">"); + } + m_of << "("; emit_param(e.args.at(0)); m_of << ")"; + } // > Obtain the discriminane of a &T as u64 else if( name == "discriminant_value" ) { const auto& ty = params.m_types.at(0); @@ -4616,7 +4669,8 @@ namespace { } } // Unchecked Arithmatic - else if( name == "unchecked_div" ) { + // - exact_div is UB to call on a non-multiple + else if( name == "unchecked_div" || name == "exact_div") { emit_lvalue(e.ret_val); m_of << " = "; if( type_is_emulated_i128(params.m_types.at(0)) ) { @@ -4689,7 +4743,7 @@ namespace { // Bit Twiddling // - CounT Leading Zeroes // - CounT Trailing Zeroes - else if( name == "ctlz" || name == "ctlz_nonzero" || name == "cttz" ) { + else if( name == "ctlz" || name == "ctlz_nonzero" || name == "cttz" || name == "cttz_nonzero" ) { auto emit_arg0 = [&](){ emit_param(e.args.at(0)); }; const auto& ty = params.m_types.at(0); emit_lvalue(e.ret_val); m_of << " = ("; @@ -4821,6 +4875,11 @@ namespace { else if( name == "volatile_store" ) { m_of << "*(volatile "; emit_ctype(params.m_types.at(0)); m_of << "*)"; emit_param(e.args.at(0)); m_of << " = "; emit_param(e.args.at(1)); } + else if( name == "nontemporal_store" ) { + // TODO: Actually do a non-temporal store + // GCC: _mm_stream_* (depending on input type, which must be `repr(simd)`) + m_of << "*(volatile "; emit_ctype(params.m_types.at(0)); m_of << "*)"; emit_param(e.args.at(0)); m_of << " = "; emit_param(e.args.at(1)); + } // --- Atomics! // > Single-ordering atomics else if( name == "atomic_xadd" || name.compare(0, 7+4+1, "atomic_xadd_") == 0 ) { @@ -4835,6 +4894,13 @@ namespace { auto ordering = get_atomic_ordering(name, 7+3+1); emit_atomic_arith(AtomicOp::And, ordering); } + else if( name == "atomic_nand" || name.compare(0, 7+4+1, "atomic_nand_") == 0 ) { + auto ordering = get_atomic_ordering(name, 7+4+1); + const auto& ty = params.m_types.at(0); + emit_lvalue(e.ret_val); m_of << " = __mrustc_atomicloop" << get_prim_size(ty) << "("; + emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", " << get_atomic_ty_gcc(ordering) << ", __mrustc_op_and_not" << get_prim_size(ty); + m_of << ")"; + } else if( name == "atomic_or" || name.compare(0, 7+2+1, "atomic_or_") == 0 ) { auto ordering = get_atomic_ordering(name, 7+2+1); emit_atomic_arith(AtomicOp::Or, ordering); @@ -4843,6 +4909,24 @@ namespace { auto ordering = get_atomic_ordering(name, 7+3+1); emit_atomic_arith(AtomicOp::Xor, ordering); } + else if( name == "atomic_max" || name.compare(0, 7+3+1, "atomic_max_") == 0 + || name == "atomic_min" || name.compare(0, 7+3+1, "atomic_min_") == 0 ) { + auto ordering = get_atomic_ordering(name, 7+3+1); + const auto& ty = params.m_types.at(0); + const char* op = (name[7+1] == 'a' ? "imax" : "imin"); // m'a'x vs m'i'n + emit_lvalue(e.ret_val); m_of << " = __mrustc_atomicloop" << get_prim_size(ty) << "("; + emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", " << get_atomic_ty_gcc(ordering) << ", __mrustc_op_" << op << get_prim_size(ty); + m_of << ")"; + } + else if( name == "atomic_umax" || name.compare(0, 7+4+1, "atomic_umax_") == 0 + || name == "atomic_umin" || name.compare(0, 7+4+1, "atomic_umin_") == 0 ) { + auto ordering = get_atomic_ordering(name, 7+4+1); + const auto& ty = params.m_types.at(0); + const char* op = (name[7+2] == 'a' ? "umax" : "umin"); // m'a'x vs m'i'n + emit_lvalue(e.ret_val); m_of << " = __mrustc_atomicloop" << get_prim_size(ty) << "("; + emit_param(e.args.at(0)); m_of << ", "; emit_param(e.args.at(1)); m_of << ", " << get_atomic_ty_gcc(ordering) << ", __mrustc_op_" << op << get_prim_size(ty); + m_of << ")"; + } else if( name == "atomic_load" || name.compare(0, 7+4+1, "atomic_load_") == 0 ) { auto ordering = get_atomic_ordering(name, 7+4+1); emit_lvalue(e.ret_val); m_of << " = "; @@ -4953,6 +5037,11 @@ namespace { else if( name == "atomic_singlethreadfence" || name.compare(0, 7+18, "atomic_singlethreadfence_") == 0 ) { // TODO: Does this matter? } + // -- Platform Intrinsics -- + else if( name.compare(0, 9, "platform:") == 0 ) { + // TODO: Platform intrinsics + m_of << "abort() /* TODO: Platform intrinsic \"" << name << "\" */"; + } else { MIR_BUG(mir_res, "Unknown intrinsic '" << name << "'"); } @@ -5518,10 +5607,16 @@ namespace { // TODO: This should have been eliminated? ("MIR Cleanup" should have removed all inline Const references) ::HIR::TypeRef ty; const auto& lit = get_literal_for_const(c.p, ty); - if(lit.is_Integer() || lit.is_Float() || lit.is_String()) + if(lit.is_Integer() || lit.is_Float()) { emit_literal(ty, lit, {}); } + else if( lit.is_String()) + { + m_of << "make_sliceptr("; + this->print_escaped_string( lit.as_String() ); + m_of << ", " << ::std::dec << lit.as_String().size() << ")"; + } else { // NOTE: GCC hack - statement expressions |