From 5b2a79848ced20db80f3f4ce46b3ef7f4a051d53 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 11 Jan 2021 22:01:16 -0700 Subject: [PATCH] stage2: cleanups regarding red zone CLI flags * CLI: change to -mred-zone and -mno-red-zone to match gcc/clang. * build.zig: remove the double negative and make it an optional bool. This follows precedent from other flags, allowing the compiler CLI to be the decider of what is default instead of duplicating the default value into the build system code. * Compilation: make it an optional `want_red_zone` instead of a `no_red_zone` bool. The default is decided by a call to `target_util.hasRedZone`. * When creating a Clang command line, put -mred-zone on the command line if we are forcing it to be enabled. * Update update_clang_options.zig with respect to the recent {s}/{} format changes. * `zig cc` integration with red zone preference. --- lib/std/build.zig | 11 ++++-- src/Compilation.zig | 21 ++++++----- src/clang_options_data.zig | 18 ++++++++-- src/glibc.zig | 2 +- src/libcxx.zig | 4 +-- src/libunwind.zig | 2 +- src/link.zig | 2 +- src/main.zig | 20 ++++++----- src/musl.zig | 2 +- src/stage1.zig | 2 +- src/stage1/all_types.hpp | 2 +- src/stage1/codegen.cpp | 4 +-- src/stage1/stage1.cpp | 2 +- src/stage1/stage1.h | 2 +- src/target.zig | 18 ++++++++++ tools/update_clang_options.zig | 64 +++++++++++++++++++--------------- 16 files changed, 114 insertions(+), 62 deletions(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index 869671c785a14cd2d41f1876e58295c2120130d8..381488d80092b5f4618a824082c549bfbf2af6a6 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -1262,7 +1262,6 @@ pub const LibExeObjStep = struct { disable_stack_probing: bool, disable_sanitize_c: bool, sanitize_thread: bool, - no_red_zone: bool = false, rdynamic: bool, c_std: Builder.CStd, override_lib_dir: ?[]const u8, @@ -1333,6 +1332,8 @@ pub const LibExeObjStep = struct { /// Position Independent Executable pie: ?bool = null, + red_zone: ?bool = null, + subsystem: ?builtin.SubSystem = null, /// Overrides the default stack size @@ -2261,8 +2262,12 @@ pub const LibExeObjStep = struct { if (self.disable_stack_probing) { try zig_args.append("-fno-stack-check"); } - if (self.no_red_zone) { - try zig_args.append("-fno-red-zone"); + if (self.red_zone) |red_zone| { + if (red_zone) { + try zig_args.append("-mred-zone"); + } else { + try zig_args.append("-mno-red-zone"); + } } if (self.disable_sanitize_c) { try zig_args.append("-fno-sanitize-c"); diff --git a/src/Compilation.zig b/src/Compilation.zig index 1588544010395cd4cf56d9b162ccd03f6bd71d0f..0efad3362d93b94747a4a948b5e6d76781bcab6d 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -392,7 +392,7 @@ pub const InitOptions = struct { want_pie: ?bool = null, want_sanitize_c: ?bool = null, want_stack_check: ?bool = null, - no_red_zone: bool = false, + want_red_zone: ?bool = null, want_valgrind: ?bool = null, want_tsan: ?bool = null, want_compiler_rt: ?bool = null, @@ -744,6 +744,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { } else null; const strip = options.strip or !target_util.hasDebugInfo(options.target); + const red_zone = options.want_red_zone orelse target_util.hasRedZone(options.target); // We put everything into the cache hash that *cannot be modified during an incremental update*. // For example, one cannot change the target between updates, but one can change source files, @@ -774,7 +775,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { cache.hash.add(pie); cache.hash.add(tsan); cache.hash.add(stack_check); - cache.hash.add(options.no_red_zone); + cache.hash.add(red_zone); cache.hash.add(link_mode); cache.hash.add(options.function_sections); cache.hash.add(strip); @@ -984,7 +985,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { .valgrind = valgrind, .tsan = tsan, .stack_check = stack_check, - .no_red_zone = options.no_red_zone, + .red_zone = red_zone, .single_threaded = single_threaded, .verbose_link = options.verbose_link, .machine_code_model = options.machine_code_model, @@ -2258,11 +2259,13 @@ pub fn addCCArgs( } else if (!comp.sanitize_c and comp.bin_file.options.tsan) { try argv.append("-fsanitize=thread"); } - - if (comp.bin_file.options.no_red_zone) { + + if (comp.bin_file.options.red_zone) { + try argv.append("-mred-zone"); + } else if (target_util.hasRedZone(target)) { try argv.append("-mno-red-zone"); } - + switch (comp.bin_file.options.optimize_mode) { .Debug => { // windows c runtime requires -D_DEBUG if using debug libraries @@ -2967,7 +2970,7 @@ fn buildOutputFromZig( .function_sections = true, .want_sanitize_c = false, .want_stack_check = false, - .no_red_zone = comp.bin_file.options.no_red_zone, + .want_red_zone = comp.bin_file.options.red_zone, .want_valgrind = false, .want_tsan = false, .want_pic = comp.bin_file.options.pic, @@ -3206,7 +3209,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node .tsan_enabled = comp.bin_file.options.tsan, .function_sections = comp.bin_file.options.function_sections, .enable_stack_probing = comp.bin_file.options.stack_check, - .no_red_zone = comp.bin_file.options.no_red_zone, + .red_zone = comp.bin_file.options.red_zone, .enable_time_report = comp.time_report, .enable_stack_report = comp.stack_report, .test_is_evented = comp.test_evented_io, @@ -3351,7 +3354,7 @@ pub fn build_crt_file( .optimize_mode = comp.compilerRtOptMode(), .want_sanitize_c = false, .want_stack_check = false, - .no_red_zone = comp.bin_file.options.no_red_zone, + .want_red_zone = comp.bin_file.options.red_zone, .want_valgrind = false, .want_tsan = false, .want_pic = comp.bin_file.options.pic, diff --git a/src/clang_options_data.zig b/src/clang_options_data.zig index 52dc8c0280415b035d485ee5433cefb86757894a..c901c6045fa47c520e0e99947bb10518c54ec2e2 100644 --- a/src/clang_options_data.zig +++ b/src/clang_options_data.zig @@ -3803,7 +3803,14 @@ flagpd1("mno-qpx"), flagpd1("mno-rdpid"), flagpd1("mno-rdrnd"), flagpd1("mno-rdseed"), -flagpd1("mno-red-zone"), +.{ + .name = "mno-red-zone", + .syntax = .flag, + .zig_equivalent = .no_red_zone, + .pd1 = true, + .pd2 = false, + .psl = false, +}, flagpd1("mno-reference-types"), flagpd1("mno-relax"), flagpd1("mno-relax-all"), @@ -3901,7 +3908,14 @@ flagpd1("mrdseed"), flagpd1("mreassociate"), flagpd1("mrecip"), flagpd1("mrecord-mcount"), -flagpd1("mred-zone"), +.{ + .name = "mred-zone", + .syntax = .flag, + .zig_equivalent = .red_zone, + .pd1 = true, + .pd2 = false, + .psl = false, +}, flagpd1("mreference-types"), sepd1("mregparm"), flagpd1("mrelax"), diff --git a/src/glibc.zig b/src/glibc.zig index 28ed31f7bbed930ad1cfd238ca459159c760618d..b154bd530de96da22a55fbd23cf4b03b910aa65a 100644 --- a/src/glibc.zig +++ b/src/glibc.zig @@ -934,7 +934,7 @@ fn buildSharedLib( .optimize_mode = comp.compilerRtOptMode(), .want_sanitize_c = false, .want_stack_check = false, - .no_red_zone = comp.bin_file.options.no_red_zone, + .want_red_zone = comp.bin_file.options.red_zone, .want_valgrind = false, .want_tsan = false, .emit_h = null, diff --git a/src/libcxx.zig b/src/libcxx.zig index dc9fdc15e7cc957979aa3d86804bffce0c94b80c..11989998e92fff0b656d9fd9200e19e7c979a2be 100644 --- a/src/libcxx.zig +++ b/src/libcxx.zig @@ -167,7 +167,7 @@ pub fn buildLibCXX(comp: *Compilation) !void { .link_mode = link_mode, .want_sanitize_c = false, .want_stack_check = false, - .no_red_zone = comp.bin_file.options.no_red_zone, + .want_red_zone = comp.bin_file.options.red_zone, .want_valgrind = false, .want_tsan = comp.bin_file.options.tsan, .want_pic = comp.bin_file.options.pic, @@ -285,7 +285,7 @@ pub fn buildLibCXXABI(comp: *Compilation) !void { .link_mode = link_mode, .want_sanitize_c = false, .want_stack_check = false, - .no_red_zone = comp.bin_file.options.no_red_zone, + .want_red_zone = comp.bin_file.options.red_zone, .want_valgrind = false, .want_tsan = comp.bin_file.options.tsan, .want_pic = comp.bin_file.options.pic, diff --git a/src/libunwind.zig b/src/libunwind.zig index cfc0cb00aa2386f49170ccac552674ad4d9eda47..c2d0475d6fa4146dd14112a2bfde2eca2fdba9ad 100644 --- a/src/libunwind.zig +++ b/src/libunwind.zig @@ -108,7 +108,7 @@ pub fn buildStaticLib(comp: *Compilation) !void { .link_mode = link_mode, .want_sanitize_c = false, .want_stack_check = false, - .no_red_zone = comp.bin_file.options.no_red_zone, + .want_red_zone = comp.bin_file.options.red_zone, .want_valgrind = false, .want_tsan = false, .want_pic = comp.bin_file.options.pic, diff --git a/src/link.zig b/src/link.zig index 04cfce99abc23e2cd8e43cf260a77f92fab0ab63..6914131beaee8998171cc11c347b458e011da82a 100644 --- a/src/link.zig +++ b/src/link.zig @@ -77,7 +77,7 @@ pub const Options = struct { valgrind: bool, tsan: bool, stack_check: bool, - no_red_zone: bool, + red_zone: bool, single_threaded: bool, verbose_link: bool, dll_export_fns: bool, diff --git a/src/main.zig b/src/main.zig index a7a23c2b2deabec854fc7d65f41772dcdd8f4a7e..867aa348b17ba3c3585fb2ddb9c56359162d27cc 100644 --- a/src/main.zig +++ b/src/main.zig @@ -267,6 +267,8 @@ const usage_build_generic = \\ -mcmodel=[default|tiny| Limit range of code and data virtual addresses \\ small|kernel| \\ medium|large] + \\ -mred-zone Force-enable the "red-zone" + \\ -mno-red-zone Force-disable the "red-zone" \\ --name [name] Override root name (not a file path) \\ -O [mode] Choose what to optimize for \\ Debug (default) Optimizations off, safety on @@ -282,8 +284,6 @@ const usage_build_generic = \\ -fno-PIE Force-disable Position Independent Executable \\ -fstack-check Enable stack probing in unsafe builds \\ -fno-stack-check Disable stack probing in safe builds - \\ -fred-zone Enable the "red-zone" - \\ -fno-red-zone Disable the "red-zone" \\ -fsanitize-c Enable C undefined behavior detection in unsafe builds \\ -fno-sanitize-c Disable C undefined behavior detection in safe builds \\ -fvalgrind Include valgrind client requests in release builds @@ -507,7 +507,7 @@ fn buildOutputType( var want_pie: ?bool = null; var want_sanitize_c: ?bool = null; var want_stack_check: ?bool = null; - var no_red_zone: bool = false; + var want_red_zone: ?bool = null; var want_valgrind: ?bool = null; var want_tsan: ?bool = null; var want_compiler_rt: ?bool = null; @@ -846,10 +846,10 @@ fn buildOutputType( want_stack_check = true; } else if (mem.eql(u8, arg, "-fno-stack-check")) { want_stack_check = false; - } else if (mem.eql(u8, arg, "-fred-zone")) { - no_red_zone = false; - } else if (mem.eql(u8, arg, "-fno-red-zone")) { - no_red_zone = true; + } else if (mem.eql(u8, arg, "-mred-zone")) { + want_red_zone = true; + } else if (mem.eql(u8, arg, "-mno-red-zone")) { + want_red_zone = false; } else if (mem.eql(u8, arg, "-fsanitize-c")) { want_sanitize_c = true; } else if (mem.eql(u8, arg, "-fno-sanitize-c")) { @@ -1075,6 +1075,8 @@ fn buildOutputType( .no_pic => want_pic = false, .pie => want_pie = true, .no_pie => want_pie = false, + .red_zone => want_red_zone = true, + .no_red_zone => want_red_zone = false, .nostdlib => ensure_libc_on_non_freestanding = false, .nostdlib_cpp => ensure_libcpp_on_non_freestanding = false, .shared => { @@ -1767,7 +1769,7 @@ fn buildOutputType( .want_pie = want_pie, .want_sanitize_c = want_sanitize_c, .want_stack_check = want_stack_check, - .no_red_zone = no_red_zone, + .want_red_zone = want_red_zone, .want_valgrind = want_valgrind, .want_tsan = want_tsan, .want_compiler_rt = want_compiler_rt, @@ -2977,6 +2979,8 @@ pub const ClangArgIterator = struct { framework_dir, framework, nostdlibinc, + red_zone, + no_red_zone, }; const Args = struct { diff --git a/src/musl.zig b/src/musl.zig index d9060307d08b46539344de2133d05ae12eccae64..0cb6983e2846448967f51ce6496d56d49e311e47 100644 --- a/src/musl.zig +++ b/src/musl.zig @@ -206,7 +206,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void { .optimize_mode = comp.compilerRtOptMode(), .want_sanitize_c = false, .want_stack_check = false, - .no_red_zone = comp.bin_file.options.no_red_zone, + .want_red_zone = comp.bin_file.options.red_zone, .want_valgrind = false, .want_tsan = false, .emit_h = null, diff --git a/src/stage1.zig b/src/stage1.zig index 721ab93fcddf3dd4c1f5fe24cfe74c0c61e79159..44fd8e109e603238593717680b3325463af522a2 100644 --- a/src/stage1.zig +++ b/src/stage1.zig @@ -119,7 +119,7 @@ pub const Module = extern struct { tsan_enabled: bool, function_sections: bool, enable_stack_probing: bool, - no_red_zone: bool, + red_zone: bool, enable_time_report: bool, enable_stack_report: bool, test_is_evented: bool, diff --git a/src/stage1/all_types.hpp b/src/stage1/all_types.hpp index af8305d4b01301dd49500d0db479e37df9acb10a..c235bb362d23a60356a06d027df66b1df31aa580 100644 --- a/src/stage1/all_types.hpp +++ b/src/stage1/all_types.hpp @@ -2195,7 +2195,7 @@ struct CodeGen { bool link_mode_dynamic; bool dll_export_fns; bool have_stack_probing; - bool no_red_zone; + bool red_zone; bool function_sections; bool test_is_evented; bool valgrind_enabled; diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp index fbc13f2638057336329175e32fc3613d61cd81af..10943483f4088e778064adcde4802f7118140970 100644 --- a/src/stage1/codegen.cpp +++ b/src/stage1/codegen.cpp @@ -513,8 +513,8 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { } else { maybe_import_dll(g, llvm_fn, linkage); } - - if (g->no_red_zone) { + + if (!g->red_zone) { addLLVMFnAttr(llvm_fn, "noredzone"); } diff --git a/src/stage1/stage1.cpp b/src/stage1/stage1.cpp index 7cf34c9a47b1825a1f937903fb0f6b6f7e11b021..d680121577689e161a56467fb146d95a64afe7fa 100644 --- a/src/stage1/stage1.cpp +++ b/src/stage1/stage1.cpp @@ -91,7 +91,7 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) { g->have_pic = stage1->pic; g->have_pie = stage1->pie; g->have_stack_probing = stage1->enable_stack_probing; - g->no_red_zone = stage1->no_red_zone; + g->red_zone = stage1->red_zone; g->is_single_threaded = stage1->is_single_threaded; g->valgrind_enabled = stage1->valgrind_enabled; g->tsan_enabled = stage1->tsan_enabled; diff --git a/src/stage1/stage1.h b/src/stage1/stage1.h index 66e0effbf68fce6a2e81d00f0479bead333969e4..6db3621cf5f235c4265d9086362a6bfe8afd444d 100644 --- a/src/stage1/stage1.h +++ b/src/stage1/stage1.h @@ -188,7 +188,7 @@ struct ZigStage1 { bool tsan_enabled; bool function_sections; bool enable_stack_probing; - bool no_red_zone; + bool red_zone; bool enable_time_report; bool enable_stack_report; bool test_is_evented; diff --git a/src/target.zig b/src/target.zig index daac577c7bdf4424b988d9c5ba245c60e0e7b595..c3df682ce0a228c7c23aabfcdfeee874be57c92c 100644 --- a/src/target.zig +++ b/src/target.zig @@ -349,3 +349,21 @@ pub fn defaultCompilerRtOptimizeMode(target: std.Target) std.builtin.Mode { return .ReleaseFast; } } + +pub fn hasRedZone(target: std.Target) bool { + return switch (target.cpu.arch) { + .x86_64, + .i386, + .wasm32, + .wasm64, + .powerpc, + .powerpc64, + .powerpc64le, + .aarch64, + .aarch64_be, + .aarch64_32, + => true, + + else => false, + }; +} diff --git a/tools/update_clang_options.zig b/tools/update_clang_options.zig index ad380e0139d3465ed74dcd22e1f83ea342575aa9..189a2ed7faad82668d6b7b4e91506f93cd364129 100644 --- a/tools/update_clang_options.zig +++ b/tools/update_clang_options.zig @@ -248,6 +248,14 @@ const known_options = [_]KnownOpt{ .name = "mtune", .ident = "mcpu", }, + .{ + .name = "mred-zone", + .ident = "red_zone", + }, + .{ + .name = "mno-red-zone", + .ident = "no_red_zone", + }, .{ .name = "MD", .ident = "dep_file", @@ -340,9 +348,9 @@ pub fn main() anyerror!void { const child_args = [_][]const u8{ llvm_tblgen_exe, "--dump-json", - try std.fmt.allocPrint(allocator, "{}/clang/include/clang/Driver/Options.td", .{llvm_src_root}), - try std.fmt.allocPrint(allocator, "-I={}/llvm/include", .{llvm_src_root}), - try std.fmt.allocPrint(allocator, "-I={}/clang/include/clang/Driver", .{llvm_src_root}), + try std.fmt.allocPrint(allocator, "{s}/clang/include/clang/Driver/Options.td", .{llvm_src_root}), + try std.fmt.allocPrint(allocator, "-I={s}/llvm/include", .{llvm_src_root}), + try std.fmt.allocPrint(allocator, "-I={s}/clang/include/clang/Driver", .{llvm_src_root}), }; const child_result = try std.ChildProcess.exec(.{ @@ -351,11 +359,11 @@ pub fn main() anyerror!void { .max_output_bytes = 100 * 1024 * 1024, }); - std.debug.warn("{}\n", .{child_result.stderr}); + std.debug.warn("{s}\n", .{child_result.stderr}); const json_text = switch (child_result.term) { .Exited => |code| if (code == 0) child_result.stdout else { - std.debug.warn("llvm-tblgen exited with code {}\n", .{code}); + std.debug.warn("llvm-tblgen exited with code {d}\n", .{code}); std.process.exit(1); }, else => { @@ -412,7 +420,7 @@ pub fn main() anyerror!void { } else if (std.mem.eql(u8, prefix, "/")) { pslash = true; } else { - std.debug.warn("{} has unrecognized prefix '{}'\n", .{ name, prefix }); + std.debug.warn("{s} has unrecognized prefix '{s}'\n", .{ name, prefix }); std.process.exit(1); } } @@ -422,7 +430,7 @@ pub fn main() anyerror!void { // `-MT foo` is ambiguous because there is also an -MT flag // The canonical way to specify the flag is with `/MT` and so we make this // the only way. - try stdout.print("flagpsl(\"{}\"),\n", .{name}); + try stdout.print("flagpsl(\"{s}\"),\n", .{name}); } else if (knownOption(name)) |ident| { // Workaround the fact that in 'Options.td' -Ofast is listed as 'joined' @@ -430,34 +438,34 @@ pub fn main() anyerror!void { try stdout.print( \\.{{ - \\ .name = "{}", - \\ .syntax = {}, - \\ .zig_equivalent = .{}, - \\ .pd1 = {}, - \\ .pd2 = {}, - \\ .psl = {}, + \\ .name = "{s}", + \\ .syntax = {s}, + \\ .zig_equivalent = .{s}, + \\ .pd1 = {s}, + \\ .pd2 = {s}, + \\ .psl = {s}, \\}}, \\ , .{ name, final_syntax, ident, pd1, pd2, pslash }); } else if (pd1 and !pd2 and !pslash and syntax == .flag) { - try stdout.print("flagpd1(\"{}\"),\n", .{name}); + try stdout.print("flagpd1(\"{s}\"),\n", .{name}); } else if (!pd1 and !pd2 and pslash and syntax == .flag) { - try stdout.print("flagpsl(\"{}\"),\n", .{name}); + try stdout.print("flagpsl(\"{s}\"),\n", .{name}); } else if (pd1 and !pd2 and !pslash and syntax == .joined) { - try stdout.print("joinpd1(\"{}\"),\n", .{name}); + try stdout.print("joinpd1(\"{s}\"),\n", .{name}); } else if (pd1 and !pd2 and !pslash and syntax == .joined_or_separate) { - try stdout.print("jspd1(\"{}\"),\n", .{name}); + try stdout.print("jspd1(\"{s}\"),\n", .{name}); } else if (pd1 and !pd2 and !pslash and syntax == .separate) { - try stdout.print("sepd1(\"{}\"),\n", .{name}); + try stdout.print("sepd1(\"{s}\"),\n", .{name}); } else { try stdout.print( \\.{{ - \\ .name = "{}", - \\ .syntax = {}, + \\ .name = "{s}", + \\ .syntax = {s}, \\ .zig_equivalent = .other, - \\ .pd1 = {}, - \\ .pd2 = {}, - \\ .psl = {}, + \\ .pd1 = {s}, + \\ .pd2 = {s}, + \\ .psl = {s}, \\}}, \\ , .{ name, syntax, pd1, pd2, pslash }); @@ -506,8 +514,8 @@ const Syntax = union(enum) { out_stream: anytype, ) !void { switch (self) { - .multi_arg => |n| return out_stream.print(".{{.{}={}}}", .{ @tagName(self), n }), - else => return out_stream.print(".{}", .{@tagName(self)}), + .multi_arg => |n| return out_stream.print(".{{.{s}={}}}", .{ @tagName(self), n }), + else => return out_stream.print(".{s}", .{@tagName(self)}), } } }; @@ -559,9 +567,9 @@ fn objSyntax(obj: *json.ObjectMap) Syntax { return .flag; } const key = obj.get("!name").?.String; - std.debug.warn("{} (key {}) has unrecognized superclasses:\n", .{ name, key }); + std.debug.warn("{s} (key {s}) has unrecognized superclasses:\n", .{ name, key }); for (obj.get("!superclasses").?.Array.items) |superclass_json| { - std.debug.warn(" {}\n", .{superclass_json.String}); + std.debug.warn(" {s}\n", .{superclass_json.String}); } std.process.exit(1); } @@ -612,7 +620,7 @@ fn objectLessThan(context: void, a: *json.ObjectMap, b: *json.ObjectMap) bool { fn usageAndExit(file: fs.File, arg0: []const u8, code: u8) noreturn { file.writer().print( - \\Usage: {} /path/to/llvm-tblgen /path/to/git/llvm/llvm-project + \\Usage: {s} /path/to/llvm-tblgen /path/to/git/llvm/llvm-project \\Alternative Usage: zig run /path/to/git/zig/tools/update_clang_options.zig -- /path/to/llvm-tblgen /path/to/git/llvm/llvm-project \\ \\Prints to stdout Zig code which you can use to replace the file src/clang_options_data.zig. -- 2.54.0