diff options
author | John Hodge <tpg@mutabah.net> | 2017-08-20 10:46:02 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2017-08-20 10:46:02 +0800 |
commit | ee38738e083079e4f8d529ac58781aae47e09188 (patch) | |
tree | 6aa43accc15d4c419f4322066c52eafe0b654ec6 /src/trans/codegen_c.cpp | |
parent | 54eda831fff08ef95f8d2e06b1557b75f90f6f93 (diff) | |
download | mrust-ee38738e083079e4f8d529ac58781aae47e09188.tar.gz |
Codegen C - Rough support for msvc inline assembly
Diffstat (limited to 'src/trans/codegen_c.cpp')
-rw-r--r-- | src/trans/codegen_c.cpp | 216 |
1 files changed, 137 insertions, 79 deletions
diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 973aa33a..23d02531 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -2036,82 +2036,17 @@ namespace { if( e.flag_idx != ~0u ) m_of << indent << "}\n"; break; } - case ::MIR::Statement::TAG_Asm: { - const auto& e = stmt.as_Asm(); - - struct H { - static bool has_flag(const ::std::vector<::std::string>& flags, const char* des) { - return ::std::find_if(flags.begin(), flags.end(), [des](const auto&x){return x==des;}) != flags.end(); - } - static const char* convert_reg(const char* r) { - if( ::std::strcmp(r, "{eax}") == 0 || ::std::strcmp(r, "{rax}") == 0 ) { - return "a"; - } - else { - return r; - } - } - }; - bool is_volatile = H::has_flag(e.flags, "volatile"); - bool is_intel = H::has_flag(e.flags, "intel"); - - m_of << indent << "__asm__ "; - if(is_volatile) m_of << "__volatile__"; - // TODO: Convert format string? - // TODO: Use a C-specific escaper here. - m_of << "(\"" << (is_intel ? ".syntax intel; " : ""); - for(auto it = e.tpl.begin(); it != e.tpl.end(); ++it) - { - if( *it == '\n' ) - m_of << ";\\n"; - else if( *it == '"' ) - m_of << "\\\""; - else if( *it == '\\' ) - m_of << "\\\\"; - else if( *it == '/' && *(it+1) == '/' ) - { - while( it != e.tpl.end() || *it == '\n' ) - ++it; - -- it; - } - else if( *it == '%' && *(it+1) == '%' ) - m_of << "%"; - else if( *it == '%' && !isdigit(*(it+1)) ) - m_of << "%%"; - else - m_of << *it; - } - m_of << (is_intel ? ".syntax att; " : "") << "\""; - m_of << ": "; - for(unsigned int i = 0; i < e.outputs.size(); i ++ ) - { - const auto& v = e.outputs[i]; - if( i != 0 ) m_of << ", "; - m_of << "\""; - switch(v.first[0]) - { - case '=': m_of << "="; break; - case '+': m_of << "+"; break; - default: MIR_TODO(mir_res, "Handle asm! output leader '" << v.first[0] << "'"); - } - m_of << H::convert_reg(v.first.c_str()+1); - m_of << "\"("; emit_lvalue(v.second); m_of << ")"; - } - m_of << ": "; - for(unsigned int i = 0; i < e.inputs.size(); i ++ ) - { - const auto& v = e.inputs[i]; - if( i != 0 ) m_of << ", "; - m_of << "\"" << v.first << "\"("; emit_lvalue(v.second); m_of << ")"; - } - m_of << ": "; - for(unsigned int i = 0; i < e.clobbers.size(); i ++ ) + case ::MIR::Statement::TAG_Asm: + switch(m_compiler) { - if( i != 0 ) m_of << ", "; - m_of << "\"" << e.clobbers[i] << "\""; + case Compiler::Gcc: + this->emit_asm_gcc(mir_res, stmt.as_Asm(), indent_level); + break; + case Compiler::Msvc: + this->emit_asm_msvc(mir_res, stmt.as_Asm(), indent_level); + break; } - m_of << ");\n"; - break; } + break; case ::MIR::Statement::TAG_Assign: { const auto& e = stmt.as_Assign(); DEBUG("- " << e.dst << " = " << e.src); @@ -2815,6 +2750,121 @@ namespace { } m_of << " );\n"; } + void emit_asm_gcc(const ::MIR::TypeResolve& mir_res, const ::MIR::Statement::Data_Asm& e, unsigned indent_level) + { + auto indent = RepeatLitStr{ "\t", static_cast<int>(indent_level) }; + struct H { + static bool has_flag(const ::std::vector<::std::string>& flags, const char* des) { + return ::std::find_if(flags.begin(), flags.end(), [des](const auto&x) {return x == des; }) != flags.end(); + } + static const char* convert_reg(const char* r) { + if (::std::strcmp(r, "{eax}") == 0 || ::std::strcmp(r, "{rax}") == 0) { + return "a"; + } + else { + return r; + } + } + }; + bool is_volatile = H::has_flag(e.flags, "volatile"); + bool is_intel = H::has_flag(e.flags, "intel"); + + + m_of << indent << "__asm__ "; + if (is_volatile) m_of << "__volatile__"; + // TODO: Convert format string? + // TODO: Use a C-specific escaper here. + m_of << "(\"" << (is_intel ? ".syntax intel; " : ""); + for (auto it = e.tpl.begin(); it != e.tpl.end(); ++it) + { + if (*it == '\n') + m_of << ";\\n"; + else if (*it == '"') + m_of << "\\\""; + else if (*it == '\\') + m_of << "\\\\"; + else if (*it == '/' && *(it + 1) == '/') + { + while (it != e.tpl.end() || *it == '\n') + ++it; + --it; + } + else if (*it == '%' && *(it + 1) == '%') + m_of << "%"; + else if (*it == '%' && !isdigit(*(it + 1))) + m_of << "%%"; + else + m_of << *it; + } + m_of << (is_intel ? ".syntax att; " : "") << "\""; + m_of << ": "; + for (unsigned int i = 0; i < e.outputs.size(); i++) + { + const auto& v = e.outputs[i]; + if (i != 0) m_of << ", "; + m_of << "\""; + switch (v.first[0]) + { + case '=': m_of << "="; break; + case '+': m_of << "+"; break; + default: MIR_TODO(mir_res, "Handle asm! output leader '" << v.first[0] << "'"); + } + m_of << H::convert_reg(v.first.c_str() + 1); + m_of << "\"("; emit_lvalue(v.second); m_of << ")"; + } + m_of << ": "; + for (unsigned int i = 0; i < e.inputs.size(); i++) + { + const auto& v = e.inputs[i]; + if (i != 0) m_of << ", "; + m_of << "\"" << v.first << "\"("; emit_lvalue(v.second); m_of << ")"; + } + m_of << ": "; + for (unsigned int i = 0; i < e.clobbers.size(); i++) + { + if (i != 0) m_of << ", "; + m_of << "\"" << e.clobbers[i] << "\""; + } + m_of << ");\n"; + } + void emit_asm_msvc(const ::MIR::TypeResolve& mir_res, const ::MIR::Statement::Data_Asm& e, unsigned indent_level) + { + auto indent = RepeatLitStr{ "\t", static_cast<int>(indent_level) }; + + if( !e.inputs.empty() || !e.outputs.empty() ) + { + MIR_TODO(mir_res, "Inputs/outputs in msvc inline assembly"); +#if 0 + m_of << indent << "{\n"; + for(size_t i = 0; i < e.inputs.size(); i ++) + { + m_of << indent << "auto asm_i_" << i << " = "; + emit_lvalue(e.inputs[i]); + } +#endif + } + + m_of << indent << "__asm {\n"; + + m_of << indent << "\t"; + for (auto it = e.tpl.begin(); it != e.tpl.end(); ++it) + { + if (*it == ';') + { + m_of << "\n"; + m_of << indent << "\t"; + } + else + m_of << *it; + } + + m_of << "\n" << indent << "}"; + if (!e.inputs.empty() || !e.outputs.empty()) + { + m_of << "}"; + } + m_of << ";\n"; + } private: const ::HIR::TypeRef& monomorphise_fcn_return(::HIR::TypeRef& tmp, const ::HIR::Function& item, const Trans_Params& params) { @@ -4154,13 +4204,21 @@ namespace { m_of << "\", " << ::std::dec << c.size() << ")"; ), (Const, - // TODO: This should have been eliminated? - // NOTE: GCC hack - statement expressions + // 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); - m_of << "({"; emit_ctype(ty, FMT_CB(ss, ss<<"v";)); m_of << "; "; - assign_from_literal([&](){ m_of << "v"; }, ty, lit); - m_of << "; v;})"; + if(lit.is_Integer() || lit.is_Float() || lit.is_String()) + { + emit_literal(ty, lit, {}); + } + else + { + // NOTE: GCC hack - statement expressions + MIR_ASSERT(*m_mir_res, m_compiler == Compiler::Gcc, "TODO: Support inline constants without statement expressions"); + m_of << "({"; emit_ctype(ty, FMT_CB(ss, ss<<"v";)); m_of << "; "; + assign_from_literal([&](){ m_of << "v"; }, ty, lit); + m_of << "; v;})"; + } ), (ItemAddr, TU_MATCHA( (c.m_data), (pe), |