diff --git a/lib/std/build.zig b/lib/std/build.zig index d310f53c06..f535b022af 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -1149,6 +1149,7 @@ pub const LibExeObjStep = struct { name_prefix: []const u8, filter: ?[]const u8, single_threaded: bool, + code_model: builtin.CodeModel = .default, root_src: ?FileSource, out_h_filename: []const u8, @@ -1970,6 +1971,11 @@ pub const LibExeObjStep = struct { try zig_args.append("-fno-sanitize-c"); } + if (self.code_model != .default) { + try zig_args.append("-code-model"); + try zig_args.append(@tagName(self.code_model)); + } + switch (self.target) { .Native => {}, .Cross => |cross| { diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index d65b9b08ee..d8f24753d3 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -91,6 +91,21 @@ pub const AtomicRmwOp = enum { Min, }; +/// The code model puts constraints on the location of symbols and the size of code and data. +/// The selection of a code model is a trade off on speed and restrictions that needs to be selected on a per application basis to meet its requirements. +/// A slightly more detailed explanation can be found in (for example) the [System V Application Binary Interface (x86_64)](https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-1.0.pdf) 3.5.1. +/// +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const CodeModel = enum { + default, + tiny, + small, + kernel, + medium, + large, +}; + /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const Mode = enum { diff --git a/src/all_types.hpp b/src/all_types.hpp index c2405127dc..651ea807ad 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1947,6 +1947,15 @@ enum BuildMode { BuildModeSmallRelease, }; +enum CodeModel { + CodeModelDefault, + CodeModelTiny, + CodeModelSmall, + CodeModelKernel, + CodeModelMedium, + CodeModelLarge, +}; + enum EmitFileType { EmitFileTypeBinary, EmitFileTypeAssembly, @@ -2235,6 +2244,7 @@ struct CodeGen { bool enable_dump_analysis; bool enable_doc_generation; bool disable_bin_generation; + CodeModel code_model; Buf *mmacosx_version_min; Buf *mios_version_min; diff --git a/src/codegen.cpp b/src/codegen.cpp index f749b21008..03417f01e5 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8365,6 +8365,25 @@ static bool detect_err_ret_tracing(CodeGen *g) { g->build_mode != BuildModeSmallRelease; } +static LLVMCodeModel to_llvm_code_model(CodeGen *g) { + switch (g->code_model) { + case CodeModelDefault: + return LLVMCodeModelDefault; + case CodeModelTiny: + return LLVMCodeModelTiny; + case CodeModelSmall: + return LLVMCodeModelSmall; + case CodeModelKernel: + return LLVMCodeModelKernel; + case CodeModelMedium: + return LLVMCodeModelMedium; + case CodeModelLarge: + return LLVMCodeModelLarge; + } + + zig_unreachable(); +} + Buf *codegen_generate_builtin_source(CodeGen *g) { g->have_dynamic_link = detect_dynamic_link(g); g->have_pic = detect_pic(g); @@ -8544,6 +8563,34 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { buf_appendf(contents, "pub const position_independent_code = %s;\n", bool_to_str(g->have_pic)); buf_appendf(contents, "pub const strip_debug_info = %s;\n", bool_to_str(g->strip_debug_symbols)); + { + const char *code_model; + switch (g->code_model) { + case CodeModelDefault: + code_model = "default"; + break; + case CodeModelTiny: + code_model = "tiny"; + break; + case CodeModelSmall: + code_model = "small"; + break; + case CodeModelKernel: + code_model = "kernel"; + break; + case CodeModelMedium: + code_model = "medium"; + break; + case CodeModelLarge: + code_model = "large"; + break; + default: + zig_unreachable(); + } + + buf_appendf(contents, "pub const code_model = CodeModel.%s;\n", code_model); + } + { TargetSubsystem detected_subsystem = detect_subsystem(g); if (detected_subsystem != TargetSubsystemAuto) { @@ -8588,6 +8635,7 @@ static Error define_builtin_compile_vars(CodeGen *g) { cache_bool(&cache_hash, g->is_dynamic); cache_bool(&cache_hash, g->is_test_build); cache_bool(&cache_hash, g->is_single_threaded); + cache_int(&cache_hash, g->code_model); cache_int(&cache_hash, g->zig_target->is_native); cache_int(&cache_hash, g->zig_target->arch); cache_int(&cache_hash, g->zig_target->sub_arch); @@ -8745,7 +8793,7 @@ static void init(CodeGen *g) { g->target_machine = ZigLLVMCreateTargetMachine(target_ref, buf_ptr(&g->llvm_triple_str), target_specific_cpu_args, target_specific_features, opt_level, reloc_mode, - LLVMCodeModelDefault, g->function_sections); + to_llvm_code_model(g), g->function_sections); g->target_data_ref = LLVMCreateTargetDataLayout(g->target_machine); @@ -9527,6 +9575,8 @@ Error create_c_object_cache(CodeGen *g, CacheHash **out_cache_hash, bool verbose cache_bool(cache_hash, g->have_sanitize_c); cache_bool(cache_hash, want_valgrind_support(g)); cache_bool(cache_hash, g->function_sections); + cache_int(cache_hash, g->code_model); + for (size_t arg_i = 0; arg_i < g->clang_argv_len; arg_i += 1) { cache_str(cache_hash, g->clang_argv[arg_i]); } @@ -10696,6 +10746,7 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget g->one_possible_values.init(32); g->is_test_build = is_test_build; g->is_single_threaded = false; + g->code_model = CodeModelDefault; buf_resize(&g->global_asm, 0); for (size_t i = 0; i < array_length(symbols_that_llvm_depends_on); i += 1) { diff --git a/src/main.cpp b/src/main.cpp index a844730014..991b46b320 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -103,6 +103,9 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { " -D[macro]=[value] define C [macro] to [value] (1 if [value] omitted)\n" " -target-cpu [cpu] target one specific CPU by name\n" " -target-feature [features] specify the set of CPU features to target\n" + " -code-model [default|tiny| set target code model\n" + " small|kernel|\n" + " medium|large]\n" "\n" "Link Options:\n" " --bundle-compiler-rt for static libraries, include compiler-rt symbols\n" @@ -452,6 +455,7 @@ int main(int argc, char **argv) { bool function_sections = false; const char *cpu = nullptr; const char *features = nullptr; + CodeModel code_model = CodeModelDefault; ZigList llvm_argv = {0}; llvm_argv.append("zig (LLVM option parsing)"); @@ -768,6 +772,23 @@ int main(int argc, char **argv) { clang_argv.append(argv[i]); llvm_argv.append(argv[i]); + } else if (strcmp(arg, "-code-model") == 0) { + if (strcmp(argv[i], "default") == 0) { + code_model = CodeModelDefault; + } else if (strcmp(argv[i], "tiny") == 0) { + code_model = CodeModelTiny; + } else if (strcmp(argv[i], "small") == 0) { + code_model = CodeModelSmall; + } else if (strcmp(argv[i], "kernel") == 0) { + code_model = CodeModelKernel; + } else if (strcmp(argv[i], "medium") == 0) { + code_model = CodeModelMedium; + } else if (strcmp(argv[i], "large") == 0) { + code_model = CodeModelLarge; + } else { + fprintf(stderr, "-code-model options are 'default', 'tiny', 'small', 'kernel', 'medium', or 'large'\n"); + return print_error_usage(arg0); + } } else if (strcmp(arg, "--override-lib-dir") == 0) { override_lib_dir = buf_create_from_str(argv[i]); } else if (strcmp(arg, "--main-pkg-path") == 0) { @@ -1170,6 +1191,7 @@ int main(int argc, char **argv) { codegen_set_errmsg_color(g, color); g->system_linker_hack = system_linker_hack; g->function_sections = function_sections; + g->code_model = code_model; for (size_t i = 0; i < lib_dirs.length; i += 1) {