Commit 1e1598950a

Jacob Young <jacobly0@users.noreply.github.com>
2024-02-25 15:56:57
llvm: implement per-module stripping
This avoids llvm module verification errors when the strip option is different across modules.
1 parent 661137a
Changed files (3)
src/codegen/llvm/Builder.zig
@@ -3797,6 +3797,7 @@ pub const Function = struct {
     instructions: std.MultiArrayList(Instruction) = .{},
     names: [*]const String = &[0]String{},
     value_indices: [*]const u32 = &[0]u32{},
+    strip: bool,
     debug_locations: std.AutoHashMapUnmanaged(Instruction.Index, DebugLocation) = .{},
     debug_values: []const Instruction.Index = &.{},
     extra: []const u32 = &.{},
@@ -4890,6 +4891,7 @@ pub const WipFunction = struct {
     blocks: std.ArrayListUnmanaged(Block),
     instructions: std.MultiArrayList(Instruction),
     names: std.ArrayListUnmanaged(String),
+    strip: bool,
     debug_locations: std.AutoArrayHashMapUnmanaged(Instruction.Index, DebugLocation),
     debug_values: std.AutoArrayHashMapUnmanaged(Instruction.Index, void),
     extra: std.ArrayListUnmanaged(u32),
@@ -4922,31 +4924,35 @@ pub const WipFunction = struct {
 
     pub const Instruction = Function.Instruction;
 
-    pub fn init(builder: *Builder, function: Function.Index) Allocator.Error!WipFunction {
+    pub fn init(builder: *Builder, options: struct {
+        function: Function.Index,
+        strip: bool,
+    }) Allocator.Error!WipFunction {
         var self: WipFunction = .{
             .builder = builder,
-            .function = function,
+            .function = options.function,
             .prev_debug_location = .no_location,
             .debug_location = .no_location,
             .cursor = undefined,
             .blocks = .{},
             .instructions = .{},
             .names = .{},
+            .strip = options.strip,
             .debug_locations = .{},
             .debug_values = .{},
             .extra = .{},
         };
         errdefer self.deinit();
 
-        const params_len = function.typeOf(self.builder).functionParameters(self.builder).len;
+        const params_len = options.function.typeOf(self.builder).functionParameters(self.builder).len;
         try self.ensureUnusedExtraCapacity(params_len, NoExtra, 0);
         try self.instructions.ensureUnusedCapacity(self.builder.gpa, params_len);
-        if (!self.builder.strip) {
+        if (!self.strip) {
             try self.names.ensureUnusedCapacity(self.builder.gpa, params_len);
         }
         for (0..params_len) |param_index| {
             self.instructions.appendAssumeCapacity(.{ .tag = .arg, .data = @intCast(param_index) });
-            if (!self.builder.strip) {
+            if (!self.strip) {
                 self.names.appendAssumeCapacity(.empty); // TODO: param names
             }
         }
@@ -4967,7 +4973,7 @@ pub const WipFunction = struct {
         try self.blocks.ensureUnusedCapacity(self.builder.gpa, 1);
 
         const index: Block.Index = @enumFromInt(self.blocks.items.len);
-        const final_name = if (self.builder.strip) .empty else try self.builder.string(name);
+        const final_name = if (self.strip) .empty else try self.builder.string(name);
         self.blocks.appendAssumeCapacity(.{
             .name = final_name,
             .incoming = incoming,
@@ -5828,7 +5834,7 @@ pub const WipFunction = struct {
     }
 
     pub fn debugValue(self: *WipFunction, value: Value) Allocator.Error!Metadata {
-        if (self.builder.strip) return .none;
+        if (self.strip) return .none;
         return switch (value.unwrap()) {
             .instruction => |instr_index| blk: {
                 const gop = try self.debug_values.getOrPut(self.builder.gpa, instr_index);
@@ -6015,7 +6021,7 @@ pub const WipFunction = struct {
             value_index += 1;
             function.instructions.appendAssumeCapacity(argument);
             names[@intFromEnum(new_argument_index)] = try wip_name.map(
-                if (self.builder.strip) .empty else self.names.items[@intFromEnum(old_argument_index)],
+                if (self.strip) .empty else self.names.items[@intFromEnum(old_argument_index)],
                 ".",
             );
             if (self.debug_locations.get(old_argument_index)) |location| {
@@ -6333,7 +6339,7 @@ pub const WipFunction = struct {
                     },
                 }
                 function.instructions.appendAssumeCapacity(instruction);
-                names[@intFromEnum(new_instruction_index)] = try wip_name.map(if (self.builder.strip)
+                names[@intFromEnum(new_instruction_index)] = try wip_name.map(if (self.strip)
                     if (old_instruction_index.hasResultWip(self)) .empty else .none
                 else
                     self.names.items[@intFromEnum(old_instruction_index)], ".");
@@ -6356,6 +6362,7 @@ pub const WipFunction = struct {
         function.blocks = blocks;
         function.names = names.ptr;
         function.value_indices = value_indices.ptr;
+        function.strip = self.strip;
         function.debug_locations = debug_locations;
         function.debug_values = debug_values;
     }
@@ -6503,19 +6510,19 @@ pub const WipFunction = struct {
     ) Allocator.Error!Instruction.Index {
         const block_instructions = &self.cursor.block.ptr(self).instructions;
         try self.instructions.ensureUnusedCapacity(self.builder.gpa, 1);
-        if (!self.builder.strip) {
+        if (!self.strip) {
             try self.names.ensureUnusedCapacity(self.builder.gpa, 1);
             try self.debug_locations.ensureUnusedCapacity(self.builder.gpa, 1);
         }
         try block_instructions.ensureUnusedCapacity(self.builder.gpa, 1);
         const final_name = if (name) |n|
-            if (self.builder.strip) .empty else try self.builder.string(n)
+            if (self.strip) .empty else try self.builder.string(n)
         else
             .none;
 
         const index: Instruction.Index = @enumFromInt(self.instructions.len);
         self.instructions.appendAssumeCapacity(instruction);
-        if (!self.builder.strip) {
+        if (!self.strip) {
             self.names.appendAssumeCapacity(final_name);
             if (block_instructions.items.len == 0 or
                 !std.meta.eql(self.debug_location, self.prev_debug_location))
@@ -8723,11 +8730,14 @@ pub fn addFunctionAssumeCapacity(
 ) Function.Index {
     assert(ty.isFunction(self));
     const function_index: Function.Index = @enumFromInt(self.functions.items.len);
-    self.functions.appendAssumeCapacity(.{ .global = self.addGlobalAssumeCapacity(name, .{
-        .addr_space = addr_space,
-        .type = ty,
-        .kind = .{ .function = function_index },
-    }) });
+    self.functions.appendAssumeCapacity(.{
+        .global = self.addGlobalAssumeCapacity(name, .{
+            .addr_space = addr_space,
+            .type = ty,
+            .kind = .{ .function = function_index },
+        }),
+        .strip = undefined,
+    });
     return function_index;
 }
 
@@ -14396,16 +14406,17 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                     return @intCast(switch (value.unwrap()) {
                         .instruction => |instruction| instruction.valueIndex(adapter.func) + adapter.firstInstr(),
                         .constant => |constant| adapter.constant_adapter.getConstantIndex(constant),
-                        .metadata => |metadata| if (!adapter.metadata_adapter.builder.strip) blk: {
+                        .metadata => |metadata| {
+                            assert(!adapter.func.strip);
                             const real_metadata = metadata.unwrap(adapter.metadata_adapter.builder);
                             if (@intFromEnum(real_metadata) < Metadata.first_local_metadata)
-                                break :blk adapter.metadata_adapter.getMetadataIndex(real_metadata) - 1;
+                                return adapter.metadata_adapter.getMetadataIndex(real_metadata) - 1;
 
                             return @intCast(@intFromEnum(metadata) -
                                 Metadata.first_local_metadata +
                                 adapter.metadata_adapter.builder.metadata_string_map.count() - 1 +
                                 adapter.metadata_adapter.builder.metadata_map.count() - 1);
-                        } else unreachable,
+                        },
                     });
                 }
 
@@ -14452,7 +14463,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                 var adapter = FunctionAdapter.init(constant_adapter, metadata_adapter, &func);
 
                 // Emit function level metadata block
-                if (!self.strip and func.debug_values.len != 0) {
+                if (!func.strip and func.debug_values.len > 0) {
                     const MetadataBlock = ir.FunctionMetadataBlock;
                     var metadata_block = try function_block.enterSubBlock(MetadataBlock);
 
@@ -14913,7 +14924,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                         },
                     }
 
-                    if (!self.strip) {
+                    if (!func.strip) {
                         if (func.debug_locations.get(@enumFromInt(instr_index))) |debug_location| {
                             switch (debug_location) {
                                 .no_location => has_location = false,
@@ -14937,7 +14948,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                 }
 
                 // VALUE_SYMTAB
-                if (!self.strip) {
+                if (!func.strip) {
                     const ValueSymbolTable = ir.FunctionValueSymbolTable;
 
                     var value_symtab_block = try function_block.enterSubBlock(ValueSymbolTable);
@@ -14959,7 +14970,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
                 }
 
                 // METADATA_ATTACHMENT_BLOCK
-                if (!self.strip) blk: {
+                if (!func.strip) blk: {
                     const dbg = func.global.ptrConst(self).dbg;
 
                     if (dbg == .none) break :blk;
src/codegen/llvm.zig
@@ -837,11 +837,10 @@ pub const Object = struct {
         const gpa = comp.gpa;
         const target = comp.root_mod.resolved_target.result;
         const llvm_target_triple = try targetTriple(arena, target);
-        const strip = comp.root_mod.strip;
 
         var builder = try Builder.init(.{
             .allocator = gpa,
-            .strip = strip,
+            .strip = comp.config.debug_format == .strip,
             .name = comp.root_name,
             .target = target,
             .triple = llvm_target_triple,
@@ -1052,7 +1051,10 @@ pub const Object = struct {
         const mod = o.module;
         const errors_len = mod.global_error_set.count();
 
-        var wip = try Builder.WipFunction.init(&o.builder, llvm_fn.ptrConst(&o.builder).kind.function);
+        var wip = try Builder.WipFunction.init(&o.builder, .{
+            .function = llvm_fn.ptrConst(&o.builder).kind.function,
+            .strip = true,
+        });
         defer wip.deinit();
         wip.cursor = .{ .block = try wip.block(0, "Entry") };
 
@@ -1372,6 +1374,7 @@ pub const Object = struct {
         air: Air,
         liveness: Liveness,
     ) !void {
+        const comp = zcu.comp;
         const func = zcu.funcInfo(func_index);
         const decl_index = func.owner_decl;
         const decl = zcu.declPtr(decl_index);
@@ -1440,7 +1443,10 @@ pub const Object = struct {
             function_index.setSection(try o.builder.string(section), &o.builder);
 
         var deinit_wip = true;
-        var wip = try Builder.WipFunction.init(&o.builder, function_index);
+        var wip = try Builder.WipFunction.init(&o.builder, .{
+            .function = function_index,
+            .strip = owner_mod.strip,
+        });
         defer if (deinit_wip) wip.deinit();
         wip.cursor = .{ .block = try wip.block(0, "Entry") };
 
@@ -1459,8 +1465,6 @@ pub const Object = struct {
             .unsigned => try attributes.addRetAttr(.zeroext, &o.builder),
         };
 
-        const comp = zcu.comp;
-
         const err_return_tracing = Type.fromInterned(fn_info.return_type).isError(zcu) and
             comp.config.any_error_tracing;
 
@@ -1645,7 +1649,7 @@ pub const Object = struct {
 
         function_index.setAttributes(try attributes.finish(&o.builder), &o.builder);
 
-        const file, const subprogram = if (!o.builder.strip) debug_info: {
+        const file, const subprogram = if (!wip.strip) debug_info: {
             const file = try o.getDebugFile(namespace.file_scope);
 
             const line_number = decl.src_line + 1;
@@ -4616,7 +4620,10 @@ pub const Object = struct {
         function_index.setAttributes(try attributes.finish(&o.builder), &o.builder);
         gop.value_ptr.* = function_index.ptrConst(&o.builder).global;
 
-        var wip = try Builder.WipFunction.init(&o.builder, function_index);
+        var wip = try Builder.WipFunction.init(&o.builder, .{
+            .function = function_index,
+            .strip = true,
+        });
         defer wip.deinit();
         wip.cursor = .{ .block = try wip.block(0, "Entry") };
 
@@ -4686,23 +4693,23 @@ pub const DeclGen = struct {
 
     fn genDecl(dg: *DeclGen) !void {
         const o = dg.object;
-        const mod = o.module;
+        const zcu = o.module;
         const decl = dg.decl;
         const decl_index = dg.decl_index;
         assert(decl.has_tv);
 
-        if (decl.val.getExternFunc(mod)) |extern_func| {
+        if (decl.val.getExternFunc(zcu)) |extern_func| {
             _ = try o.resolveLlvmFunction(extern_func.decl);
         } else {
             const variable_index = try o.resolveGlobalDecl(decl_index);
             variable_index.setAlignment(
-                decl.getAlignment(mod).toLlvm(),
+                decl.getAlignment(zcu).toLlvm(),
                 &o.builder,
             );
-            if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |section|
+            if (zcu.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |section|
                 variable_index.setSection(try o.builder.string(section), &o.builder);
             assert(decl.has_tv);
-            const init_val = if (decl.val.getVariable(mod)) |decl_var| decl_var.init else init_val: {
+            const init_val = if (decl.val.getVariable(zcu)) |decl_var| decl_var.init else init_val: {
                 variable_index.setMutability(.constant, &o.builder);
                 break :init_val decl.val.toIntern();
             };
@@ -4714,12 +4721,15 @@ pub const DeclGen = struct {
             const line_number = decl.src_line + 1;
             const is_internal_linkage = !o.module.decl_exports.contains(decl_index);
 
-            if (dg.object.builder.strip) return;
+            const namespace = zcu.namespacePtr(decl.src_namespace);
+            const owner_mod = namespace.file_scope.mod;
 
-            const debug_file = try o.getDebugFile(mod.namespacePtr(decl.src_namespace).file_scope);
+            if (owner_mod.strip) return;
+
+            const debug_file = try o.getDebugFile(namespace.file_scope);
 
             const debug_global_var = try o.builder.debugGlobalVar(
-                try o.builder.metadataString(mod.intern_pool.stringToSlice(decl.name)), // Name
+                try o.builder.metadataString(zcu.intern_pool.stringToSlice(decl.name)), // Name
                 try o.builder.metadataStringFromString(variable_index.name(&o.builder)), // Linkage name
                 debug_file, // File
                 debug_file, // Scope
@@ -4735,7 +4745,7 @@ pub const DeclGen = struct {
                 debug_global_var,
                 debug_expression,
             );
-            if (!is_internal_linkage or decl.isExtern(mod))
+            if (!is_internal_linkage or decl.isExtern(zcu))
                 variable_index.setGlobalVariableExpression(debug_global_var_expression, &o.builder);
             try o.debug_globals.append(o.gpa, debug_global_var_expression);
         }
@@ -6570,7 +6580,6 @@ pub const FuncGen = struct {
     }
 
     fn airDbgStmt(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
-        if (self.wip.builder.strip) return .none;
         const dbg_stmt = self.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;
         self.prev_dbg_line = @intCast(self.base_line + dbg_stmt.line + 1);
         self.prev_dbg_column = @intCast(dbg_stmt.column + 1);
@@ -6593,7 +6602,6 @@ pub const FuncGen = struct {
     }
 
     fn airDbgInlineBegin(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
-        if (self.wip.builder.strip) return .none;
         const o = self.dg.object;
         const zcu = o.module;
 
@@ -6660,7 +6668,6 @@ pub const FuncGen = struct {
     }
 
     fn airDbgInlineEnd(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {
-        if (self.wip.builder.strip) return .none;
         const o = self.dg.object;
 
         const ty_fn = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn;
@@ -6677,7 +6684,6 @@ pub const FuncGen = struct {
     }
 
     fn airDbgBlockBegin(self: *FuncGen) Allocator.Error!Builder.Value {
-        if (self.wip.builder.strip) return .none;
         const o = self.dg.object;
 
         try self.scope_stack.append(self.gpa, self.scope);
@@ -6693,13 +6699,11 @@ pub const FuncGen = struct {
     }
 
     fn airDbgBlockEnd(self: *FuncGen) !Builder.Value {
-        if (self.wip.builder.strip) return .none;
         self.scope = self.scope_stack.pop();
         return .none;
     }
 
     fn airDbgVarPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
-        if (self.wip.builder.strip) return .none;
         const o = self.dg.object;
         const mod = o.module;
         const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
@@ -6732,7 +6736,6 @@ pub const FuncGen = struct {
     }
 
     fn airDbgVarVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
-        if (self.wip.builder.strip) return .none;
         const o = self.dg.object;
         const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
         const operand = try self.resolveInst(pl_op.operand);
@@ -8813,7 +8816,7 @@ pub const FuncGen = struct {
         const arg_val = self.args[self.arg_index];
         self.arg_index += 1;
 
-        if (self.wip.builder.strip) return arg_val;
+        if (self.wip.strip) return arg_val;
 
         const inst_ty = self.typeOfIndex(inst);
         if (needDbgVarWorkaround(o)) return arg_val;
@@ -9660,7 +9663,10 @@ pub const FuncGen = struct {
         function_index.setAttributes(try attributes.finish(&o.builder), &o.builder);
         gop.value_ptr.* = function_index;
 
-        var wip = try Builder.WipFunction.init(&o.builder, function_index);
+        var wip = try Builder.WipFunction.init(&o.builder, .{
+            .function = function_index,
+            .strip = true,
+        });
         defer wip.deinit();
         wip.cursor = .{ .block = try wip.block(0, "Entry") };
 
src/Sema.zig
@@ -6415,8 +6415,6 @@ fn zirDbgVar(
     inst: Zir.Inst.Index,
     air_tag: Air.Inst.Tag,
 ) CompileError!void {
-    if (block.is_comptime or block.ownerModule().strip) return;
-
     const str_op = sema.code.instructions.items(.data)[@intFromEnum(inst)].str_op;
     const operand = try sema.resolveInst(str_op.operand);
     const name = str_op.getStr(sema.code);
@@ -6430,6 +6428,8 @@ fn addDbgVar(
     air_tag: Air.Inst.Tag,
     name: []const u8,
 ) CompileError!void {
+    if (block.is_comptime or block.ownerModule().strip) return;
+
     const mod = sema.mod;
     const operand_ty = sema.typeOf(operand);
     const val_ty = switch (air_tag) {