summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/trans/codegen_c.cpp28
-rw-r--r--src/trans/target.cpp104
-rw-r--r--src/trans/target.hpp12
3 files changed, 114 insertions, 30 deletions
diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp
index a4b0387a..c30657bf 100644
--- a/src/trans/codegen_c.cpp
+++ b/src/trans/codegen_c.cpp
@@ -205,7 +205,7 @@ namespace {
m_outfile_path_c(outfile + ".c"),
m_of(m_outfile_path_c)
{
- switch(Target_GetCurSpec().m_codegen_mode)
+ switch(Target_GetCurSpec().m_backend_c.m_codegen_mode)
{
case CodegenMode::Gnu11:
m_compiler = Compiler::Gcc;
@@ -303,7 +303,7 @@ namespace {
<< "\treturn ((v&0xFFFFFFFF) == 0 ? __builtin_ctz(v>>32) + 32 : __builtin_ctz(v));\n"
<< "}\n"
;
- break;
+ break;
case Compiler::Msvc:
m_of
<< "static inline uint64_t __builtin_popcount(uint64_t v) {\n"
@@ -567,7 +567,7 @@ namespace {
// - `gcc-${TRIPLE}` (if available)
// - `gcc` as fallback
{
- ::std::string varname = "CC-" + Target_GetCurSpec().m_c_compiler;
+ ::std::string varname = "CC-" + Target_GetCurSpec().m_backend_c.m_c_compiler;
if( getenv(varname.c_str()) ) {
args.push_back( getenv(varname.c_str()) );
}
@@ -576,12 +576,14 @@ namespace {
}
else {
// TODO: Determine if the compiler can't be found, and fall back to `gcc` if that's the case
- args.push_back( Target_GetCurSpec().m_c_compiler + "-gcc" );
+ args.push_back( Target_GetCurSpec().m_backend_c.m_c_compiler + "-gcc" );
//args.push_back( "gcc" );
}
}
- args.push_back("-ffunction-sections");
- args.push_back("-pthread");
+ for( const auto& a : Target_GetCurSpec().m_backend_c.m_compiler_opts )
+ {
+ args.push_back( a.c_str() );
+ }
switch(opt.opt_level)
{
case 0: break;
@@ -624,7 +626,10 @@ namespace {
{
args.push_back("-l"); args.push_back(path.c_str());
}
- args.push_back("-Wl,--gc-sections");
+ for( const auto& a : Target_GetCurSpec().m_backend_c.m_linker_opts )
+ {
+ args.push_back( a.c_str() );
+ }
}
else
{
@@ -633,8 +638,9 @@ namespace {
break;
case Compiler::Msvc:
// TODO: Look up these paths in the registry and use CreateProcess instead of system
+ // - OR, run `vcvarsall` and get the required environment variables and PATH from it?
args.push_back(detect_msvc().path_vcvarsall);
- args.push_back( Target_GetCurSpec().m_c_compiler );
+ args.push_back( Target_GetCurSpec().m_backend_c.m_c_compiler );
args.push_back("&");
args.push_back("cl.exe");
args.push_back("/nologo");
@@ -680,9 +686,9 @@ namespace {
}
args.push_back("kernel32.lib"); // Needed for Interlocked*
- // Command-line specified linker search directories
args.push_back("/link");
- //args.push_back("/verbose");
+
+ // Command-line specified linker search directories
for(const auto& path : link_dirs )
{
args.push_back(FMT("/LIBPATH:" << path));
@@ -3569,7 +3575,7 @@ namespace {
#endif
}
- if( Target_GetCurSpec().m_c_compiler == "amd64" ) {
+ if( Target_GetCurSpec().m_backend_c.m_c_compiler == "amd64" ) {
MIR_TODO(mir_res, "MSVC amd64 doesn't support inline assembly, need to have a transform for '" << e.tpl << "'");
}
m_of << indent << "__asm {\n";
diff --git a/src/trans/target.cpp b/src/trans/target.cpp
index 87b5aa1d..1727cdba 100644
--- a/src/trans/target.cpp
+++ b/src/trans/target.cpp
@@ -133,11 +133,11 @@ namespace
check_path_length(key_val, 3);
if( key_val.value.as_string() == "msvc" )
{
- rv.m_codegen_mode = CodegenMode::Msvc;
+ rv.m_backend_c.m_codegen_mode = CodegenMode::Msvc;
}
else if( key_val.value.as_string() == "gnu" )
{
- rv.m_codegen_mode = CodegenMode::Gnu11;
+ rv.m_backend_c.m_codegen_mode = CodegenMode::Gnu11;
}
else
{
@@ -148,7 +148,23 @@ namespace
else if( key_val.path[2] == "target" )
{
check_path_length(key_val, 3);
- rv.m_c_compiler = key_val.value.as_string();
+ rv.m_backend_c.m_c_compiler = key_val.value.as_string();
+ }
+ else if( key_val.path[2] == "compiler-opts" )
+ {
+ check_path_length(key_val, 3);
+ for(const auto& v : key_val.value.as_list())
+ {
+ rv.m_backend_c.m_compiler_opts.push_back( v.as_string() );
+ }
+ }
+ else if( key_val.path[2] == "linker-opts" )
+ {
+ check_path_length(key_val, 3);
+ for(const auto& v : key_val.value.as_list())
+ {
+ rv.m_backend_c.m_linker_opts.push_back( v.as_string() );
+ }
}
else
{
@@ -233,8 +249,56 @@ namespace
return rv;
}
+ void save_spec_to_file(const ::std::string& filename, const TargetSpec& spec)
+ {
+ // TODO: Have a round-trip unit test
+ ::std::ofstream of(filename);
+
+ struct H
+ {
+ static const char* tfstr(bool v)
+ {
+ return v ? "true" : "false";
+ }
+ static const char* c_variant_name(const CodegenMode m)
+ {
+ switch(m)
+ {
+ case CodegenMode::Gnu11: return "gnu";
+ case CodegenMode::Msvc: return "msvc";
+ }
+ return "";
+ }
+ };
+
+ of
+ << "[target]\n"
+ << "family = \"" << spec.m_family << "\"\n"
+ << "os-name = \"" << spec.m_os_name << "\"\n"
+ << "env-name = \"" << spec.m_env_name << "\"\n"
+ //<< "arch = \"" << spec.m_arch.m_name << "\"\n"
+ << "\n"
+ << "[backend.c]\n"
+ << "variant = \"" << H::c_variant_name(spec.m_backend_c.m_codegen_mode) << "\"\n"
+ << "target = \"" << spec.m_backend_c.m_c_compiler << "\"\n"
+ << "compiler-opts = [" << spec.m_backend_c.m_compiler_opts << "]\n"
+ << "linker-opts = [" << spec.m_backend_c.m_linker_opts << "]\n"
+ << "\n"
+ << "[arch]"
+ << "name = \"" << spec.m_arch.m_name << "\"\n"
+ << "pointer-bits = " << spec.m_arch.m_pointer_bits << "\n"
+ << "is-big-endian = " << H::tfstr(spec.m_arch.m_big_endian) << "\n"
+ << "has-atomic-u8 = " << H::tfstr(spec.m_arch.m_atomics.u8) << "\n"
+ << "has-atomic-u16 = " << H::tfstr(spec.m_arch.m_atomics.u16) << "\n"
+ << "has-atomic-u32 = " << H::tfstr(spec.m_arch.m_atomics.u32) << "\n"
+ << "has-atomic-u64 = " << H::tfstr(spec.m_arch.m_atomics.u64) << "\n"
+ << "has-atomic-ptr = " << H::tfstr(spec.m_arch.m_atomics.ptr) << "\n"
+ ;
+ }
TargetSpec init_from_spec_name(const ::std::string& target_name)
{
+ // Options for all the fully-GNU environments
+ #define BACKEND_C_OPTS_GNU {"-ffunction-sections", "-pthread"}, {"-Wl,--gc-sections"}
// If there's a '/' or a '\' in the filename, open it as a path, otherwise assume it's a triple.
if( target_name.find('/') != ::std::string::npos || target_name.find('\\') != ::std::string::npos )
{
@@ -243,98 +307,100 @@ namespace
else if(target_name == "i586-linux-gnu")
{
return TargetSpec {
- "unix", "linux", "gnu", CodegenMode::Gnu11, "i586-linux-gnu",
+ "unix", "linux", "gnu", {CodegenMode::Gnu11, "i586-linux-gnu", BACKEND_C_OPTS_GNU},
ARCH_X86
};
}
else if(target_name == "x86_64-linux-gnu")
{
return TargetSpec {
- "unix", "linux", "gnu", CodegenMode::Gnu11, "x86_64-linux-gnu",
+ "unix", "linux", "gnu", {CodegenMode::Gnu11, "x86_64-linux-gnu", BACKEND_C_OPTS_GNU},
ARCH_X86_64
};
}
else if(target_name == "arm-linux-gnu")
{
return TargetSpec {
- "unix", "linux", "gnu", CodegenMode::Gnu11, "arm-elf-eabi",
+ "unix", "linux", "gnu", {CodegenMode::Gnu11, "arm-elf-eabi", BACKEND_C_OPTS_GNU},
ARCH_ARM32
};
}
else if(target_name == "aarch64-linux-gnu")
{
return TargetSpec {
- "unix", "linux", "gnu", CodegenMode::Gnu11, "aarch64-linux-gnu",
+ "unix", "linux", "gnu", {CodegenMode::Gnu11, "aarch64-linux-gnu", BACKEND_C_OPTS_GNU},
ARCH_ARM64
};
}
else if(target_name == "i586-windows-gnu")
{
return TargetSpec {
- "windows", "windows", "gnu", CodegenMode::Gnu11, "mingw32",
+ "windows", "windows", "gnu", {CodegenMode::Gnu11, "mingw32", BACKEND_C_OPTS_GNU},
ARCH_X86
};
}
else if(target_name == "x86_64-windows-gnu")
{
return TargetSpec {
- "windows", "windows", "gnu", CodegenMode::Gnu11, "x86_64-w64-mingw32",
+ "windows", "windows", "gnu", {CodegenMode::Gnu11, "x86_64-w64-mingw32", BACKEND_C_OPTS_GNU},
ARCH_X86_64
};
}
else if (target_name == "x86-windows-msvc")
{
+ // TODO: Should this include the "kernel32.lib" inclusion?
return TargetSpec {
- "windows", "windows", "msvc", CodegenMode::Msvc, "x86",
+ "windows", "windows", "msvc", {CodegenMode::Msvc, "x86", {}, {}},
ARCH_X86
};
}
else if (target_name == "x86_64-windows-msvc")
{
return TargetSpec {
- "windows", "windows", "msvc", CodegenMode::Msvc, "amd64",
+ "windows", "windows", "msvc", {CodegenMode::Msvc, "amd64", {}, {}},
ARCH_X86_64
};
}
else if(target_name == "x86_64-unknown-netbsd")
{
return TargetSpec {
- "unix", "netbsd", "gnu", CodegenMode::Gnu11, "x86_64-unknown-netbsd",
+ "unix", "netbsd", "gnu", {CodegenMode::Gnu11, "x86_64-unknown-netbsd", BACKEND_C_OPTS_GNU},
ARCH_X86_64
};
}
else if(target_name == "i686-unknown-openbsd")
{
return TargetSpec {
- "unix", "openbsd", "gnu", CodegenMode::Gnu11, "i686-unknown-openbsd",
+ "unix", "openbsd", "gnu", {CodegenMode::Gnu11, "i686-unknown-openbsd", BACKEND_C_OPTS_GNU},
ARCH_X86
};
}
else if(target_name == "x86_64-unknown-openbsd")
{
return TargetSpec {
- "unix", "openbsd", "gnu", CodegenMode::Gnu11, "x86_64-unknown-openbsd",
+ "unix", "openbsd", "gnu", {CodegenMode::Gnu11, "x86_64-unknown-openbsd", BACKEND_C_OPTS_GNU},
ARCH_X86_64
};
}
else if(target_name == "arm-unknown-openbsd")
{
return TargetSpec {
- "unix", "openbsd", "gnu", CodegenMode::Gnu11, "arm-unknown-openbsd",
+ "unix", "openbsd", "gnu", {CodegenMode::Gnu11, "arm-unknown-openbsd", BACKEND_C_OPTS_GNU},
ARCH_ARM32
};
}
else if(target_name == "aarch64-unknown-openbsd")
{
return TargetSpec {
- "unix", "openbsd", "gnu", CodegenMode::Gnu11, "aarch64-unknown-openbsd",
+ "unix", "openbsd", "gnu", {CodegenMode::Gnu11, "aarch64-unknown-openbsd", BACKEND_C_OPTS_GNU},
ARCH_ARM64
};
}
else if(target_name == "x86_64-apple-macosx")
{
+ // NOTE: OSX uses clang and lld, which don't fully support the defaults used for GNU targets
return TargetSpec {
- "unix", "macos", "gnu", CodegenMode::Gnu11, "x86_64-apple-darwin",
+ "unix", "macos", "gnu", {CodegenMode::Gnu11, "x86_64-apple-darwin", {}, {}},
ARCH_X86_64
};
}
@@ -351,6 +417,10 @@ const TargetSpec& Target_GetCurSpec()
{
return g_target;
}
+void Target_ExportCurSpec(const ::std::string& filename)
+{
+ save_spec_to_file(filename, g_target);
+}
void Target_SetCfg(const ::std::string& target_name)
{
g_target = init_from_spec_name(target_name);
diff --git a/src/trans/target.hpp b/src/trans/target.hpp
index 81205831..b1ed9456 100644
--- a/src/trans/target.hpp
+++ b/src/trans/target.hpp
@@ -31,14 +31,20 @@ struct TargetArch
bool ptr;
} m_atomics;
};
+struct BackendOptsC
+{
+ CodegenMode m_codegen_mode;
+ ::std::string m_c_compiler; // MSVC arch / GNU triplet
+ ::std::vector< ::std::string> m_compiler_opts;
+ ::std::vector< ::std::string> m_linker_opts;
+};
struct TargetSpec
{
::std::string m_family;
::std::string m_os_name;
::std::string m_env_name;
- CodegenMode m_codegen_mode;
- ::std::string m_c_compiler; // MSVC arch / GNU triplet
+ BackendOptsC m_backend_c;
TargetArch m_arch;
};
@@ -96,6 +102,8 @@ struct TypeRepr
extern const TargetSpec& Target_GetCurSpec();
extern void Target_SetCfg(const ::std::string& target_name);
+extern void Target_ExportCurSpec(const ::std::string& filename);
+
extern bool Target_GetSizeOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_size);
extern bool Target_GetAlignOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_align);
extern bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_size, size_t& out_align);