diff --git a/BRANCH_TODO b/BRANCH_TODO index 221d2ec28b..c5af55bbf2 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,4 +1,3 @@ - * integrate code model and have_frame_pointer to main() and c objects * integrate target features into building C source files * integrate target features into building assembly code * handle .d files from c objects diff --git a/src-self-hosted/Compilation.zig b/src-self-hosted/Compilation.zig index 90ff6c9a80..484f43e4ab 100644 --- a/src-self-hosted/Compilation.zig +++ b/src-self-hosted/Compilation.zig @@ -271,6 +271,7 @@ pub const InitOptions = struct { self_exe_path: ?[]const u8 = null, version: ?std.builtin.Version = null, libc_installation: ?*const LibCInstallation = null, + machine_code_model: std.builtin.CodeModel = .default, }; pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { @@ -319,6 +320,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { // We would also want to prefer LLVM for architectures that we don't have self-hosted support for too. break :blk false; }; + if (!use_llvm and options.machine_code_model != .default) { + return error.MachineCodeModelNotSupported; + } const is_exe_or_dyn_lib = switch (options.output_mode) { .Obj => false, @@ -425,6 +429,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { cache.hash.add(options.strip); cache.hash.add(options.link_libc); cache.hash.add(options.output_mode); + cache.hash.add(options.machine_code_model); // TODO audit this and make sure everything is in it const module: ?*Module = if (options.root_pkg) |root_pkg| blk: { @@ -593,6 +598,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { .stack_check = stack_check, .single_threaded = single_threaded, .debug_link = options.debug_link, + .machine_code_model = options.machine_code_model, }); errdefer bin_file.destroy(); @@ -964,10 +970,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { ch.hash.addListOfBytes(comp.clang_argv); ch.hash.add(comp.bin_file.options.link_libcpp); ch.hash.addListOfBytes(comp.libc_include_dir_list); - // TODO - //cache_int(cache_hash, g->code_model); - //cache_bool(cache_hash, codegen_have_frame_pointer(g)); - _ = try ch.addFile(c_object.src_path, null); + _ = try ch.addFile(c_object.src.src_path, null); { // Hash the extra flags, with special care to call addFile for file parameters. // TODO this logic can likely be improved by utilizing clang_options_data.zig. @@ -989,7 +992,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { defer arena_allocator.deinit(); const arena = &arena_allocator.allocator; - const c_source_basename = std.fs.path.basename(c_object.src_path); + const c_source_basename = std.fs.path.basename(c_object.src.src_path); // Special case when doing build-obj for just one C file. When there are more than one object // file and building an object we need to link them together, but with just one it should go // directly to the output file. @@ -1012,14 +1015,14 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { try argv.appendSlice(&[_][]const u8{ self_exe_path, "clang", "-c" }); - const ext = classifyFileExt(c_object.src_path); + const ext = classifyFileExt(c_object.src.src_path); // TODO capture the .d file and deal with caching stuff try comp.addCCArgs(arena, &argv, ext, false, null); try argv.append("-o"); try argv.append(out_obj_path); - try argv.append(c_object.src_path); + try argv.append(c_object.src.src_path); try argv.appendSlice(c_object.src.extra_flags); if (comp.debug_cc) { @@ -1095,7 +1098,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { try std.os.renameat(zig_cache_tmp_dir.fd, tmp_basename, o_dir.fd, o_basename); ch.writeManifest() catch |err| { - std.log.warn("failed to write cache manifest when compiling '{}': {}", .{ c_object.src_path, @errorName(err) }); + std.log.warn("failed to write cache manifest when compiling '{}': {}", .{ c_object.src.src_path, @errorName(err) }); }; break :blk digest; }; @@ -1219,6 +1222,10 @@ fn addCCArgs( // flag = SplitIterator_next(&it); // } //} + const mcmodel = comp.bin_file.options.machine_code_model; + if (mcmodel != .default) { + try argv.append(try std.fmt.allocPrint(arena, "-mcmodel={}", .{@tagName(mcmodel)})); + } if (translate_c) { // This gives us access to preprocessing entities, presumably at the cost of performance. try argv.append("-Xclang"); @@ -1432,6 +1439,9 @@ test "classifyFileExt" { } fn haveFramePointer(comp: *Compilation) bool { + // If you complicate this logic make sure you update the parent cache hash. + // Right now it's not in the cache hash because the value depends on optimize_mode + // and strip which are both already part of the hash. return switch (comp.bin_file.options.optimize_mode) { .Debug, .ReleaseSafe => !comp.bin_file.options.strip, .ReleaseSmall, .ReleaseFast => false, diff --git a/src-self-hosted/link.zig b/src-self-hosted/link.zig index 4d3fd5085d..cdeb2b5e5c 100644 --- a/src-self-hosted/link.zig +++ b/src-self-hosted/link.zig @@ -24,6 +24,7 @@ pub const Options = struct { link_mode: std.builtin.LinkMode, object_format: std.builtin.ObjectFormat, optimize_mode: std.builtin.Mode, + machine_code_model: std.builtin.CodeModel, root_name: []const u8, /// Not every Compilation compiles .zig code! For example you could do `zig build-exe foo.o`. module: ?*Module, diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig index 6ec2c45531..fcf548a2d6 100644 --- a/src-self-hosted/main.zig +++ b/src-self-hosted/main.zig @@ -183,6 +183,9 @@ const usage_build_generic = \\Compile Options: \\ -target [name] -- see the targets command \\ -mcpu [cpu] Specify target CPU and feature set + \\ -mcmodel=[default|tiny| Limit range of code and data virtual addresses + \\ small|kernel| + \\ medium|large] \\ --name [name] Override output name \\ --mode [mode] Set the build mode \\ Debug (default) optimizations off, safety on @@ -306,6 +309,7 @@ pub fn buildOutputType( var use_clang: ?bool = null; var link_eh_frame_hdr = false; var libc_paths_file: ?[]const u8 = null; + var machine_code_model: std.builtin.CodeModel = .default; var system_libs = std.ArrayList([]const u8).init(gpa); defer system_libs.deinit(); @@ -446,10 +450,16 @@ pub fn buildOutputType( if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg}); i += 1; target_mcpu = args[i]; + } else if (mem.eql(u8, arg, "-mcmodel")) { + if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg}); + i += 1; + machine_code_model = parseCodeModel(args[i]); } else if (mem.startsWith(u8, arg, "-ofmt=")) { target_ofmt = arg["-ofmt=".len..]; } else if (mem.startsWith(u8, arg, "-mcpu=")) { target_mcpu = arg["-mcpu=".len..]; + } else if (mem.startsWith(u8, arg, "-mcmodel=")) { + machine_code_model = parseCodeModel(arg["-mcmodel=".len..]); } else if (mem.eql(u8, arg, "--dynamic-linker")) { if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg}); i += 1; @@ -1150,6 +1160,7 @@ pub fn buildOutputType( .libc_installation = if (libc_installation) |*lci| lci else null, .debug_cc = debug_cc, .debug_link = debug_link, + .machine_code_model = machine_code_model, }) catch |err| { fatal("unable to create compilation: {}", .{@errorName(err)}); }; @@ -1917,3 +1928,8 @@ fn is_libcpp_lib_name(target: std.Target, name: []const u8) bool { eqlIgnoreCase(ignore_case, name, "stdc++") or eqlIgnoreCase(ignore_case, name, "c++abi"); } + +fn parseCodeModel(arg: []const u8) std.builtin.CodeModel { + return std.meta.stringToEnum(std.builtin.CodeModel, arg) orelse + fatal("unsupported machine code model: '{}'", .{arg}); +}