diff options
Diffstat (limited to 'src/trans/target.cpp')
-rw-r--r-- | src/trans/target.cpp | 508 |
1 files changed, 461 insertions, 47 deletions
diff --git a/src/trans/target.cpp b/src/trans/target.cpp index a91b1225..316749be 100644 --- a/src/trans/target.cpp +++ b/src/trans/target.cpp @@ -12,21 +12,37 @@ #include <map> #include <hir/hir.hpp> #include <hir_typeck/helpers.hpp> +#include <toml.h> // tools/common -TargetArch ARCH_X86_64 = { +const TargetArch ARCH_X86_64 = { "x86_64", 64, false, - { /*atomic(u8)=*/true, false, true, true, true } + TargetArch::Atomics(/*atomic(u8)=*/true, false, true, true, true), + TargetArch::Alignments(2, 4, 8, 16, 4, 8, 8) }; -TargetArch ARCH_X86 = { +const TargetArch ARCH_X86 = { "x86", 32, false, - { /*atomic(u8)=*/true, false, true, false, true } + { /*atomic(u8)=*/true, false, true, false, true }, + TargetArch::Alignments(2, 4, /*u64*/4, /*u128*/4, 4, 4, /*ptr*/4) // u128 has the same alignment as u64, which is u32's alignment. And f64 is 4 byte aligned }; -TargetArch ARCH_ARM32 = { +const TargetArch ARCH_ARM64 = { + "aarch64", + 64, false, + { /*atomic(u8)=*/true, true, true, true, true }, + TargetArch::Alignments(2, 4, 8, 16, 4, 8, 8) +}; +const TargetArch ARCH_ARM32 = { "arm", 32, false, - { /*atomic(u8)=*/true, false, true, false, true } + { /*atomic(u8)=*/true, false, true, false, true }, + TargetArch::Alignments(2, 4, 8, 16, 4, 8, 4) // Note, all types are natively aligned (but i128 will be emulated) +}; +const TargetArch ARCH_M68K = { + "m68k", + 32, true, + { /*atomic(u8)=*/true, false, true, false, true }, + TargetArch::Alignments(2, 2, 2, 2, 2, 2, 2) }; TargetSpec g_target; @@ -37,91 +53,464 @@ namespace { TargetSpec load_spec_from_file(const ::std::string& filename) { - throw ""; + TargetSpec rv; + + TomlFile toml_file(filename); + for(auto key_val : toml_file) + { + // Assertion: The way toml works, there has to be at least two entries in every path. + assert(key_val.path.size() > 1); + DEBUG(key_val.path << " = " << key_val.value); + + auto check_path_length = [&](const TomlKeyValue& kv, unsigned len) { + if( kv.path.size() != len ) { + if( kv.path.size() > len ) { + ::std::cerr << "ERROR: Unexpected sub-node to " << kv.path << " in " << filename << ::std::endl; + } + else { + ::std::cerr << "ERROR: Expected sub-nodes in " << kv.path << " in " << filename << ::std::endl; + } + exit(1); + } + }; + auto check_path_length_min = [&](const TomlKeyValue& kv, unsigned len) { + if( kv.path.size() < len ) { + ::std::cerr << "ERROR: Expected sub-nodes in " << kv.path << " in " << filename << ::std::endl; + } + }; + + try + { + if( key_val.path[0] == "target" ) + { + check_path_length_min(key_val, 2); + if( key_val.path[1] == "family" ) + { + check_path_length(key_val, 2); + rv.m_family = key_val.value.as_string(); + } + else if( key_val.path[1] == "os-name" ) + { + check_path_length(key_val, 2); + rv.m_os_name = key_val.value.as_string(); + } + else if( key_val.path[1] == "env-name" ) + { + check_path_length(key_val, 2); + rv.m_env_name = key_val.value.as_string(); + } + else if( key_val.path[1] == "arch" ) + { + check_path_length(key_val, 2); + if( key_val.value.as_string() == ARCH_ARM32.m_name ) + { + rv.m_arch = ARCH_ARM32; + } + else if( key_val.value.as_string() == ARCH_ARM64.m_name ) + { + rv.m_arch = ARCH_ARM64; + } + else if( key_val.value.as_string() == ARCH_X86.m_name ) + { + rv.m_arch = ARCH_X86; + } + else if( key_val.value.as_string() == ARCH_X86_64.m_name ) + { + rv.m_arch = ARCH_X86_64; + } + else if( key_val.value.as_string() == ARCH_M68K.m_name ) + { + rv.m_arch = ARCH_M68K; + } + else + { + // Error. + ::std::cerr << "ERROR: Unknown architecture name '" << key_val.value.as_string() << "' in " << filename << ::std::endl; + exit(1); + } + } + else + { + // Warning + ::std::cerr << "Warning: Unknown configuration item " << key_val.path[0] << "." << key_val.path[1] << " in " << filename << ::std::endl; + } + } + else if( key_val.path[0] == "backend" ) + { + check_path_length_min(key_val, 2); + if( key_val.path[1] == "c" ) + { + check_path_length_min(key_val, 3); + + if( key_val.path[2] == "variant" ) + { + check_path_length(key_val, 3); + if( key_val.value.as_string() == "msvc" ) + { + rv.m_backend_c.m_codegen_mode = CodegenMode::Msvc; + } + else if( key_val.value.as_string() == "gnu" ) + { + rv.m_backend_c.m_codegen_mode = CodegenMode::Gnu11; + } + else + { + ::std::cerr << "ERROR: Unknown C variant name '" << key_val.value.as_string() << "' in " << filename << ::std::endl; + exit(1); + } + } + else if( key_val.path[2] == "target" ) + { + check_path_length(key_val, 3); + rv.m_backend_c.m_c_compiler = key_val.value.as_string(); + } + else if( key_val.path[2] == "emulate-i128" ) + { + check_path_length(key_val, 3); + rv.m_backend_c.m_emulated_i128 = key_val.value.as_bool(); + } + 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 + { + ::std::cerr << "WARNING: Unknown field backend.c." << key_val.path[2] << " in " << filename << ::std::endl; + } + } + // Does MMIR need configuration? + else + { + ::std::cerr << "WARNING: Unknown configuration item backend." << key_val.path[1] << " in " << filename << ::std::endl; + } + } + else if( key_val.path[0] == "arch" ) + { + check_path_length_min(key_val, 2); + if( key_val.path[1] == "name" ) + { + check_path_length(key_val, 2); + if( rv.m_arch.m_name != "" ) { + ::std::cerr << "ERROR: Architecture already specified to be '" << rv.m_arch.m_name << "'" << ::std::endl; + exit(1); + } + rv.m_arch.m_name = key_val.value.as_string(); + } + else if( key_val.path[1] == "pointer-bits" ) + { + check_path_length(key_val, 2); + rv.m_arch.m_pointer_bits = key_val.value.as_int(); + } + else if( key_val.path[1] == "is-big-endian" ) + { + check_path_length(key_val, 2); + rv.m_arch.m_big_endian = key_val.value.as_bool(); + } + else if( key_val.path[1] == "has-atomic-u8" ) + { + check_path_length(key_val, 2); + rv.m_arch.m_atomics.u8 = key_val.value.as_bool(); + } + else if( key_val.path[1] == "has-atomic-u16" ) + { + check_path_length(key_val, 2); + rv.m_arch.m_atomics.u16 = key_val.value.as_bool(); + } + else if( key_val.path[1] == "has-atomic-u32" ) + { + check_path_length(key_val, 2); + rv.m_arch.m_atomics.u32 = key_val.value.as_bool(); + } + else if( key_val.path[1] == "has-atomic-u64" ) + { + check_path_length(key_val, 2); + rv.m_arch.m_atomics.u64 = key_val.value.as_bool(); + } + else if( key_val.path[1] == "has-atomic-ptr" ) + { + check_path_length(key_val, 2); + rv.m_arch.m_atomics.ptr = key_val.value.as_bool(); + } + else if( key_val.path[1] == "alignments" ) + { + check_path_length(key_val, 3); + if( key_val.path[2] == "u16" ) + { + rv.m_arch.m_alignments.u16 = key_val.value.as_int(); + } + else if( key_val.path[2] == "u32" ) + { + rv.m_arch.m_alignments.u32 = key_val.value.as_int(); + } + else if( key_val.path[2] == "u64" ) + { + rv.m_arch.m_alignments.u64 = key_val.value.as_int(); + } + else if( key_val.path[2] == "u128" ) + { + rv.m_arch.m_alignments.u128 = key_val.value.as_int(); + } + else if( key_val.path[2] == "f32" ) + { + rv.m_arch.m_alignments.f32 = key_val.value.as_int(); + } + else if( key_val.path[2] == "f64" ) + { + rv.m_arch.m_alignments.f64 = key_val.value.as_int(); + } + else if( key_val.path[2] == "ptr" ) + { + rv.m_arch.m_alignments.ptr = key_val.value.as_int(); + } + else + { + ::std::cerr << "WARNING: Unknown field arch.alignments." << key_val.path[1] << " in " << filename << ::std::endl; + } + } + else + { + ::std::cerr << "WARNING: Unknown field arch." << key_val.path[1] << " in " << filename << ::std::endl; + } + } + else + { + ::std::cerr << "WARNING: Unknown configuration item " << key_val.path[0] << " in " << filename << ::std::endl; + } + } + catch(const TomlValue::TypeError& e) + { + ::std::cerr << "ERROR: Invalid type for " << key_val.path << " - " << e << ::std::endl; + exit(1); + } + } + + // TODO: Ensure that everything is set + if( rv.m_arch.m_name == "" ) { + ::std::cerr << "ERROR: Architecture not specified in " << filename << ::std::endl; + exit(1); + } + + 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 = ["; for(const auto& s : spec.m_backend_c.m_compiler_opts) of << "\"" << s << "\","; of << "]\n" + << "linker-opts = ["; for(const auto& s : spec.m_backend_c.m_linker_opts) of << "\"" << s << "\","; of << "]\n" + << "\n" + << "[arch]\n" + << "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" + << "alignments = {" + << " u16 = " << static_cast<int>(spec.m_arch.m_alignments.u16 ) << "," + << " u32 = " << static_cast<int>(spec.m_arch.m_alignments.u32 ) << "," + << " u64 = " << static_cast<int>(spec.m_arch.m_alignments.u64 ) << "," + << " u128 = " << static_cast<int>(spec.m_arch.m_alignments.u128) << "," + << " f32 = " << static_cast<int>(spec.m_arch.m_alignments.f32 ) << "," + << " f64 = " << static_cast<int>(spec.m_arch.m_alignments.f64 ) << "," + << " ptr = " << static_cast<int>(spec.m_arch.m_alignments.ptr ) + << " }\n" + << "\n" + ; } TargetSpec init_from_spec_name(const ::std::string& target_name) { - if( ::std::ifstream(target_name).is_open() ) + // 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 ) { return load_spec_from_file(target_name); } else if(target_name == "i586-linux-gnu") { return TargetSpec { - "unix", "linux", "gnu", CodegenMode::Gnu11, "i586-pc-linux-gnu", + "unix", "linux", "gnu", {CodegenMode::Gnu11, true, "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-pc-linux-gnu", + "unix", "linux", "gnu", {CodegenMode::Gnu11, false, "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, true, "arm-elf-eabi", BACKEND_C_OPTS_GNU}, ARCH_ARM32 }; } + else if(target_name == "aarch64-linux-gnu") + { + return TargetSpec { + "unix", "linux", "gnu", {CodegenMode::Gnu11, false, "aarch64-linux-gnu", BACKEND_C_OPTS_GNU}, + ARCH_ARM64 + }; + } + else if(target_name == "m68k-linux-gnu") + { + return TargetSpec { + "unix", "linux", "gnu", {CodegenMode::Gnu11, true, "m68k-linux-gnu", BACKEND_C_OPTS_GNU}, + ARCH_M68K + }; + } else if(target_name == "i586-windows-gnu") { return TargetSpec { - "windows", "windows", "gnu", CodegenMode::Gnu11, "mingw32", + "windows", "windows", "gnu", {CodegenMode::Gnu11, true, "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, false, "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, true, "x86", {}, {}}, ARCH_X86 }; } else if (target_name == "x86_64-windows-msvc") { return TargetSpec { - "windows", "windows", "msvc", CodegenMode::Msvc, "amd64", + "windows", "windows", "msvc", {CodegenMode::Msvc, true, "amd64", {}, {}}, ARCH_X86_64 }; } + else if(target_name == "i686-unknown-freebsd") + { + return TargetSpec { + "unix", "freebsd", "gnu", {CodegenMode::Gnu11, true, "i686-unknown-freebsd", BACKEND_C_OPTS_GNU}, + ARCH_X86 + }; + } + else if(target_name == "x86_64-unknown-freebsd") + { + return TargetSpec { + "unix", "freebsd", "gnu", {CodegenMode::Gnu11, false, "x86_64-unknown-freebsd", BACKEND_C_OPTS_GNU}, + ARCH_X86_64 + }; + } + else if(target_name == "arm-unknown-freebsd") + { + return TargetSpec { + "unix", "freebsd", "gnu", {CodegenMode::Gnu11, true, "arm-unknown-freebsd", BACKEND_C_OPTS_GNU}, + ARCH_ARM32 + }; + } + else if(target_name == "aarch64-unknown-freebsd") + { + return TargetSpec { + "unix", "freebsd", "gnu", {CodegenMode::Gnu11, false, "aarch64-unknown-freebsd", BACKEND_C_OPTS_GNU}, + ARCH_ARM64 + }; + } else if(target_name == "x86_64-unknown-netbsd") { return TargetSpec { - "unix", "netbsd", "gnu", CodegenMode::Gnu11, "x86_64-unknown-netbsd", + "unix", "netbsd", "gnu", {CodegenMode::Gnu11, false, "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, true, "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, false, "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, true, "arm-unknown-openbsd", BACKEND_C_OPTS_GNU}, ARCH_ARM32 }; } + else if(target_name == "aarch64-unknown-openbsd") + { + return TargetSpec { + "unix", "openbsd", "gnu", {CodegenMode::Gnu11, false, "aarch64-unknown-openbsd", BACKEND_C_OPTS_GNU}, + ARCH_ARM64 + }; + } + else if(target_name == "x86_64-unknown-dragonfly") + { + return TargetSpec { + "unix", "dragonfly", "gnu", {CodegenMode::Gnu11, false, "x86_64-unknown-dragonfly", BACKEND_C_OPTS_GNU}, + ARCH_X86_64 + }; + } + else if(target_name == "x86_64-apple-macosx") + { + // NOTE: OSX uses Mach-O binaries, which don't fully support the defaults used for GNU targets + return TargetSpec { + "unix", "macos", "gnu", {CodegenMode::Gnu11, false, "x86_64-apple-darwin", {}, {}}, + ARCH_X86_64 + }; + } else { ::std::cerr << "Unknown target name '" << target_name << "'" << ::std::endl; @@ -135,6 +524,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); @@ -152,28 +545,41 @@ void Target_SetCfg(const ::std::string& target_name) Cfg_SetFlag("linux"); Cfg_SetValue("target_vendor", "gnu"); } - Cfg_SetValue("target_env", g_target.m_env_name); + + if( g_target.m_os_name == "freebsd" ) + { + Cfg_SetFlag("freebsd"); + Cfg_SetValue("target_vendor", "unknown"); + } if( g_target.m_os_name == "netbsd" ) { Cfg_SetFlag("netbsd"); Cfg_SetValue("target_vendor", "unknown"); } - Cfg_SetValue("target_env", g_target.m_env_name); if( g_target.m_os_name == "openbsd" ) { Cfg_SetFlag("openbsd"); Cfg_SetValue("target_vendor", "unknown"); } - Cfg_SetValue("target_env", g_target.m_env_name); + if( g_target.m_os_name == "dragonfly" ) + { + Cfg_SetFlag("dragonfly"); + Cfg_SetValue("target_vendor", "unknown"); + } + + Cfg_SetValue("target_env", g_target.m_env_name); Cfg_SetValue("target_os", g_target.m_os_name); Cfg_SetValue("target_pointer_width", FMT(g_target.m_arch.m_pointer_bits)); Cfg_SetValue("target_endian", g_target.m_arch.m_big_endian ? "big" : "little"); Cfg_SetValue("target_arch", g_target.m_arch.m_name); Cfg_SetValueCb("target_has_atomic", [&](const ::std::string& s) { if(s == "8") return g_target.m_arch.m_atomics.u8; // Has an atomic byte + if(s == "16") return g_target.m_arch.m_atomics.u16; + if(s == "32") return g_target.m_arch.m_atomics.u32; + if(s == "64") return g_target.m_arch.m_atomics.u64; if(s == "ptr") return g_target.m_arch.m_atomics.ptr; // Has an atomic pointer-sized value return false; }); @@ -233,8 +639,9 @@ namespace { { case ::HIR::Struct::Repr::Packed: packed = true; - TODO(sp, "make_struct_repr - repr(packed)"); // needs codegen help + TODO(sp, "make_struct_repr - repr(packed)"); // needs codegen to know to pack the structure break; + case ::HIR::Struct::Repr::Simd: case ::HIR::Struct::Repr::C: // No sorting, no packing break; @@ -314,8 +721,6 @@ const StructRepr* Target_GetStructRepr(const Span& sp, const StaticTraitResolve& return ires.first->second.get(); } -// TODO: Include NonZero and other repr optimisations here - bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::TypeRef& ty, size_t& out_size, size_t& out_align) { TRACE_FUNCTION_FR(ty, "size=" << out_size << ", align=" << out_align); @@ -335,42 +740,45 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve, case ::HIR::CoreType::U8: case ::HIR::CoreType::I8: out_size = 1; - out_align = 1; + out_align = 1; // u8 is always 1 aligned return true; case ::HIR::CoreType::U16: case ::HIR::CoreType::I16: out_size = 2; - out_align = 2; + out_align = g_target.m_arch.m_alignments.u16; return true; case ::HIR::CoreType::U32: case ::HIR::CoreType::I32: case ::HIR::CoreType::Char: out_size = 4; - out_align = 4; + out_align = g_target.m_arch.m_alignments.u32; return true; case ::HIR::CoreType::U64: case ::HIR::CoreType::I64: out_size = 8; - out_align = 8; + out_align = g_target.m_arch.m_alignments.u64; return true; case ::HIR::CoreType::U128: case ::HIR::CoreType::I128: out_size = 16; - // TODO: If i128 is emulated, this can be 8 - out_align = 16; + // TODO: If i128 is emulated, this can be 8 (as it is on x86, where it's actually 4 due to the above comment) + if( g_target.m_backend_c.m_emulated_i128 ) + out_align = g_target.m_arch.m_alignments.u64; + else + out_align = g_target.m_arch.m_alignments.u128; return true; case ::HIR::CoreType::Usize: case ::HIR::CoreType::Isize: out_size = g_target.m_arch.m_pointer_bits / 8; - out_align = g_target.m_arch.m_pointer_bits / 8; + out_align = g_target.m_arch.m_alignments.ptr; return true; case ::HIR::CoreType::F32: out_size = 4; - out_align = 4; + out_align = g_target.m_arch.m_alignments.f32; return true; case ::HIR::CoreType::F64: out_size = 8; - out_align = 8; + out_align = g_target.m_arch.m_alignments.f64; return true; case ::HIR::CoreType::Str: DEBUG("sizeof on a `str` - unsized"); @@ -472,8 +880,7 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const StaticTraitResolve& resolve, return true; ), (Closure, - // TODO. - DEBUG("TODO Closure - " << ty); + BUG(sp, "Encountered closure type at trans stage - " << ty); ) ) return false; @@ -557,10 +964,12 @@ namespace { switch(str.m_repr) { case ::HIR::Struct::Repr::Packed: + // packed, not sorted packed = true; - TODO(sp, "make_struct_repr - repr(packed)"); // needs codegen help + // NOTE: codegen_c checks m_repr for packing too break; case ::HIR::Struct::Repr::C: + case ::HIR::Struct::Repr::Simd: // No sorting, no packing break; case ::HIR::Struct::Repr::Rust: @@ -580,10 +989,6 @@ namespace { DEBUG("Can't get size/align of " << t); return nullptr; } - if( size == SIZE_MAX ) - { - TODO(sp, "Unsized type in struct - " << t); - } ents.push_back(Ent { idx++, size, align }); fields.push_back(TypeRepr::Field { 0, t.clone() }); } @@ -596,9 +1001,12 @@ namespace { if( allow_sort ) { - // TODO: Sort by alignment then size (largest first) - // - Requires codegen to use this information + // Sort by alignment then size (largest first) // - NOTE: ?Sized fields (which includes unsized fields) MUST be at the end, even after monomorph + // - This means that this code needs to know if a field was ?Sized + // TODO: Determine if a field was from a ?Sized generic (so should be fixed as last) + //auto cmpfn_lt = [](const Ent& a, const Ent& b){ return a.align == b.align ? a.size < b.size : a.align < b.size; }; + //::std::sort(ents.begin(), ents.end(), cmpfn_lt); } TypeRepr rv; @@ -619,7 +1027,7 @@ namespace { fields[e.field].offset = cur_ofs; if( e.size == SIZE_MAX ) { - // TODO: Ensure that this is the last item + // Ensure that this is the last item ASSERT_BUG(sp, &e == &ents.back(), "Unsized item isn't the last item in " << ty); cur_ofs = SIZE_MAX; } @@ -664,6 +1072,13 @@ namespace { return true; } } + // Handle the NonZero lang item (Note: Checks just the simplepath part) + if( te.path.m_data.as_Generic().m_path == resolve.m_crate.get_lang_item_path(sp, "non_zero") ) + { + out_path.sub_fields.push_back(0); + out_path.size = r->size; + return true; + } } } break; TU_ARM(ty.m_data, Borrow, _te) { (void)_te; @@ -707,6 +1122,7 @@ namespace { { nz_path.index = 1; ::std::reverse(nz_path.sub_fields.begin(), nz_path.sub_fields.end()); + DEBUG("nz_path = " << nz_path.sub_fields); size_t max_size = 0; size_t max_align = 0; for(auto& t : mono_types) @@ -757,7 +1173,7 @@ namespace { max_size ++; } size_t tag_size = 0; - // TODO: repr(C) enums + // TODO: repr(C) enums - they have different rules if( mono_types.size() == 0 ) { // Unreachable } @@ -802,8 +1218,6 @@ namespace { { ASSERT_BUG(sp, max_size == 0, "Zero alignment, but non-zero size"); } - - // TODO: Variants. } } break; TU_ARM(enm.m_data, Value, e) { |