authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2024-11-13 06:04:04+01:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2024-12-11 00:10:15+01:00
log8af82621d75f9f0d96ebf734f5ea862d06a5f1fa
treee004815ccdc1ae57557d69a2e42270edd81ca469
parent0b67463b9285158d818d6cd196c5f2ba9961a05e
signaturebadge-check Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM

compiler: Improve the handling of unwind table levels.

The goal here is to support both levels of unwind tables (sync and async) in zig cc and zig build. Previously, the LLVM backend always used async tables while zig cc was partially influenced by whatever was Clang's default.

16 files changed, 174 insertions(+), 53 deletions(-)

lib/std/Build.zig+5-5
...@@ -706,7 +706,7 @@ pub const ExecutableOptions = struct {...@@ -706,7 +706,7 @@ pub const ExecutableOptions = struct {
706 single_threaded: ?bool = null,706 single_threaded: ?bool = null,
707 pic: ?bool = null,707 pic: ?bool = null,
708 strip: ?bool = null,708 strip: ?bool = null,
709 unwind_tables: ?bool = null,709 unwind_tables: ?std.builtin.UnwindTables = null,
710 omit_frame_pointer: ?bool = null,710 omit_frame_pointer: ?bool = null,
711 sanitize_thread: ?bool = null,711 sanitize_thread: ?bool = null,
712 error_tracing: ?bool = null,712 error_tracing: ?bool = null,
...@@ -762,7 +762,7 @@ pub const ObjectOptions = struct {...@@ -762,7 +762,7 @@ pub const ObjectOptions = struct {
762 single_threaded: ?bool = null,762 single_threaded: ?bool = null,
763 pic: ?bool = null,763 pic: ?bool = null,
764 strip: ?bool = null,764 strip: ?bool = null,
765 unwind_tables: ?bool = null,765 unwind_tables: ?std.builtin.UnwindTables = null,
766 omit_frame_pointer: ?bool = null,766 omit_frame_pointer: ?bool = null,
767 sanitize_thread: ?bool = null,767 sanitize_thread: ?bool = null,
768 error_tracing: ?bool = null,768 error_tracing: ?bool = null,
...@@ -810,7 +810,7 @@ pub const SharedLibraryOptions = struct {...@@ -810,7 +810,7 @@ pub const SharedLibraryOptions = struct {
810 single_threaded: ?bool = null,810 single_threaded: ?bool = null,
811 pic: ?bool = null,811 pic: ?bool = null,
812 strip: ?bool = null,812 strip: ?bool = null,
813 unwind_tables: ?bool = null,813 unwind_tables: ?std.builtin.UnwindTables = null,
814 omit_frame_pointer: ?bool = null,814 omit_frame_pointer: ?bool = null,
815 sanitize_thread: ?bool = null,815 sanitize_thread: ?bool = null,
816 error_tracing: ?bool = null,816 error_tracing: ?bool = null,
...@@ -867,7 +867,7 @@ pub const StaticLibraryOptions = struct {...@@ -867,7 +867,7 @@ pub const StaticLibraryOptions = struct {
867 single_threaded: ?bool = null,867 single_threaded: ?bool = null,
868 pic: ?bool = null,868 pic: ?bool = null,
869 strip: ?bool = null,869 strip: ?bool = null,
870 unwind_tables: ?bool = null,870 unwind_tables: ?std.builtin.UnwindTables = null,
871 omit_frame_pointer: ?bool = null,871 omit_frame_pointer: ?bool = null,
872 sanitize_thread: ?bool = null,872 sanitize_thread: ?bool = null,
873 error_tracing: ?bool = null,873 error_tracing: ?bool = null,
...@@ -919,7 +919,7 @@ pub const TestOptions = struct {...@@ -919,7 +919,7 @@ pub const TestOptions = struct {
919 single_threaded: ?bool = null,919 single_threaded: ?bool = null,
920 pic: ?bool = null,920 pic: ?bool = null,
921 strip: ?bool = null,921 strip: ?bool = null,
922 unwind_tables: ?bool = null,922 unwind_tables: ?std.builtin.UnwindTables = null,
923 omit_frame_pointer: ?bool = null,923 omit_frame_pointer: ?bool = null,
924 sanitize_thread: ?bool = null,924 sanitize_thread: ?bool = null,
925 error_tracing: ?bool = null,925 error_tracing: ?bool = null,
lib/std/Build/Module.zig+10-3
...@@ -22,7 +22,7 @@ frameworks: std.StringArrayHashMapUnmanaged(LinkFrameworkOptions),...@@ -22,7 +22,7 @@ frameworks: std.StringArrayHashMapUnmanaged(LinkFrameworkOptions),
22link_objects: std.ArrayListUnmanaged(LinkObject),22link_objects: std.ArrayListUnmanaged(LinkObject),
2323
24strip: ?bool,24strip: ?bool,
25unwind_tables: ?bool,25unwind_tables: ?std.builtin.UnwindTables,
26single_threaded: ?bool,26single_threaded: ?bool,
27stack_protector: ?bool,27stack_protector: ?bool,
28stack_check: ?bool,28stack_check: ?bool,
...@@ -218,7 +218,7 @@ pub const CreateOptions = struct {...@@ -218,7 +218,7 @@ pub const CreateOptions = struct {
218 link_libcpp: ?bool = null,218 link_libcpp: ?bool = null,
219 single_threaded: ?bool = null,219 single_threaded: ?bool = null,
220 strip: ?bool = null,220 strip: ?bool = null,
221 unwind_tables: ?bool = null,221 unwind_tables: ?std.builtin.UnwindTables = null,
222 dwarf_format: ?std.dwarf.Format = null,222 dwarf_format: ?std.dwarf.Format = null,
223 code_model: std.builtin.CodeModel = .default,223 code_model: std.builtin.CodeModel = .default,
224 stack_protector: ?bool = null,224 stack_protector: ?bool = null,
...@@ -675,7 +675,6 @@ pub fn appendZigProcessFlags(...@@ -675,7 +675,6 @@ pub fn appendZigProcessFlags(
675 const b = m.owner;675 const b = m.owner;
676676
677 try addFlag(zig_args, m.strip, "-fstrip", "-fno-strip");677 try addFlag(zig_args, m.strip, "-fstrip", "-fno-strip");
678 try addFlag(zig_args, m.unwind_tables, "-funwind-tables", "-fno-unwind-tables");
679 try addFlag(zig_args, m.single_threaded, "-fsingle-threaded", "-fno-single-threaded");678 try addFlag(zig_args, m.single_threaded, "-fsingle-threaded", "-fno-single-threaded");
680 try addFlag(zig_args, m.stack_check, "-fstack-check", "-fno-stack-check");679 try addFlag(zig_args, m.stack_check, "-fstack-check", "-fno-stack-check");
681 try addFlag(zig_args, m.stack_protector, "-fstack-protector", "-fno-stack-protector");680 try addFlag(zig_args, m.stack_protector, "-fstack-protector", "-fno-stack-protector");
...@@ -695,6 +694,14 @@ pub fn appendZigProcessFlags(...@@ -695,6 +694,14 @@ pub fn appendZigProcessFlags(
695 });694 });
696 }695 }
697696
697 if (m.unwind_tables) |unwind_tables| {
698 try zig_args.append(switch (unwind_tables) {
699 .none => "-fno-unwind-tables",
700 .sync => "-funwind-tables",
701 .@"async" => "-fasync-unwind-tables",
702 });
703 }
704
698 try zig_args.ensureUnusedCapacity(1);705 try zig_args.ensureUnusedCapacity(1);
699 if (m.optimize) |optimize| switch (optimize) {706 if (m.optimize) |optimize| switch (optimize) {
700 .Debug => zig_args.appendAssumeCapacity("-ODebug"),707 .Debug => zig_args.appendAssumeCapacity("-ODebug"),
lib/std/builtin.zig+8
...@@ -804,6 +804,14 @@ pub const LinkMode = enum {...@@ -804,6 +804,14 @@ pub const LinkMode = enum {
804 dynamic,804 dynamic,
805};805};
806806
807/// This data structure is used by the Zig language code generation and
808/// therefore must be kept in sync with the compiler implementation.
809pub const UnwindTables = enum {
810 none,
811 sync,
812 @"async",
813};
814
807/// This data structure is used by the Zig language code generation and815/// This data structure is used by the Zig language code generation and
808/// therefore must be kept in sync with the compiler implementation.816/// therefore must be kept in sync with the compiler implementation.
809pub const WasiExecModel = enum {817pub const WasiExecModel = enum {
src/Builtin.zig+3
...@@ -2,6 +2,7 @@ target: std.Target,...@@ -2,6 +2,7 @@ target: std.Target,
2zig_backend: std.builtin.CompilerBackend,2zig_backend: std.builtin.CompilerBackend,
3output_mode: std.builtin.OutputMode,3output_mode: std.builtin.OutputMode,
4link_mode: std.builtin.LinkMode,4link_mode: std.builtin.LinkMode,
5unwind_tables: std.builtin.UnwindTables,
5is_test: bool,6is_test: bool,
6single_threaded: bool,7single_threaded: bool,
7link_libc: bool,8link_libc: bool,
...@@ -40,6 +41,7 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void {...@@ -40,6 +41,7 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void {
40 \\41 \\
41 \\pub const output_mode: std.builtin.OutputMode = .{p_};42 \\pub const output_mode: std.builtin.OutputMode = .{p_};
42 \\pub const link_mode: std.builtin.LinkMode = .{p_};43 \\pub const link_mode: std.builtin.LinkMode = .{p_};
44 \\pub const unwind_tables: std.builtin.UnwindTables = .{p_};
43 \\pub const is_test = {};45 \\pub const is_test = {};
44 \\pub const single_threaded = {};46 \\pub const single_threaded = {};
45 \\pub const abi: std.Target.Abi = .{p_};47 \\pub const abi: std.Target.Abi = .{p_};
...@@ -53,6 +55,7 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void {...@@ -53,6 +55,7 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void {
53 std.zig.fmtId(@tagName(zig_backend)),55 std.zig.fmtId(@tagName(zig_backend)),
54 std.zig.fmtId(@tagName(opts.output_mode)),56 std.zig.fmtId(@tagName(opts.output_mode)),
55 std.zig.fmtId(@tagName(opts.link_mode)),57 std.zig.fmtId(@tagName(opts.link_mode)),
58 std.zig.fmtId(@tagName(opts.unwind_tables)),
56 opts.is_test,59 opts.is_test,
57 opts.single_threaded,60 opts.single_threaded,
58 std.zig.fmtId(@tagName(target.abi)),61 std.zig.fmtId(@tagName(target.abi)),
src/Compilation.zig+20-7
...@@ -1261,12 +1261,15 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1261,12 +1261,15 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1261 // The "any" values provided by resolved config only account for1261 // The "any" values provided by resolved config only account for
1262 // explicitly-provided settings. We now make them additionally account1262 // explicitly-provided settings. We now make them additionally account
1263 // for default setting resolution.1263 // for default setting resolution.
1264 const any_unwind_tables = options.config.any_unwind_tables or options.root_mod.unwind_tables;1264 const any_unwind_tables = switch (options.config.any_unwind_tables) {
1265 .none => options.root_mod.unwind_tables,
1266 .sync, .@"async" => |uwt| uwt,
1267 };
1265 const any_non_single_threaded = options.config.any_non_single_threaded or !options.root_mod.single_threaded;1268 const any_non_single_threaded = options.config.any_non_single_threaded or !options.root_mod.single_threaded;
1266 const any_sanitize_thread = options.config.any_sanitize_thread or options.root_mod.sanitize_thread;1269 const any_sanitize_thread = options.config.any_sanitize_thread or options.root_mod.sanitize_thread;
1267 const any_fuzz = options.config.any_fuzz or options.root_mod.fuzz;1270 const any_fuzz = options.config.any_fuzz or options.root_mod.fuzz;
12681271
1269 const link_eh_frame_hdr = options.link_eh_frame_hdr or any_unwind_tables;1272 const link_eh_frame_hdr = options.link_eh_frame_hdr or any_unwind_tables != .none;
1270 const build_id = options.build_id orelse .none;1273 const build_id = options.build_id orelse .none;
12711274
1272 const link_libc = options.config.link_libc;1275 const link_libc = options.config.link_libc;
...@@ -1354,6 +1357,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1354,6 +1357,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1354 cache.hash.add(options.config.pie);1357 cache.hash.add(options.config.pie);
1355 cache.hash.add(options.config.lto);1358 cache.hash.add(options.config.lto);
1356 cache.hash.add(options.config.link_mode);1359 cache.hash.add(options.config.link_mode);
1360 cache.hash.add(options.config.any_unwind_tables);
1357 cache.hash.add(options.function_sections);1361 cache.hash.add(options.function_sections);
1358 cache.hash.add(options.data_sections);1362 cache.hash.add(options.data_sections);
1359 cache.hash.add(link_libc);1363 cache.hash.add(link_libc);
...@@ -5538,10 +5542,17 @@ pub fn addCCArgs(...@@ -5538,10 +5542,17 @@ pub fn addCCArgs(
5538 try argv.append("-Werror=date-time");5542 try argv.append("-Werror=date-time");
5539 }5543 }
55405544
5541 if (mod.unwind_tables) {5545 switch (mod.unwind_tables) {
5542 try argv.append("-funwind-tables");5546 .none => {
5543 } else {5547 try argv.append("-fno-unwind-tables");
5544 try argv.append("-fno-unwind-tables");5548 try argv.append("-fno-asynchronous-unwind-tables");
5549 },
5550 .sync => {
5551 // Need to override Clang's convoluted default logic.
5552 try argv.append("-fno-asynchronous-unwind-tables");
5553 try argv.append("-funwind-tables");
5554 },
5555 .@"async" => try argv.append("-fasynchronous-unwind-tables"),
5545 }5556 }
5546 },5557 },
5547 .shared_library, .ll, .bc, .unknown, .static_library, .object, .def, .zig, .res, .manifest => {},5558 .shared_library, .ll, .bc, .unknown, .static_library, .object, .def, .zig, .res, .manifest => {},
...@@ -6273,6 +6284,7 @@ pub const CrtFileOptions = struct {...@@ -6273,6 +6284,7 @@ pub const CrtFileOptions = struct {
6273 function_sections: ?bool = null,6284 function_sections: ?bool = null,
6274 data_sections: ?bool = null,6285 data_sections: ?bool = null,
6275 omit_frame_pointer: ?bool = null,6286 omit_frame_pointer: ?bool = null,
6287 unwind_tables: ?std.builtin.UnwindTables = null,
6276 pic: ?bool = null,6288 pic: ?bool = null,
6277 no_builtin: ?bool = null,6289 no_builtin: ?bool = null,
6278};6290};
...@@ -6334,7 +6346,8 @@ pub fn build_crt_file(...@@ -6334,7 +6346,8 @@ pub fn build_crt_file(
6334 // Some libcs (e.g. musl) are opinionated about -fomit-frame-pointer.6346 // Some libcs (e.g. musl) are opinionated about -fomit-frame-pointer.
6335 .omit_frame_pointer = options.omit_frame_pointer orelse comp.root_mod.omit_frame_pointer,6347 .omit_frame_pointer = options.omit_frame_pointer orelse comp.root_mod.omit_frame_pointer,
6336 .valgrind = false,6348 .valgrind = false,
6337 .unwind_tables = false,6349 // Some libcs (e.g. MinGW) are opinionated about -funwind-tables.
6350 .unwind_tables = options.unwind_tables orelse .none,
6338 // Some CRT objects (e.g. musl's rcrt1.o and Scrt1.o) are opinionated about PIC.6351 // Some CRT objects (e.g. musl's rcrt1.o and Scrt1.o) are opinionated about PIC.
6339 .pic = options.pic orelse comp.root_mod.pic,6352 .pic = options.pic orelse comp.root_mod.pic,
6340 .optimize_mode = comp.compilerRtOptMode(),6353 .optimize_mode = comp.compilerRtOptMode(),
src/Compilation/Config.zig+14-10
...@@ -12,13 +12,14 @@ link_libunwind: bool,...@@ -12,13 +12,14 @@ link_libunwind: bool,
12/// True if and only if the c_source_files field will have nonzero length when12/// True if and only if the c_source_files field will have nonzero length when
13/// calling Compilation.create.13/// calling Compilation.create.
14any_c_source_files: bool,14any_c_source_files: bool,
15/// This is true if any Module has unwind_tables set explicitly to true. Until15/// This is not `.none` if any `Module` has `unwind_tables` set explicitly to a
16/// Compilation.create is called, it is possible for this to be false while in16/// value other than `.none`. Until `Compilation.create()` is called, it is
17/// fact all Module instances have unwind_tables=true due to the default17/// possible for this to be `.none` while in fact all `Module` instances have
18/// being unwind_tables=true. After Compilation.create is called this will18/// `unwind_tables != .none` due to the default. After `Compilation.create()` is
19/// also take into account the default setting, making this value true if and19/// called, this will also take into account the default setting, making this
20/// only if any Module has unwind_tables set to true.20/// value `.sync` or `.@"async"` if and only if any `Module` has
21any_unwind_tables: bool,21/// `unwind_tables != .none`.
22any_unwind_tables: std.builtin.UnwindTables,
22/// This is true if any Module has single_threaded set explicitly to false. Until23/// This is true if any Module has single_threaded set explicitly to false. Until
23/// Compilation.create is called, it is possible for this to be false while in24/// Compilation.create is called, it is possible for this to be false while in
24/// fact all Module instances have single_threaded=false due to the default25/// fact all Module instances have single_threaded=false due to the default
...@@ -85,7 +86,7 @@ pub const Options = struct {...@@ -85,7 +86,7 @@ pub const Options = struct {
85 any_non_single_threaded: bool = false,86 any_non_single_threaded: bool = false,
86 any_sanitize_thread: bool = false,87 any_sanitize_thread: bool = false,
87 any_fuzz: bool = false,88 any_fuzz: bool = false,
88 any_unwind_tables: bool = false,89 any_unwind_tables: std.builtin.UnwindTables = .none,
89 any_dyn_libs: bool = false,90 any_dyn_libs: bool = false,
90 any_c_source_files: bool = false,91 any_c_source_files: bool = false,
91 any_non_stripped: bool = false,92 any_non_stripped: bool = false,
...@@ -356,8 +357,11 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -356,8 +357,11 @@ pub fn resolve(options: Options) ResolveError!Config {
356 break :b false;357 break :b false;
357 };358 };
358359
359 const any_unwind_tables = options.any_unwind_tables or360 const any_unwind_tables = b: {
360 link_libunwind or target_util.needUnwindTables(target);361 if (options.any_unwind_tables != .none) break :b options.any_unwind_tables;
362
363 break :b target_util.needUnwindTables(target, link_libunwind, options.any_sanitize_thread);
364 };
361365
362 const link_mode = b: {366 const link_mode = b: {
363 const explicitly_exe_or_dyn_lib = switch (options.output_mode) {367 const explicitly_exe_or_dyn_lib = switch (options.output_mode) {
src/Package/Module.zig+4-3
...@@ -27,7 +27,7 @@ red_zone: bool,...@@ -27,7 +27,7 @@ red_zone: bool,
27sanitize_c: bool,27sanitize_c: bool,
28sanitize_thread: bool,28sanitize_thread: bool,
29fuzz: bool,29fuzz: bool,
30unwind_tables: bool,30unwind_tables: std.builtin.UnwindTables,
31cc_argv: []const []const u8,31cc_argv: []const []const u8,
32/// (SPIR-V) whether to generate a structured control flow graph or not32/// (SPIR-V) whether to generate a structured control flow graph or not
33structured_cfg: bool,33structured_cfg: bool,
...@@ -91,7 +91,7 @@ pub const CreateOptions = struct {...@@ -91,7 +91,7 @@ pub const CreateOptions = struct {
91 /// other number means stack protection with that buffer size.91 /// other number means stack protection with that buffer size.
92 stack_protector: ?u32 = null,92 stack_protector: ?u32 = null,
93 red_zone: ?bool = null,93 red_zone: ?bool = null,
94 unwind_tables: ?bool = null,94 unwind_tables: ?std.builtin.UnwindTables = null,
95 sanitize_c: ?bool = null,95 sanitize_c: ?bool = null,
96 sanitize_thread: ?bool = null,96 sanitize_thread: ?bool = null,
97 fuzz: ?bool = null,97 fuzz: ?bool = null,
...@@ -112,7 +112,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {...@@ -112,7 +112,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {
112 if (options.inherited.sanitize_thread == true) assert(options.global.any_sanitize_thread);112 if (options.inherited.sanitize_thread == true) assert(options.global.any_sanitize_thread);
113 if (options.inherited.fuzz == true) assert(options.global.any_fuzz);113 if (options.inherited.fuzz == true) assert(options.global.any_fuzz);
114 if (options.inherited.single_threaded == false) assert(options.global.any_non_single_threaded);114 if (options.inherited.single_threaded == false) assert(options.global.any_non_single_threaded);
115 if (options.inherited.unwind_tables == true) assert(options.global.any_unwind_tables);115 if (options.inherited.unwind_tables) |uwt| if (uwt != .none) assert(options.global.any_unwind_tables != .none);
116 if (options.inherited.error_tracing == true) assert(options.global.any_error_tracing);116 if (options.inherited.error_tracing == true) assert(options.global.any_error_tracing);
117117
118 const resolved_target = options.inherited.resolved_target orelse options.parent.?.resolved_target;118 const resolved_target = options.inherited.resolved_target orelse options.parent.?.resolved_target;
...@@ -382,6 +382,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {...@@ -382,6 +382,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {
382 .zig_backend = zig_backend,382 .zig_backend = zig_backend,
383 .output_mode = options.global.output_mode,383 .output_mode = options.global.output_mode,
384 .link_mode = options.global.link_mode,384 .link_mode = options.global.link_mode,
385 .unwind_tables = options.global.any_unwind_tables,
385 .is_test = options.global.is_test,386 .is_test = options.global.is_test,
386 .single_threaded = single_threaded,387 .single_threaded = single_threaded,
387 .link_libc = options.global.link_libc,388 .link_libc = options.global.link_libc,
src/clang_options_data.zig+16-2
...@@ -2757,7 +2757,14 @@ flagpd1("fast"),...@@ -2757,7 +2757,14 @@ flagpd1("fast"),
2757flagpd1("fastcp"),2757flagpd1("fastcp"),
2758flagpd1("fastf"),2758flagpd1("fastf"),
2759flagpd1("fasync-exceptions"),2759flagpd1("fasync-exceptions"),
2760flagpd1("fasynchronous-unwind-tables"),2760.{
2761 .name = "fasynchronous-unwind-tables",
2762 .syntax = .flag,
2763 .zig_equivalent = .asynchronous_unwind_tables,
2764 .pd1 = true,
2765 .pd2 = false,
2766 .psl = false,
2767},
2761flagpd1("fauto-import"),2768flagpd1("fauto-import"),
2762flagpd1("fauto-profile"),2769flagpd1("fauto-profile"),
2763flagpd1("fauto-profile-accurate"),2770flagpd1("fauto-profile-accurate"),
...@@ -3247,7 +3254,14 @@ flagpd1("fno-assume-sane-operator-new"),...@@ -3247,7 +3254,14 @@ flagpd1("fno-assume-sane-operator-new"),
3247flagpd1("fno-assume-unique-vtables"),3254flagpd1("fno-assume-unique-vtables"),
3248flagpd1("fno-assumptions"),3255flagpd1("fno-assumptions"),
3249flagpd1("fno-async-exceptions"),3256flagpd1("fno-async-exceptions"),
3250flagpd1("fno-asynchronous-unwind-tables"),3257.{
3258 .name = "fno-asynchronous-unwind-tables",
3259 .syntax = .flag,
3260 .zig_equivalent = .no_asynchronous_unwind_tables,
3261 .pd1 = true,
3262 .pd2 = false,
3263 .psl = false,
3264},
3251flagpd1("fno-auto-import"),3265flagpd1("fno-auto-import"),
3252flagpd1("fno-auto-profile"),3266flagpd1("fno-auto-profile"),
3253flagpd1("fno-auto-profile-accurate"),3267flagpd1("fno-auto-profile-accurate"),
src/codegen/llvm.zig+5-2
...@@ -3141,8 +3141,11 @@ pub const Object = struct {...@@ -3141,8 +3141,11 @@ pub const Object = struct {
3141 } }, &o.builder);3141 } }, &o.builder);
3142 }3142 }
3143 try attributes.addFnAttr(.nounwind, &o.builder);3143 try attributes.addFnAttr(.nounwind, &o.builder);
3144 if (owner_mod.unwind_tables) {3144 if (owner_mod.unwind_tables != .none) {
3145 try attributes.addFnAttr(.{ .uwtable = Builder.Attribute.UwTable.default }, &o.builder);3145 try attributes.addFnAttr(
3146 .{ .uwtable = if (owner_mod.unwind_tables == .@"async") .@"async" else .sync },
3147 &o.builder,
3148 );
3146 }3149 }
3147 if (owner_mod.no_builtin) {3150 if (owner_mod.no_builtin) {
3148 // The intent here is for compiler-rt and libc functions to not generate3151 // The intent here is for compiler-rt and libc functions to not generate
src/libcxx.zig+6-3
...@@ -397,7 +397,6 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildErr...@@ -397,7 +397,6 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
397397
398 const optimize_mode = comp.compilerRtOptMode();398 const optimize_mode = comp.compilerRtOptMode();
399 const strip = comp.compilerRtStrip();399 const strip = comp.compilerRtStrip();
400 const unwind_tables = true;
401400
402 const config = Compilation.Config.resolve(.{401 const config = Compilation.Config.resolve(.{
403 .output_mode = output_mode,402 .output_mode = output_mode,
...@@ -409,7 +408,6 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildErr...@@ -409,7 +408,6 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
409 .root_optimize_mode = optimize_mode,408 .root_optimize_mode = optimize_mode,
410 .root_strip = strip,409 .root_strip = strip,
411 .link_libc = true,410 .link_libc = true,
412 .any_unwind_tables = unwind_tables,
413 .lto = comp.config.lto,411 .lto = comp.config.lto,
414 .any_sanitize_thread = comp.config.any_sanitize_thread,412 .any_sanitize_thread = comp.config.any_sanitize_thread,
415 }) catch |err| {413 }) catch |err| {
...@@ -440,7 +438,12 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildErr...@@ -440,7 +438,12 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
440 .valgrind = false,438 .valgrind = false,
441 .optimize_mode = optimize_mode,439 .optimize_mode = optimize_mode,
442 .structured_cfg = comp.root_mod.structured_cfg,440 .structured_cfg = comp.root_mod.structured_cfg,
443 .unwind_tables = unwind_tables,441 // See the `-fno-exceptions` logic for WASI.
442 // The old 32-bit x86 variant of SEH doesn't use tables.
443 .unwind_tables = if (target.os.tag == .wasi or (target.cpu.arch == .x86 and target.os.tag == .windows))
444 .none
445 else
446 .@"async",
444 .pic = comp.root_mod.pic,447 .pic = comp.root_mod.pic,
445 },448 },
446 .global = config,449 .global = config,
src/libunwind.zig+2-1
...@@ -65,7 +65,8 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr...@@ -65,7 +65,8 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
65 .sanitize_c = false,65 .sanitize_c = false,
66 .sanitize_thread = false,66 .sanitize_thread = false,
67 // necessary so that libunwind can unwind through its own stack frames67 // necessary so that libunwind can unwind through its own stack frames
68 .unwind_tables = true,68 // The old 32-bit x86 variant of SEH doesn't use tables.
69 .unwind_tables = if (target.cpu.arch == .x86 and target.os.tag == .windows) .none else .@"async",
69 .pic = if (target_util.supports_fpic(target)) true else null,70 .pic = if (target_util.supports_fpic(target)) true else null,
70 .optimize_mode = comp.compilerRtOptMode(),71 .optimize_mode = comp.compilerRtOptMode(),
71 },72 },
src/main.zig+46-8
...@@ -510,6 +510,7 @@ const usage_build_generic =...@@ -510,6 +510,7 @@ const usage_build_generic =
510 \\ -ffuzz Enable fuzz testing instrumentation510 \\ -ffuzz Enable fuzz testing instrumentation
511 \\ -fno-fuzz Disable fuzz testing instrumentation511 \\ -fno-fuzz Disable fuzz testing instrumentation
512 \\ -funwind-tables Always produce unwind table entries for all functions512 \\ -funwind-tables Always produce unwind table entries for all functions
513 \\ -fasync-unwind-tables Always produce asynchronous unwind table entries for all functions
513 \\ -fno-unwind-tables Never produce unwind table entries514 \\ -fno-unwind-tables Never produce unwind table entries
514 \\ -ferror-tracing Enable error tracing in ReleaseFast mode515 \\ -ferror-tracing Enable error tracing in ReleaseFast mode
515 \\ -fno-error-tracing Disable error tracing in Debug and ReleaseSafe mode516 \\ -fno-error-tracing Disable error tracing in Debug and ReleaseSafe mode
...@@ -1385,9 +1386,11 @@ fn buildOutputType(...@@ -1385,9 +1386,11 @@ fn buildOutputType(
1385 } else if (mem.eql(u8, arg, "-fno-lto")) {1386 } else if (mem.eql(u8, arg, "-fno-lto")) {
1386 create_module.opts.lto = false;1387 create_module.opts.lto = false;
1387 } else if (mem.eql(u8, arg, "-funwind-tables")) {1388 } else if (mem.eql(u8, arg, "-funwind-tables")) {
1388 mod_opts.unwind_tables = true;1389 mod_opts.unwind_tables = .sync;
1390 } else if (mem.eql(u8, arg, "-fasync-unwind-tables")) {
1391 mod_opts.unwind_tables = .@"async";
1389 } else if (mem.eql(u8, arg, "-fno-unwind-tables")) {1392 } else if (mem.eql(u8, arg, "-fno-unwind-tables")) {
1390 mod_opts.unwind_tables = false;1393 mod_opts.unwind_tables = .none;
1391 } else if (mem.eql(u8, arg, "-fstack-check")) {1394 } else if (mem.eql(u8, arg, "-fstack-check")) {
1392 mod_opts.stack_check = true;1395 mod_opts.stack_check = true;
1393 } else if (mem.eql(u8, arg, "-fno-stack-check")) {1396 } else if (mem.eql(u8, arg, "-fno-stack-check")) {
...@@ -1973,8 +1976,27 @@ fn buildOutputType(...@@ -1973,8 +1976,27 @@ fn buildOutputType(
1973 }1976 }
1974 },1977 },
1975 .no_stack_protector => mod_opts.stack_protector = 0,1978 .no_stack_protector => mod_opts.stack_protector = 0,
1976 .unwind_tables => mod_opts.unwind_tables = true,1979 // The way these unwind table options are processed in GCC and Clang is crazy
1977 .no_unwind_tables => mod_opts.unwind_tables = false,1980 // convoluted, and we also don't know the target triple here, so this is all
1981 // best-effort.
1982 .unwind_tables => if (mod_opts.unwind_tables) |uwt| switch (uwt) {
1983 .none => {
1984 mod_opts.unwind_tables = .sync;
1985 },
1986 .sync, .@"async" => {},
1987 } else {
1988 mod_opts.unwind_tables = .sync;
1989 },
1990 .no_unwind_tables => mod_opts.unwind_tables = .none,
1991 .asynchronous_unwind_tables => mod_opts.unwind_tables = .@"async",
1992 .no_asynchronous_unwind_tables => if (mod_opts.unwind_tables) |uwt| switch (uwt) {
1993 .none, .sync => {},
1994 .@"async" => {
1995 mod_opts.unwind_tables = .sync;
1996 },
1997 } else {
1998 mod_opts.unwind_tables = .sync;
1999 },
1978 .nostdlib => {2000 .nostdlib => {
1979 create_module.opts.ensure_libc_on_non_freestanding = false;2001 create_module.opts.ensure_libc_on_non_freestanding = false;
1980 create_module.opts.ensure_libcpp_on_non_freestanding = false;2002 create_module.opts.ensure_libcpp_on_non_freestanding = false;
...@@ -2788,8 +2810,15 @@ fn buildOutputType(...@@ -2788,8 +2810,15 @@ fn buildOutputType(
2788 create_module.opts.any_sanitize_thread = true;2810 create_module.opts.any_sanitize_thread = true;
2789 if (mod_opts.fuzz == true)2811 if (mod_opts.fuzz == true)
2790 create_module.opts.any_fuzz = true;2812 create_module.opts.any_fuzz = true;
2791 if (mod_opts.unwind_tables == true)2813 if (mod_opts.unwind_tables) |uwt| switch (uwt) {
2792 create_module.opts.any_unwind_tables = true;2814 .none => {},
2815 .sync => if (create_module.opts.any_unwind_tables == .none) {
2816 create_module.opts.any_unwind_tables = .sync;
2817 },
2818 .@"async" => {
2819 create_module.opts.any_unwind_tables = .@"async";
2820 },
2821 };
2793 if (mod_opts.strip == false)2822 if (mod_opts.strip == false)
2794 create_module.opts.any_non_stripped = true;2823 create_module.opts.any_non_stripped = true;
2795 if (mod_opts.error_tracing == true)2824 if (mod_opts.error_tracing == true)
...@@ -5713,6 +5742,8 @@ pub const ClangArgIterator = struct {...@@ -5713,6 +5742,8 @@ pub const ClangArgIterator = struct {
5713 no_lto,5742 no_lto,
5714 unwind_tables,5743 unwind_tables,
5715 no_unwind_tables,5744 no_unwind_tables,
5745 asynchronous_unwind_tables,
5746 no_asynchronous_unwind_tables,
5716 nostdlib,5747 nostdlib,
5717 nostdlib_cpp,5748 nostdlib_cpp,
5718 shared,5749 shared,
...@@ -7435,8 +7466,15 @@ fn handleModArg(...@@ -7435,8 +7466,15 @@ fn handleModArg(
7435 create_module.opts.any_sanitize_thread = true;7466 create_module.opts.any_sanitize_thread = true;
7436 if (mod_opts.fuzz == true)7467 if (mod_opts.fuzz == true)
7437 create_module.opts.any_fuzz = true;7468 create_module.opts.any_fuzz = true;
7438 if (mod_opts.unwind_tables == true)7469 if (mod_opts.unwind_tables) |uwt| switch (uwt) {
7439 create_module.opts.any_unwind_tables = true;7470 .none => {},
7471 .sync => if (create_module.opts.any_unwind_tables == .none) {
7472 create_module.opts.any_unwind_tables = .sync;
7473 },
7474 .@"async" => {
7475 create_module.opts.any_unwind_tables = .@"async";
7476 },
7477 };
7440 if (mod_opts.strip == false)7478 if (mod_opts.strip == false)
7441 create_module.opts.any_non_stripped = true;7479 create_module.opts.any_non_stripped = true;
7442 if (mod_opts.error_tracing == true)7480 if (mod_opts.error_tracing == true)
src/mingw.zig+13-4
...@@ -24,6 +24,10 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre...@@ -24,6 +24,10 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
24 var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);24 var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);
25 defer arena_allocator.deinit();25 defer arena_allocator.deinit();
26 const arena = arena_allocator.allocator();26 const arena = arena_allocator.allocator();
27 const target = comp.getTarget();
28
29 // The old 32-bit x86 variant of SEH doesn't use tables.
30 const unwind_tables: std.builtin.UnwindTables = if (target.cpu.arch != .x86) .@"async" else .none;
2731
28 switch (crt_file) {32 switch (crt_file) {
29 .crt2_o => {33 .crt2_o => {
...@@ -41,7 +45,9 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre...@@ -41,7 +45,9 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
41 .owner = undefined,45 .owner = undefined,
42 },46 },
43 };47 };
44 return comp.build_crt_file("crt2", .Obj, .@"mingw-w64 crt2.o", prog_node, &files, .{});48 return comp.build_crt_file("crt2", .Obj, .@"mingw-w64 crt2.o", prog_node, &files, .{
49 .unwind_tables = unwind_tables,
50 });
45 },51 },
4652
47 .dllcrt2_o => {53 .dllcrt2_o => {
...@@ -56,7 +62,9 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre...@@ -56,7 +62,9 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
56 .owner = undefined,62 .owner = undefined,
57 },63 },
58 };64 };
59 return comp.build_crt_file("dllcrt2", .Obj, .@"mingw-w64 dllcrt2.o", prog_node, &files, .{});65 return comp.build_crt_file("dllcrt2", .Obj, .@"mingw-w64 dllcrt2.o", prog_node, &files, .{
66 .unwind_tables = unwind_tables,
67 });
60 },68 },
6169
62 .mingw32_lib => {70 .mingw32_lib => {
...@@ -73,7 +81,6 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre...@@ -73,7 +81,6 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
73 .owner = undefined,81 .owner = undefined,
74 });82 });
75 }83 }
76 const target = comp.getTarget();
77 if (target.cpu.arch == .x86 or target.cpu.arch == .x86_64) {84 if (target.cpu.arch == .x86 or target.cpu.arch == .x86_64) {
78 for (mingw32_x86_src) |dep| {85 for (mingw32_x86_src) |dep| {
79 try c_source_files.append(.{86 try c_source_files.append(.{
...@@ -118,7 +125,9 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre...@@ -118,7 +125,9 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
118 } else {125 } else {
119 @panic("unsupported arch");126 @panic("unsupported arch");
120 }127 }
121 return comp.build_crt_file("mingw32", .Lib, .@"mingw-w64 mingw32.lib", prog_node, c_source_files.items, .{});128 return comp.build_crt_file("mingw32", .Lib, .@"mingw-w64 mingw32.lib", prog_node, c_source_files.items, .{
129 .unwind_tables = unwind_tables,
130 });
122 },131 },
123 }132 }
124}133}
src/target.zig+11-2
...@@ -4,6 +4,7 @@ const assert = std.debug.assert;...@@ -4,6 +4,7 @@ const assert = std.debug.assert;
4const Type = @import("Type.zig");4const Type = @import("Type.zig");
5const AddressSpace = std.builtin.AddressSpace;5const AddressSpace = std.builtin.AddressSpace;
6const Alignment = @import("InternPool.zig").Alignment;6const Alignment = @import("InternPool.zig").Alignment;
7const Compilation = @import("Compilation.zig");
7const Feature = @import("Zcu.zig").Feature;8const Feature = @import("Zcu.zig").Feature;
89
9pub const default_stack_protector_buffer_size = 4;10pub const default_stack_protector_buffer_size = 4;
...@@ -408,8 +409,16 @@ pub fn clangSupportsNoImplicitFloatArg(target: std.Target) bool {...@@ -408,8 +409,16 @@ pub fn clangSupportsNoImplicitFloatArg(target: std.Target) bool {
408 };409 };
409}410}
410411
411pub fn needUnwindTables(target: std.Target) bool {412pub fn needUnwindTables(target: std.Target, libunwind: bool, libtsan: bool) std.builtin.UnwindTables {
412 return target.os.tag == .windows or target.isDarwin() or std.debug.Dwarf.abi.supportsUnwinding(target);413 if (target.os.tag == .windows) {
414 // The old 32-bit x86 variant of SEH doesn't use tables.
415 return if (target.cpu.arch != .x86) .@"async" else .none;
416 }
417 if (target.os.tag.isDarwin()) return .@"async";
418 if (libunwind) return .@"async";
419 if (libtsan) return .@"async";
420 if (std.debug.Dwarf.abi.supportsUnwinding(target)) return .@"async";
421 return .none;
413}422}
414423
415pub fn defaultAddressSpace(424pub fn defaultAddressSpace(
test/standalone/stack_iterator/build.zig+3-3
...@@ -23,7 +23,7 @@ pub fn build(b: *std.Build) void {...@@ -23,7 +23,7 @@ pub fn build(b: *std.Build) void {
23 .root_source_file = b.path("unwind.zig"),23 .root_source_file = b.path("unwind.zig"),
24 .target = target,24 .target = target,
25 .optimize = optimize,25 .optimize = optimize,
26 .unwind_tables = if (target.result.isDarwin()) true else null,26 .unwind_tables = if (target.result.isDarwin()) .@"async" else null,
27 .omit_frame_pointer = false,27 .omit_frame_pointer = false,
28 });28 });
2929
...@@ -46,7 +46,7 @@ pub fn build(b: *std.Build) void {...@@ -46,7 +46,7 @@ pub fn build(b: *std.Build) void {
46 .root_source_file = b.path("unwind.zig"),46 .root_source_file = b.path("unwind.zig"),
47 .target = target,47 .target = target,
48 .optimize = optimize,48 .optimize = optimize,
49 .unwind_tables = true,49 .unwind_tables = .@"async",
50 .omit_frame_pointer = true,50 .omit_frame_pointer = true,
51 });51 });
5252
...@@ -85,7 +85,7 @@ pub fn build(b: *std.Build) void {...@@ -85,7 +85,7 @@ pub fn build(b: *std.Build) void {
85 .root_source_file = b.path("shared_lib_unwind.zig"),85 .root_source_file = b.path("shared_lib_unwind.zig"),
86 .target = target,86 .target = target,
87 .optimize = optimize,87 .optimize = optimize,
88 .unwind_tables = if (target.result.isDarwin()) true else null,88 .unwind_tables = if (target.result.isDarwin()) .@"async" else null,
89 .omit_frame_pointer = true,89 .omit_frame_pointer = true,
90 });90 });
9191
tools/update_clang_options.zig+8
...@@ -110,6 +110,14 @@ const known_options = [_]KnownOpt{...@@ -110,6 +110,14 @@ const known_options = [_]KnownOpt{
110 .name = "fno-unwind-tables",110 .name = "fno-unwind-tables",
111 .ident = "no_unwind_tables",111 .ident = "no_unwind_tables",
112 },112 },
113 .{
114 .name = "fasynchronous-unwind-tables",
115 .ident = "asynchronous_unwind_tables",
116 },
117 .{
118 .name = "fno-asynchronous-unwind-tables",
119 .ident = "no_asynchronous_unwind_tables",
120 },
113 .{121 .{
114 .name = "nolibc",122 .name = "nolibc",
115 .ident = "nostdlib",123 .ident = "nostdlib",