Commit b57819118d

Alex Rønne Petersen <alex@alexrp.com>
2024-11-05 14:29:44
Compilation: Move no_builtin to Package.Module.
This option, by its very nature, needs to be attached to a module. If it isn't, the code in a module could break at random when compiled into an application that doesn't have this option set. After this change, skip_linker_dependencies no longer implies no_builtin in the LLVM backend.
1 parent 56b4166
src/codegen/llvm.zig
@@ -3222,8 +3222,6 @@ pub const Object = struct {
         owner_mod: *Package.Module,
         omit_frame_pointer: bool,
     ) Allocator.Error!void {
-        const comp = o.pt.zcu.comp;
-
         if (!owner_mod.red_zone) {
             try attributes.addFnAttr(.noredzone, &o.builder);
         }
@@ -3242,8 +3240,7 @@ pub const Object = struct {
         if (owner_mod.unwind_tables) {
             try attributes.addFnAttr(.{ .uwtable = Builder.Attribute.UwTable.default }, &o.builder);
         }
-        const target = owner_mod.resolved_target.result;
-        if (comp.skip_linker_dependencies or comp.no_builtin or target.cpu.arch.isBpf()) {
+        if (owner_mod.no_builtin) {
             // The intent here is for compiler-rt and libc functions to not generate
             // infinite recursion. For example, if we are compiling the memcpy function,
             // and llvm detects that the body is equivalent to memcpy, it may replace the
@@ -3258,6 +3255,7 @@ pub const Object = struct {
             try attributes.addFnAttr(.minsize, &o.builder);
             try attributes.addFnAttr(.optsize, &o.builder);
         }
+        const target = owner_mod.resolved_target.result;
         if (target.cpu.model.llvm_name) |s| {
             try attributes.addFnAttr(.{ .string = .{
                 .kind = try o.builder.string("target-cpu"),
src/Package/Module.zig
@@ -31,6 +31,7 @@ unwind_tables: bool,
 cc_argv: []const []const u8,
 /// (SPIR-V) whether to generate a structured control flow graph or not
 structured_cfg: bool,
+no_builtin: bool,
 
 /// If the module is an `@import("builtin")` module, this is the `File` that
 /// is preallocated for it. Otherwise this field is null.
@@ -95,6 +96,7 @@ pub const CreateOptions = struct {
         sanitize_thread: ?bool = null,
         fuzz: ?bool = null,
         structured_cfg: ?bool = null,
+        no_builtin: ?bool = null,
     };
 };
 
@@ -298,6 +300,13 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {
         };
     };
 
+    const no_builtin = b: {
+        if (options.inherited.no_builtin) |x| break :b x;
+        if (options.parent) |p| break :b p.no_builtin;
+
+        break :b target.cpu.arch.isBpf();
+    };
+
     const llvm_cpu_features: ?[*:0]const u8 = b: {
         if (resolved_target.llvm_cpu_features) |x| break :b x;
         if (!options.global.use_llvm) break :b null;
@@ -350,6 +359,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {
         .unwind_tables = unwind_tables,
         .cc_argv = options.cc_argv,
         .structured_cfg = structured_cfg,
+        .no_builtin = no_builtin,
         .builtin_file = null,
     };
 
@@ -442,6 +452,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {
             .unwind_tables = unwind_tables,
             .cc_argv = &.{},
             .structured_cfg = structured_cfg,
+            .no_builtin = no_builtin,
             .builtin_file = new_file,
         };
         new_file.* = .{
@@ -502,6 +513,7 @@ pub fn createLimited(gpa: Allocator, options: LimitedOptions) Allocator.Error!*P
         .unwind_tables = undefined,
         .cc_argv = undefined,
         .structured_cfg = undefined,
+        .no_builtin = undefined,
         .builtin_file = null,
     };
     return mod;
src/Compilation.zig
@@ -89,7 +89,6 @@ windows_libs: std.StringArrayHashMapUnmanaged(void),
 version: ?std.SemanticVersion,
 libc_installation: ?*const LibCInstallation,
 skip_linker_dependencies: bool,
-no_builtin: bool,
 function_sections: bool,
 data_sections: bool,
 link_eh_frame_hdr: bool,
@@ -852,6 +851,7 @@ pub const cache_helpers = struct {
         hh.add(mod.fuzz);
         hh.add(mod.unwind_tables);
         hh.add(mod.structured_cfg);
+        hh.add(mod.no_builtin);
         hh.addListOfBytes(mod.cc_argv);
     }
 
@@ -1057,7 +1057,6 @@ pub const CreateOptions = struct {
     want_lto: ?bool = null,
     function_sections: bool = false,
     data_sections: bool = false,
-    no_builtin: bool = false,
     time_report: bool = false,
     stack_report: bool = false,
     link_eh_frame_hdr: bool = false,
@@ -1353,7 +1352,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
         cache.hash.add(options.config.link_mode);
         cache.hash.add(options.function_sections);
         cache.hash.add(options.data_sections);
-        cache.hash.add(options.no_builtin);
         cache.hash.add(link_libc);
         cache.hash.add(options.config.link_libcpp);
         cache.hash.add(options.config.link_libunwind);
@@ -1490,7 +1488,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
             .framework_dirs = options.framework_dirs,
             .llvm_opt_bisect_limit = options.llvm_opt_bisect_limit,
             .skip_linker_dependencies = options.skip_linker_dependencies,
-            .no_builtin = options.no_builtin,
             .job_queued_update_builtin_zig = have_zcu,
             .function_sections = options.function_sections,
             .data_sections = options.data_sections,
@@ -5261,7 +5258,7 @@ pub fn addCCArgs(
         try argv.append("-fdata-sections");
     }
 
-    if (comp.no_builtin) {
+    if (mod.no_builtin) {
         try argv.append("-fno-builtin");
     }
 
@@ -6189,6 +6186,7 @@ fn buildOutputFromZig(
             .pic = comp.root_mod.pic,
             .optimize_mode = optimize_mode,
             .structured_cfg = comp.root_mod.structured_cfg,
+            .no_builtin = true,
             .code_model = comp.root_mod.code_model,
         },
         .global = config,
@@ -6237,7 +6235,6 @@ fn buildOutputFromZig(
         },
         .function_sections = true,
         .data_sections = true,
-        .no_builtin = true,
         .emit_h = null,
         .verbose_cc = comp.verbose_cc,
         .verbose_link = comp.verbose_link,
@@ -6262,16 +6259,21 @@ fn buildOutputFromZig(
     comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
 }
 
+pub const CrtFileOptions = struct {
+    pic: ?bool = null,
+    no_builtin: ?bool = null,
+};
+
 pub fn build_crt_file(
     comp: *Compilation,
     root_name: []const u8,
     output_mode: std.builtin.OutputMode,
-    pic: ?bool,
     misc_task_tag: MiscTask,
     prog_node: std.Progress.Node,
     /// These elements have to get mutated to add the owner module after it is
     /// created within this function.
     c_source_files: []CSourceFile,
+    options: CrtFileOptions,
 ) !void {
     const tracy_trace = trace(@src());
     defer tracy_trace.end();
@@ -6319,10 +6321,12 @@ pub fn build_crt_file(
             .omit_frame_pointer = comp.root_mod.omit_frame_pointer,
             .valgrind = false,
             .unwind_tables = false,
-            // Some CRT objects (rcrt1.o, Scrt1.o) are opinionated about PIC.
-            .pic = pic orelse comp.root_mod.pic,
+            // Some CRT objects (e.g. musl's rcrt1.o and Scrt1.o) are opinionated about PIC.
+            .pic = options.pic orelse comp.root_mod.pic,
             .optimize_mode = comp.compilerRtOptMode(),
             .structured_cfg = comp.root_mod.structured_cfg,
+            // Some libcs (e.g. musl) are opinionated about -fno-builtin.
+            .no_builtin = options.no_builtin orelse comp.root_mod.no_builtin,
         },
         .global = config,
         .cc_argv = &.{},
src/glibc.zig
@@ -221,7 +221,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
                     .owner = comp.root_mod,
                 },
             };
-            return comp.build_crt_file("crti", .Obj, null, .@"glibc crti.o", prog_node, &files);
+            return comp.build_crt_file("crti", .Obj, .@"glibc crti.o", prog_node, &files, .{});
         },
         .crtn_o => {
             var args = std.ArrayList([]const u8).init(arena);
@@ -242,7 +242,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
                     .owner = undefined,
                 },
             };
-            return comp.build_crt_file("crtn", .Obj, null, .@"glibc crtn.o", prog_node, &files);
+            return comp.build_crt_file("crtn", .Obj, .@"glibc crtn.o", prog_node, &files, .{});
         },
         .scrt1_o => {
             const start_o: Compilation.CSourceFile = blk: {
@@ -295,7 +295,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
             };
             var files = [_]Compilation.CSourceFile{ start_o, abi_note_o, init_o };
             const basename = if (comp.config.output_mode == .Exe and !comp.config.pie) "crt1" else "Scrt1";
-            return comp.build_crt_file(basename, .Obj, null, .@"glibc Scrt1.o", prog_node, &files);
+            return comp.build_crt_file(basename, .Obj, .@"glibc Scrt1.o", prog_node, &files, .{});
         },
         .libc_nonshared_a => {
             const s = path.sep_str;
@@ -413,7 +413,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
                 files_index += 1;
             }
             const files = files_buf[0..files_index];
-            return comp.build_crt_file("c_nonshared", .Lib, null, .@"glibc libc_nonshared.a", prog_node, files);
+            return comp.build_crt_file("c_nonshared", .Lib, .@"glibc libc_nonshared.a", prog_node, files, .{});
         },
     }
 }
src/main.zig
@@ -810,7 +810,6 @@ fn buildOutputType(
     var compatibility_version: ?std.SemanticVersion = null;
     var function_sections = false;
     var data_sections = false;
-    var no_builtin = false;
     var listen: Listen = .none;
     var debug_compile_errors = false;
     var verbose_link = (native_os != .wasi or builtin.link_libc) and
@@ -1550,9 +1549,9 @@ fn buildOutputType(
                     } else if (mem.eql(u8, arg, "-fno-data-sections")) {
                         data_sections = false;
                     } else if (mem.eql(u8, arg, "-fbuiltin")) {
-                        no_builtin = false;
+                        mod_opts.no_builtin = false;
                     } else if (mem.eql(u8, arg, "-fno-builtin")) {
-                        no_builtin = true;
+                        mod_opts.no_builtin = true;
                     } else if (mem.startsWith(u8, arg, "-fopt-bisect-limit=")) {
                         const next_arg = arg["-fopt-bisect-limit=".len..];
                         llvm_opt_bisect_limit = std.fmt.parseInt(c_int, next_arg, 0) catch |err|
@@ -1963,8 +1962,8 @@ fn buildOutputType(
                     .no_function_sections => function_sections = false,
                     .data_sections => data_sections = true,
                     .no_data_sections => data_sections = false,
-                    .builtin => no_builtin = false,
-                    .no_builtin => no_builtin = true,
+                    .builtin => mod_opts.no_builtin = false,
+                    .no_builtin => mod_opts.no_builtin = true,
                     .color_diagnostics => color = .on,
                     .no_color_diagnostics => color = .off,
                     .stack_check => mod_opts.stack_check = true,
@@ -3468,7 +3467,6 @@ fn buildOutputType(
         .image_base = image_base,
         .function_sections = function_sections,
         .data_sections = data_sections,
-        .no_builtin = no_builtin,
         .clang_passthrough_mode = clang_passthrough_mode,
         .clang_preprocessor_mode = clang_preprocessor_mode,
         .version = optional_version,
src/mingw.zig
@@ -41,7 +41,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
                     .owner = undefined,
                 },
             };
-            return comp.build_crt_file("crt2", .Obj, null, .@"mingw-w64 crt2.o", prog_node, &files);
+            return comp.build_crt_file("crt2", .Obj, .@"mingw-w64 crt2.o", prog_node, &files, .{});
         },
 
         .dllcrt2_o => {
@@ -56,7 +56,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
                     .owner = undefined,
                 },
             };
-            return comp.build_crt_file("dllcrt2", .Obj, null, .@"mingw-w64 dllcrt2.o", prog_node, &files);
+            return comp.build_crt_file("dllcrt2", .Obj, .@"mingw-w64 dllcrt2.o", prog_node, &files, .{});
         },
 
         .mingw32_lib => {
@@ -118,7 +118,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
             } else {
                 @panic("unsupported arch");
             }
-            return comp.build_crt_file("mingw32", .Lib, null, .@"mingw-w64 mingw32.lib", prog_node, c_source_files.items);
+            return comp.build_crt_file("mingw32", .Lib, .@"mingw-w64 mingw32.lib", prog_node, c_source_files.items, .{});
         },
     }
 }
src/musl.zig
@@ -38,7 +38,9 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro
                     .owner = undefined,
                 },
             };
-            return comp.build_crt_file("crti", .Obj, null, .@"musl crti.o", prog_node, &files);
+            return comp.build_crt_file("crti", .Obj, .@"musl crti.o", prog_node, &files, .{
+                .no_builtin = true,
+            });
         },
         .crtn_o => {
             var args = std.ArrayList([]const u8).init(arena);
@@ -50,7 +52,9 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro
                     .owner = undefined,
                 },
             };
-            return comp.build_crt_file("crtn", .Obj, null, .@"musl crtn.o", prog_node, &files);
+            return comp.build_crt_file("crtn", .Obj, .@"musl crtn.o", prog_node, &files, .{
+                .no_builtin = true,
+            });
         },
         .crt1_o => {
             var args = std.ArrayList([]const u8).init(arena);
@@ -68,7 +72,9 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro
                     .owner = undefined,
                 },
             };
-            return comp.build_crt_file("crt1", .Obj, null, .@"musl crt1.o", prog_node, &files);
+            return comp.build_crt_file("crt1", .Obj, .@"musl crt1.o", prog_node, &files, .{
+                .no_builtin = true,
+            });
         },
         .rcrt1_o => {
             var args = std.ArrayList([]const u8).init(arena);
@@ -86,7 +92,10 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro
                     .owner = undefined,
                 },
             };
-            return comp.build_crt_file("rcrt1", .Obj, true, .@"musl rcrt1.o", prog_node, &files);
+            return comp.build_crt_file("rcrt1", .Obj, .@"musl rcrt1.o", prog_node, &files, .{
+                .pic = true,
+                .no_builtin = true,
+            });
         },
         .scrt1_o => {
             var args = std.ArrayList([]const u8).init(arena);
@@ -104,7 +113,10 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro
                     .owner = undefined,
                 },
             };
-            return comp.build_crt_file("Scrt1", .Obj, true, .@"musl Scrt1.o", prog_node, &files);
+            return comp.build_crt_file("Scrt1", .Obj, .@"musl Scrt1.o", prog_node, &files, .{
+                .pic = true,
+                .no_builtin = true,
+            });
         },
         .libc_a => {
             // When there is a src/<arch>/foo.* then it should substitute for src/foo.*
@@ -197,7 +209,9 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro
                     .owner = undefined,
                 };
             }
-            return comp.build_crt_file("c", .Lib, null, .@"musl libc.a", prog_node, c_source_files.items);
+            return comp.build_crt_file("c", .Lib, .@"musl libc.a", prog_node, c_source_files.items, .{
+                .no_builtin = true,
+            });
         },
         .libc_so => {
             const optimize_mode = comp.compilerRtOptMode();
@@ -410,7 +424,6 @@ fn addCcArgs(
     try args.appendSlice(&[_][]const u8{
         "-std=c99",
         "-ffreestanding",
-        "-fno-builtin",
         "-fexcess-precision=standard",
         "-frounding-math",
         "-ffp-contract=off",
src/wasi_libc.zig
@@ -81,7 +81,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
                     .owner = undefined,
                 },
             };
-            return comp.build_crt_file("crt1-reactor", .Obj, null, .@"wasi crt1-reactor.o", prog_node, &files);
+            return comp.build_crt_file("crt1-reactor", .Obj, .@"wasi crt1-reactor.o", prog_node, &files, .{});
         },
         .crt1_command_o => {
             var args = std.ArrayList([]const u8).init(arena);
@@ -96,7 +96,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
                     .owner = undefined,
                 },
             };
-            return comp.build_crt_file("crt1-command", .Obj, null, .@"wasi crt1-command.o", prog_node, &files);
+            return comp.build_crt_file("crt1-command", .Obj, .@"wasi crt1-command.o", prog_node, &files, .{});
         },
         .libc_a => {
             var libc_sources = std.ArrayList(Compilation.CSourceFile).init(arena);
@@ -150,7 +150,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
                 }
             }
 
-            try comp.build_crt_file("c", .Lib, null, .@"wasi libc.a", prog_node, libc_sources.items);
+            try comp.build_crt_file("c", .Lib, .@"wasi libc.a", prog_node, libc_sources.items, .{});
         },
         .libwasi_emulated_process_clocks_a => {
             var args = std.ArrayList([]const u8).init(arena);
@@ -167,7 +167,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
                     .owner = undefined,
                 });
             }
-            try comp.build_crt_file("wasi-emulated-process-clocks", .Lib, null, .@"libwasi-emulated-process-clocks.a", prog_node, emu_clocks_sources.items);
+            try comp.build_crt_file("wasi-emulated-process-clocks", .Lib, .@"libwasi-emulated-process-clocks.a", prog_node, emu_clocks_sources.items, .{});
         },
         .libwasi_emulated_getpid_a => {
             var args = std.ArrayList([]const u8).init(arena);
@@ -184,7 +184,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
                     .owner = undefined,
                 });
             }
-            try comp.build_crt_file("wasi-emulated-getpid", .Lib, null, .@"libwasi-emulated-getpid.a", prog_node, emu_getpid_sources.items);
+            try comp.build_crt_file("wasi-emulated-getpid", .Lib, .@"libwasi-emulated-getpid.a", prog_node, emu_getpid_sources.items, .{});
         },
         .libwasi_emulated_mman_a => {
             var args = std.ArrayList([]const u8).init(arena);
@@ -201,7 +201,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
                     .owner = undefined,
                 });
             }
-            try comp.build_crt_file("wasi-emulated-mman", .Lib, null, .@"libwasi-emulated-mman.a", prog_node, emu_mman_sources.items);
+            try comp.build_crt_file("wasi-emulated-mman", .Lib, .@"libwasi-emulated-mman.a", prog_node, emu_mman_sources.items, .{});
         },
         .libwasi_emulated_signal_a => {
             var emu_signal_sources = std.ArrayList(Compilation.CSourceFile).init(arena);
@@ -238,7 +238,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
                 }
             }
 
-            try comp.build_crt_file("wasi-emulated-signal", .Lib, null, .@"libwasi-emulated-signal.a", prog_node, emu_signal_sources.items);
+            try comp.build_crt_file("wasi-emulated-signal", .Lib, .@"libwasi-emulated-signal.a", prog_node, emu_signal_sources.items, .{});
         },
     }
 }