From b15d6b2a34294bd48bc090f858c1b9527763163a Mon Sep 17 00:00:00 2001 From: Lee Cannon Date: Thu, 30 Sep 2021 19:49:13 +0100 Subject: [PATCH 1/4] Add build.zig and command line flags --- lib/std/build.zig | 9 +++++++++ src/Compilation.zig | 13 +++++++++++++ src/clang_options_data.zig | 18 ++++++++++++++++-- src/glibc.zig | 1 + src/libcxx.zig | 2 ++ src/libunwind.zig | 1 + src/link.zig | 1 + src/main.zig | 12 ++++++++++++ src/musl.zig | 1 + src/stage1.zig | 1 + src/stage1/all_types.hpp | 1 + src/stage1/stage1.cpp | 1 + src/stage1/stage1.h | 1 + tools/update_clang_options.zig | 8 ++++++++ 14 files changed, 68 insertions(+), 2 deletions(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index 228c50cd20..a2b9aa3030 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -1515,6 +1515,8 @@ pub const LibExeObjStep = struct { red_zone: ?bool = null, + omit_frame_pointer: ?bool = null, + subsystem: ?std.Target.SubSystem = null, /// Overrides the default stack size @@ -2406,6 +2408,13 @@ pub const LibExeObjStep = struct { try zig_args.append("-mno-red-zone"); } } + if (self.omit_frame_pointer) |omit_frame_pointer| { + if (omit_frame_pointer) { + try zig_args.append("-fomit-frame-pointer"); + } else { + try zig_args.append("-fno-omit-frame-pointer"); + } + } if (self.disable_sanitize_c) { try zig_args.append("-fno-sanitize-c"); } diff --git a/src/Compilation.zig b/src/Compilation.zig index f997b53388..3432c38ab5 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -680,6 +680,7 @@ pub const InitOptions = struct { want_sanitize_c: ?bool = null, want_stack_check: ?bool = null, want_red_zone: ?bool = null, + omit_frame_pointer: ?bool = null, want_valgrind: ?bool = null, want_tsan: ?bool = null, want_compiler_rt: ?bool = null, @@ -1113,6 +1114,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { const strip = options.strip or !target_util.hasDebugInfo(options.target); const red_zone = options.want_red_zone orelse target_util.hasRedZone(options.target); + const omit_frame_pointer = options.omit_frame_pointer orelse (options.optimize_mode != .Debug); // 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, @@ -1146,6 +1148,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { cache.hash.add(tsan); cache.hash.add(stack_check); cache.hash.add(red_zone); + cache.hash.add(omit_frame_pointer); cache.hash.add(link_mode); cache.hash.add(options.function_sections); cache.hash.add(strip); @@ -1416,6 +1419,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { .tsan = tsan, .stack_check = stack_check, .red_zone = red_zone, + .omit_frame_pointer = omit_frame_pointer, .single_threaded = single_threaded, .verbose_link = options.verbose_link, .machine_code_model = options.machine_code_model, @@ -3189,6 +3193,12 @@ pub fn addCCArgs( try argv.append("-mno-red-zone"); } + if (comp.bin_file.options.omit_frame_pointer) { + try argv.append("-fomit-frame-pointer"); + } else { + try argv.append("-fno-omit-frame-pointer"); + } + switch (comp.bin_file.options.optimize_mode) { .Debug => { // windows c runtime requires -D_DEBUG if using debug libraries @@ -4019,6 +4029,7 @@ fn buildOutputFromZig( .want_sanitize_c = false, .want_stack_check = false, .want_red_zone = comp.bin_file.options.red_zone, + .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, .want_valgrind = false, .want_tsan = false, .want_pic = comp.bin_file.options.pic, @@ -4302,6 +4313,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node .include_compiler_rt = include_compiler_rt, .enable_stack_probing = comp.bin_file.options.stack_check, .red_zone = comp.bin_file.options.red_zone, + .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, .enable_time_report = comp.time_report, .enable_stack_report = comp.stack_report, .test_is_evented = comp.test_evented_io, @@ -4451,6 +4463,7 @@ pub fn build_crt_file( .want_sanitize_c = false, .want_stack_check = false, .want_red_zone = comp.bin_file.options.red_zone, + .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, .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 ecaa383b69..e027d2471c 100644 --- a/src/clang_options_data.zig +++ b/src/clang_options_data.zig @@ -3014,7 +3014,14 @@ flagpd1("fno-objc-infer-related-result-type"), flagpd1("fno-objc-legacy-dispatch"), flagpd1("fno-objc-nonfragile-abi"), flagpd1("fno-objc-weak"), -flagpd1("fno-omit-frame-pointer"), +.{ + .name = "fno-omit-frame-pointer", + .syntax = .flag, + .zig_equivalent = .no_omit_frame_pointer, + .pd1 = true, + .pd2 = false, + .psl = false, +}, flagpd1("fno-openmp"), flagpd1("fno-openmp-cuda-force-full-runtime"), flagpd1("fno-openmp-cuda-mode"), @@ -3235,7 +3242,14 @@ flagpd1("fobjc-runtime-has-weak"), flagpd1("fobjc-sender-dependent-dispatch"), flagpd1("fobjc-subscripting-legacy-runtime"), flagpd1("fobjc-weak"), -flagpd1("fomit-frame-pointer"), +.{ + .name = "fomit-frame-pointer", + .syntax = .flag, + .zig_equivalent = .omit_frame_pointer, + .pd1 = true, + .pd2 = false, + .psl = false, +}, flagpd1("fopenmp"), flagpd1("fopenmp-cuda-force-full-runtime"), flagpd1("fopenmp-cuda-mode"), diff --git a/src/glibc.zig b/src/glibc.zig index aed1a24437..049db4f870 100644 --- a/src/glibc.zig +++ b/src/glibc.zig @@ -953,6 +953,7 @@ fn buildSharedLib( .want_sanitize_c = false, .want_stack_check = false, .want_red_zone = comp.bin_file.options.red_zone, + .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, .want_valgrind = false, .want_tsan = false, .emit_h = null, diff --git a/src/libcxx.zig b/src/libcxx.zig index 2cff5d738a..0fa0a8fc75 100644 --- a/src/libcxx.zig +++ b/src/libcxx.zig @@ -189,6 +189,7 @@ pub fn buildLibCXX(comp: *Compilation) !void { .want_sanitize_c = false, .want_stack_check = false, .want_red_zone = comp.bin_file.options.red_zone, + .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, .want_valgrind = false, .want_tsan = comp.bin_file.options.tsan, .want_pic = comp.bin_file.options.pic, @@ -321,6 +322,7 @@ pub fn buildLibCXXABI(comp: *Compilation) !void { .want_sanitize_c = false, .want_stack_check = false, .want_red_zone = comp.bin_file.options.red_zone, + .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, .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 192f9ac2d2..50c329c6d6 100644 --- a/src/libunwind.zig +++ b/src/libunwind.zig @@ -113,6 +113,7 @@ pub fn buildStaticLib(comp: *Compilation) !void { .want_sanitize_c = false, .want_stack_check = false, .want_red_zone = comp.bin_file.options.red_zone, + .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, .want_valgrind = false, .want_tsan = false, .want_pic = comp.bin_file.options.pic, diff --git a/src/link.zig b/src/link.zig index 9af7fe929c..675c218d68 100644 --- a/src/link.zig +++ b/src/link.zig @@ -90,6 +90,7 @@ pub const Options = struct { tsan: bool, stack_check: bool, red_zone: bool, + omit_frame_pointer: bool, single_threaded: bool, verbose_link: bool, dll_export_fns: bool, diff --git a/src/main.zig b/src/main.zig index fbe388ed47..d978df565d 100644 --- a/src/main.zig +++ b/src/main.zig @@ -330,6 +330,8 @@ const usage_build_generic = \\ medium|large] \\ -mred-zone Force-enable the "red-zone" \\ -mno-red-zone Force-disable the "red-zone" + \\ -fomit-frame-pointer Omit the stack frame pointer + \\ -fno-omit-frame-pointer Store the stack frame pointer \\ -mexec-model=[value] Execution model (WASI only) \\ --name [name] Override root name (not a file path) \\ -O [mode] Choose what to optimize for @@ -587,6 +589,7 @@ fn buildOutputType( var want_sanitize_c: ?bool = null; var want_stack_check: ?bool = null; var want_red_zone: ?bool = null; + var omit_frame_pointer: ?bool = null; var want_valgrind: ?bool = null; var want_tsan: ?bool = null; var want_compiler_rt: ?bool = null; @@ -975,6 +978,10 @@ fn buildOutputType( want_red_zone = true; } else if (mem.eql(u8, arg, "-mno-red-zone")) { want_red_zone = false; + } else if (mem.eql(u8, arg, "-fomit-frame-pointer")) { + omit_frame_pointer = true; + } else if (mem.eql(u8, arg, "-fno-omit-frame-pointer")) { + omit_frame_pointer = false; } else if (mem.eql(u8, arg, "-fsanitize-c")) { want_sanitize_c = true; } else if (mem.eql(u8, arg, "-fno-sanitize-c")) { @@ -1216,6 +1223,8 @@ fn buildOutputType( .no_lto => want_lto = false, .red_zone => want_red_zone = true, .no_red_zone => want_red_zone = false, + .omit_frame_pointer => omit_frame_pointer = true, + .no_omit_frame_pointer => omit_frame_pointer = false, .unwind_tables => want_unwind_tables = true, .no_unwind_tables => want_unwind_tables = false, .nostdlib => ensure_libc_on_non_freestanding = false, @@ -2081,6 +2090,7 @@ fn buildOutputType( .want_sanitize_c = want_sanitize_c, .want_stack_check = want_stack_check, .want_red_zone = want_red_zone, + .omit_frame_pointer = omit_frame_pointer, .want_valgrind = want_valgrind, .want_tsan = want_tsan, .want_compiler_rt = want_compiler_rt, @@ -3706,6 +3716,8 @@ pub const ClangArgIterator = struct { nostdlibinc, red_zone, no_red_zone, + omit_frame_pointer, + no_omit_frame_pointer, strip, exec_model, emit_llvm, diff --git a/src/musl.zig b/src/musl.zig index 3b5915719b..d0f11af604 100644 --- a/src/musl.zig +++ b/src/musl.zig @@ -207,6 +207,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void { .want_sanitize_c = false, .want_stack_check = false, .want_red_zone = comp.bin_file.options.red_zone, + .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, .want_valgrind = false, .want_tsan = false, .emit_h = null, diff --git a/src/stage1.zig b/src/stage1.zig index 8ebc876665..467f0e69d7 100644 --- a/src/stage1.zig +++ b/src/stage1.zig @@ -128,6 +128,7 @@ pub const Module = extern struct { include_compiler_rt: bool, enable_stack_probing: bool, red_zone: bool, + omit_frame_pointer: 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 5b58766df9..284a5a5468 100644 --- a/src/stage1/all_types.hpp +++ b/src/stage1/all_types.hpp @@ -2175,6 +2175,7 @@ struct CodeGen { bool dll_export_fns; bool have_stack_probing; bool red_zone; + bool omit_frame_pointer; bool function_sections; bool include_compiler_rt; bool test_is_evented; diff --git a/src/stage1/stage1.cpp b/src/stage1/stage1.cpp index 118747e79e..856bb61dcb 100644 --- a/src/stage1/stage1.cpp +++ b/src/stage1/stage1.cpp @@ -95,6 +95,7 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) { g->unwind_tables = stage1->unwind_tables; g->have_stack_probing = stage1->enable_stack_probing; g->red_zone = stage1->red_zone; + g->omit_frame_pointer = stage1->omit_frame_pointer; 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 b3d4893747..ce8254eaef 100644 --- a/src/stage1/stage1.h +++ b/src/stage1/stage1.h @@ -199,6 +199,7 @@ struct ZigStage1 { bool include_compiler_rt; bool enable_stack_probing; bool red_zone; + bool omit_frame_pointer; bool enable_time_report; bool enable_stack_report; bool test_is_evented; diff --git a/tools/update_clang_options.zig b/tools/update_clang_options.zig index 2a0da66578..361d28cfa0 100644 --- a/tools/update_clang_options.zig +++ b/tools/update_clang_options.zig @@ -300,6 +300,14 @@ const known_options = [_]KnownOpt{ .name = "mno-red-zone", .ident = "no_red_zone", }, + .{ + .name = "fomit-frame-pointer", + .ident = "omit_frame_pointer", + }, + .{ + .name = "fno-omit-frame-pointer", + .ident = "no_omit_frame_pointer", + }, .{ .name = "MD", .ident = "dep_file", From 1e942211901f0c8bc2f857b48dc8254e57a00ef4 Mon Sep 17 00:00:00 2001 From: Lee Cannon Date: Thu, 30 Sep 2021 19:50:18 +0100 Subject: [PATCH 2/4] stage1 codegen --- src/stage1/codegen.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp index 2a9ac84286..10dbd3b359 100644 --- a/src/stage1/codegen.cpp +++ b/src/stage1/codegen.cpp @@ -363,10 +363,6 @@ static bool cc_want_sret_attr(CallingConvention cc) { zig_unreachable(); } -static bool codegen_have_frame_pointer(CodeGen *g) { - return g->build_mode == BuildModeDebug; -} - static void add_common_fn_attributes(CodeGen *g, LLVMValueRef llvm_fn) { if (!g->red_zone) { addLLVMFnAttr(llvm_fn, "noredzone"); @@ -603,7 +599,7 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { addLLVMFnAttrInt(llvm_fn, "alignstack", fn->alignstack_value); } - if (codegen_have_frame_pointer(g) && cc != CallingConventionInline) { + if (!g->omit_frame_pointer && cc != CallingConventionInline) { ZigLLVMAddFunctionAttr(llvm_fn, "frame-pointer", "all"); } if (fn->section_name) { @@ -1223,7 +1219,7 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) { // Error return trace memory is in the stack, which is impossible to be at address 0 // on any architecture. addLLVMArgAttr(fn_val, (unsigned)0, "nonnull"); - if (codegen_have_frame_pointer(g)) { + if (!g->omit_frame_pointer) { ZigLLVMAddFunctionAttr(fn_val, "frame-pointer", "all"); } @@ -1299,7 +1295,7 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) { LLVMSetLinkage(fn_val, LLVMInternalLinkage); ZigLLVMFunctionSetCallingConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); add_common_fn_attributes(g, fn_val); - if (codegen_have_frame_pointer(g)) { + if (!g->omit_frame_pointer) { ZigLLVMAddFunctionAttr(fn_val, "frame-pointer", "all"); } @@ -1381,7 +1377,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { LLVMSetLinkage(fn_val, LLVMInternalLinkage); ZigLLVMFunctionSetCallingConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); add_common_fn_attributes(g, fn_val); - if (codegen_have_frame_pointer(g)) { + if (!g->omit_frame_pointer) { ZigLLVMAddFunctionAttr(fn_val, "frame-pointer", "all"); } // Not setting alignment here. See the comment above about @@ -2389,7 +2385,7 @@ static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) { addLLVMArgAttr(fn_val, (unsigned)1, "noalias"); addLLVMArgAttr(fn_val, (unsigned)1, "readonly"); - if (codegen_have_frame_pointer(g)) { + if (!g->omit_frame_pointer) { ZigLLVMAddFunctionAttr(fn_val, "frame-pointer", "all"); } @@ -5444,7 +5440,7 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) { LLVMSetLinkage(fn_val, LLVMInternalLinkage); ZigLLVMFunctionSetCallingConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); add_common_fn_attributes(g, fn_val); - if (codegen_have_frame_pointer(g)) { + if (!g->omit_frame_pointer) { ZigLLVMAddFunctionAttr(fn_val, "frame-pointer", "all"); } From 023e4b9fedbbd2e81ec684a359b040a3a6fd065e Mon Sep 17 00:00:00 2001 From: Lee Cannon Date: Thu, 30 Sep 2021 19:51:05 +0100 Subject: [PATCH 3/4] stage2 - add llvm bindings to create attributes with string values --- src/codegen/llvm.zig | 20 ++++++++++++++++++++ src/codegen/llvm/bindings.zig | 3 +++ 2 files changed, 23 insertions(+) diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 4349fce4d9..1fb657e915 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1389,10 +1389,30 @@ pub const DeclGen = struct { val.addAttributeAtIndex(index, llvm_attr); } + fn addAttrString( + dg: *DeclGen, + val: *const llvm.Value, + index: llvm.AttributeIndex, + name: []const u8, + value: []const u8, + ) void { + const llvm_attr = dg.context.createStringAttribute( + name.ptr, + @intCast(c_uint, name.len), + value.ptr, + @intCast(c_uint, value.len), + ); + val.addAttributeAtIndex(index, llvm_attr); + } + fn addFnAttr(dg: DeclGen, val: *const llvm.Value, name: []const u8) void { dg.addAttr(val, std.math.maxInt(llvm.AttributeIndex), name); } + fn addFnAttrString(dg: *DeclGen, val: *const llvm.Value, name: []const u8, value: []const u8) void { + dg.addAttrString(val, std.math.maxInt(llvm.AttributeIndex), name, value); + } + fn removeFnAttr(fn_val: *const llvm.Value, name: []const u8) void { removeAttr(fn_val, std.math.maxInt(llvm.AttributeIndex), name); } diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index 29a46a81ee..ab4cf97350 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -28,6 +28,9 @@ pub const Context = opaque { pub const createEnumAttribute = LLVMCreateEnumAttribute; extern fn LLVMCreateEnumAttribute(*const Context, KindID: c_uint, Val: u64) *const Attribute; + pub const createStringAttribute = LLVMCreateStringAttribute; + extern fn LLVMCreateStringAttribute(*const Context, Key: [*]const u8, Key_Len: c_uint, Value: [*]const u8, Value_Len: c_uint) *const Attribute; + pub const intType = LLVMIntTypeInContext; extern fn LLVMIntTypeInContext(C: *const Context, NumBits: c_uint) *const Type; From b5be01a5972d2288658eecbf6a52c3ea8331c151 Mon Sep 17 00:00:00 2001 From: Lee Cannon Date: Thu, 30 Sep 2021 19:51:17 +0100 Subject: [PATCH 4/4] stage2 codegen --- src/codegen/llvm.zig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 1fb657e915..681b3c36db 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -674,6 +674,11 @@ pub const DeclGen = struct { if (!dg.module.comp.bin_file.options.red_zone) { dg.addFnAttr(llvm_fn, "noredzone"); } + if (dg.module.comp.bin_file.options.omit_frame_pointer) { + dg.addFnAttrString(llvm_fn, "frame-pointer", "none"); + } else { + dg.addFnAttrString(llvm_fn, "frame-pointer", "all"); + } dg.addFnAttr(llvm_fn, "nounwind"); if (dg.module.comp.unwind_tables) { dg.addFnAttr(llvm_fn, "uwtable");