update codegen.llvm references to bin_file.options

This commit is contained in:
Andrew Kelley 2023-12-15 19:12:06 -07:00
parent 92b54e50c8
commit b54ad93175
8 changed files with 358 additions and 308 deletions

View File

@ -822,7 +822,7 @@ pub const Object = struct {
type_map: TypeMap,
di_type_map: DITypeMap,
/// The LLVM global table which holds the names corresponding to Zig errors.
/// Note that the values are not added until flushModule, when all errors in
/// Note that the values are not added until `emit`, when all errors in
/// the compilation are known.
error_name_table: Builder.Variable.Index,
/// This map is usually very close to empty. It tracks only the cases when a
@ -850,7 +850,7 @@ pub const Object = struct {
pub const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, Builder.Type);
/// This is an ArrayHashMap as opposed to a HashMap because in `flushModule` we
/// This is an ArrayHashMap as opposed to a HashMap because in `emit` we
/// want to iterate over it while adding entries to it.
pub const DITypeMap = std.AutoArrayHashMapUnmanaged(InternPool.Index, AnnotatedDITypePtr);
@ -1026,17 +1026,6 @@ pub const Object = struct {
self.* = undefined;
}
fn locPath(
arena: Allocator,
opt_loc: ?Compilation.EmitLoc,
cache_directory: Compilation.Directory,
) !?[*:0]u8 {
const loc = opt_loc orelse return null;
const directory = loc.directory orelse cache_directory;
const slice = try directory.joinZ(arena, &[_][]const u8{loc.basename});
return slice.ptr;
}
fn genErrorNameTable(o: *Object) Allocator.Error!void {
// If o.error_name_table is null, then it was not referenced by any instructions.
if (o.error_name_table == .none) return;
@ -1175,12 +1164,22 @@ pub const Object = struct {
}
}
pub fn flushModule(self: *Object, comp: *Compilation, prog_node: *std.Progress.Node) !void {
var sub_prog_node = prog_node.start("LLVM Emit Object", 0);
sub_prog_node.activate();
sub_prog_node.context.refresh();
defer sub_prog_node.end();
pub const EmitOptions = struct {
pre_ir_path: ?[]const u8,
pre_bc_path: ?[]const u8,
bin_path: ?[*:0]const u8,
emit_asm: ?[*:0]const u8,
post_ir_path: ?[*:0]const u8,
post_bc_path: ?[*:0]const u8,
is_debug: bool,
is_small: bool,
time_report: bool,
sanitize_thread: bool,
lto: bool,
};
pub fn emit(self: *Object, options: EmitOptions) !void {
try self.resolveExportExternCollisions();
try self.genErrorNameTable();
try self.genCmpLtErrorsLenFunction();
@ -1206,7 +1205,7 @@ pub const Object = struct {
dib.finalize();
}
if (comp.verbose_llvm_ir) |path| {
if (options.pre_ir_path) |path| {
if (std.mem.eql(u8, path, "-")) {
self.builder.dump();
} else {
@ -1214,91 +1213,72 @@ pub const Object = struct {
}
}
if (comp.verbose_llvm_bc) |path| _ = try self.builder.writeBitcodeToFile(path);
var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);
defer arena_allocator.deinit();
const arena = arena_allocator.allocator();
const mod = comp.module.?;
const cache_dir = mod.zig_cache_artifact_directory;
if (options.pre_bc_path) |path| _ = try self.builder.writeBitcodeToFile(path);
if (std.debug.runtime_safety and !try self.builder.verify()) {
if (try locPath(arena, comp.emit_llvm_ir, cache_dir)) |emit_llvm_ir_path|
_ = self.builder.printToFileZ(emit_llvm_ir_path);
@panic("LLVM module verification failed");
}
var emit_bin_path: ?[*:0]const u8 = if (comp.bin_file.options.emit) |emit|
try emit.basenamePath(arena, try arena.dupeZ(u8, comp.bin_file.intermediary_basename.?))
else
null;
const emit_asm_path = try locPath(arena, comp.emit_asm, cache_dir);
var emit_llvm_ir_path = try locPath(arena, comp.emit_llvm_ir, cache_dir);
const emit_llvm_bc_path = try locPath(arena, comp.emit_llvm_bc, cache_dir);
const emit_asm_msg = emit_asm_path orelse "(none)";
const emit_bin_msg = emit_bin_path orelse "(none)";
const emit_llvm_ir_msg = emit_llvm_ir_path orelse "(none)";
const emit_llvm_bc_msg = emit_llvm_bc_path orelse "(none)";
const emit_asm_msg = options.asm_path orelse "(none)";
const emit_bin_msg = options.bin_path orelse "(none)";
const post_llvm_ir_msg = options.post_ir_path orelse "(none)";
const post_llvm_bc_msg = options.post_bc_path orelse "(none)";
log.debug("emit LLVM object asm={s} bin={s} ir={s} bc={s}", .{
emit_asm_msg, emit_bin_msg, emit_llvm_ir_msg, emit_llvm_bc_msg,
emit_asm_msg, emit_bin_msg, post_llvm_ir_msg, post_llvm_bc_msg,
});
if (emit_asm_path == null and emit_bin_path == null and
emit_llvm_ir_path == null and emit_llvm_bc_path == null) return;
if (options.asm_path == null and options.bin_path == null and
options.post_ir_path == null and options.post_bc_path == null) return;
if (!self.builder.useLibLlvm()) {
log.err("emitting without libllvm not implemented", .{});
return error.FailedToEmit;
}
if (!self.builder.useLibLlvm()) unreachable; // caught in Compilation.Config.resolve
// Unfortunately, LLVM shits the bed when we ask for both binary and assembly.
// So we call the entire pipeline multiple times if this is requested.
var error_message: [*:0]const u8 = undefined;
if (emit_asm_path != null and emit_bin_path != null) {
var emit_bin_path = options.bin_path;
var post_ir_path = options.post_ir_path;
if (options.asm_path != null and options.bin_path != null) {
if (self.target_machine.emitToFile(
self.builder.llvm.module.?,
&error_message,
comp.bin_file.options.optimize_mode == .Debug,
comp.bin_file.options.optimize_mode == .ReleaseSmall,
comp.time_report,
comp.bin_file.options.tsan,
comp.bin_file.options.lto,
options.is_debug,
options.is_small,
options.time_report,
options.sanitize_thread,
options.lto,
null,
emit_bin_path,
emit_llvm_ir_path,
post_ir_path,
null,
)) {
defer llvm.disposeMessage(error_message);
log.err("LLVM failed to emit bin={s} ir={s}: {s}", .{
emit_bin_msg, emit_llvm_ir_msg, error_message,
emit_bin_msg, post_llvm_ir_msg, error_message,
});
return error.FailedToEmit;
}
emit_bin_path = null;
emit_llvm_ir_path = null;
post_ir_path = null;
}
if (self.target_machine.emitToFile(
self.builder.llvm.module.?,
&error_message,
comp.bin_file.options.optimize_mode == .Debug,
comp.bin_file.options.optimize_mode == .ReleaseSmall,
comp.time_report,
comp.bin_file.options.tsan,
comp.bin_file.options.lto,
emit_asm_path,
options.is_debug,
options.is_small,
options.time_report,
options.sanitize_thread,
options.lto,
options.asm_path,
emit_bin_path,
emit_llvm_ir_path,
emit_llvm_bc_path,
post_ir_path,
options.post_bc_path,
)) {
defer llvm.disposeMessage(error_message);
log.err("LLVM failed to emit asm={s} bin={s} ir={s} bc={s}: {s}", .{
emit_asm_msg, emit_bin_msg, emit_llvm_ir_msg, emit_llvm_bc_msg,
emit_asm_msg, emit_bin_msg, post_llvm_ir_msg, post_llvm_bc_msg,
error_message,
});
return error.FailedToEmit;
@ -1307,17 +1287,19 @@ pub const Object = struct {
pub fn updateFunc(
o: *Object,
mod: *Module,
zcu: *Module,
func_index: InternPool.Index,
air: Air,
liveness: Liveness,
) !void {
const func = mod.funcInfo(func_index);
const func = zcu.funcInfo(func_index);
const decl_index = func.owner_decl;
const decl = mod.declPtr(decl_index);
const fn_info = mod.typeToFunc(decl.ty).?;
const target = mod.getTarget();
const ip = &mod.intern_pool;
const decl = zcu.declPtr(decl_index);
const namespace = zcu.namespacePtr(decl.src_namespace);
const owner_mod = namespace.file_scope.mod;
const fn_info = zcu.typeToFunc(decl.ty).?;
const target = zcu.getTarget();
const ip = &zcu.intern_pool;
var dg: DeclGen = .{
.object = o,
@ -1352,7 +1334,7 @@ pub const Object = struct {
}
// TODO: disable this if safety is off for the function scope
const ssp_buf_size = mod.comp.bin_file.options.stack_protector;
const ssp_buf_size = owner_mod.stack_protector;
if (ssp_buf_size != 0) {
try attributes.addFnAttr(.sspstrong, &o.builder);
try attributes.addFnAttr(.{ .string = .{
@ -1362,7 +1344,7 @@ pub const Object = struct {
}
// TODO: disable this if safety is off for the function scope
if (mod.comp.bin_file.options.stack_check) {
if (owner_mod.stack_check) {
try attributes.addFnAttr(.{ .string = .{
.kind = try o.builder.string("probe-stack"),
.value = try o.builder.string("__zig_probe_stack"),
@ -1385,20 +1367,22 @@ pub const Object = struct {
var llvm_arg_i: u32 = 0;
// This gets the LLVM values from the function and stores them in `dg.args`.
const sret = firstParamSRet(fn_info, mod);
const sret = firstParamSRet(fn_info, zcu);
const ret_ptr: Builder.Value = if (sret) param: {
const param = wip.arg(llvm_arg_i);
llvm_arg_i += 1;
break :param param;
} else .none;
if (ccAbiPromoteInt(fn_info.cc, mod, Type.fromInterned(fn_info.return_type))) |s| switch (s) {
if (ccAbiPromoteInt(fn_info.cc, zcu, Type.fromInterned(fn_info.return_type))) |s| switch (s) {
.signed => try attributes.addRetAttr(.signext, &o.builder),
.unsigned => try attributes.addRetAttr(.zeroext, &o.builder),
};
const err_return_tracing = Type.fromInterned(fn_info.return_type).isError(mod) and
mod.comp.config.any_error_tracing;
const comp = zcu.comp;
const err_return_tracing = Type.fromInterned(fn_info.return_type).isError(zcu) and
comp.config.any_error_tracing;
const err_ret_trace: Builder.Value = if (err_return_tracing) param: {
const param = wip.arg(llvm_arg_i);
@ -1426,8 +1410,8 @@ pub const Object = struct {
const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[param_index]);
const param = wip.arg(llvm_arg_i);
if (isByRef(param_ty, mod)) {
const alignment = param_ty.abiAlignment(mod).toLlvm();
if (isByRef(param_ty, zcu)) {
const alignment = param_ty.abiAlignment(zcu).toLlvm();
const param_llvm_ty = param.typeOfWip(&wip);
const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
_ = try wip.store(.normal, param, arg_ptr, alignment);
@ -1443,12 +1427,12 @@ pub const Object = struct {
const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);
const param_llvm_ty = try o.lowerType(param_ty);
const param = wip.arg(llvm_arg_i);
const alignment = param_ty.abiAlignment(mod).toLlvm();
const alignment = param_ty.abiAlignment(zcu).toLlvm();
try o.addByRefParamAttrs(&attributes, llvm_arg_i, alignment, it.byval_attr, param_llvm_ty);
llvm_arg_i += 1;
if (isByRef(param_ty, mod)) {
if (isByRef(param_ty, zcu)) {
args.appendAssumeCapacity(param);
} else {
args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, param, alignment, ""));
@ -1458,12 +1442,12 @@ pub const Object = struct {
const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);
const param_llvm_ty = try o.lowerType(param_ty);
const param = wip.arg(llvm_arg_i);
const alignment = param_ty.abiAlignment(mod).toLlvm();
const alignment = param_ty.abiAlignment(zcu).toLlvm();
try attributes.addParamAttr(llvm_arg_i, .noundef, &o.builder);
llvm_arg_i += 1;
if (isByRef(param_ty, mod)) {
if (isByRef(param_ty, zcu)) {
args.appendAssumeCapacity(param);
} else {
args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, param, alignment, ""));
@ -1476,11 +1460,11 @@ pub const Object = struct {
llvm_arg_i += 1;
const param_llvm_ty = try o.lowerType(param_ty);
const alignment = param_ty.abiAlignment(mod).toLlvm();
const alignment = param_ty.abiAlignment(zcu).toLlvm();
const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
_ = try wip.store(.normal, param, arg_ptr, alignment);
args.appendAssumeCapacity(if (isByRef(param_ty, mod))
args.appendAssumeCapacity(if (isByRef(param_ty, zcu))
arg_ptr
else
try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, ""));
@ -1488,14 +1472,14 @@ pub const Object = struct {
.slice => {
assert(!it.byval_attr);
const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);
const ptr_info = param_ty.ptrInfo(mod);
const ptr_info = param_ty.ptrInfo(zcu);
if (math.cast(u5, it.zig_index - 1)) |i| {
if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) {
try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder);
}
}
if (param_ty.zigTypeTag(mod) != .Optional) {
if (param_ty.zigTypeTag(zcu) != .Optional) {
try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
}
if (ptr_info.flags.is_const) {
@ -1504,7 +1488,7 @@ pub const Object = struct {
const elem_align = (if (ptr_info.flags.alignment != .none)
@as(InternPool.Alignment, ptr_info.flags.alignment)
else
Type.fromInterned(ptr_info.child).abiAlignment(mod).max(.@"1")).toLlvm();
Type.fromInterned(ptr_info.child).abiAlignment(zcu).max(.@"1")).toLlvm();
try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
const ptr_param = wip.arg(llvm_arg_i);
llvm_arg_i += 1;
@ -1521,7 +1505,7 @@ pub const Object = struct {
const field_types = it.types_buffer[0..it.types_len];
const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);
const param_llvm_ty = try o.lowerType(param_ty);
const param_alignment = param_ty.abiAlignment(mod).toLlvm();
const param_alignment = param_ty.abiAlignment(zcu).toLlvm();
const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, param_alignment, target);
const llvm_ty = try o.builder.structType(.normal, field_types);
for (0..field_types.len) |field_i| {
@ -1533,7 +1517,7 @@ pub const Object = struct {
_ = try wip.store(.normal, param, field_ptr, alignment);
}
const is_by_ref = isByRef(param_ty, mod);
const is_by_ref = isByRef(param_ty, zcu);
args.appendAssumeCapacity(if (is_by_ref)
arg_ptr
else
@ -1551,11 +1535,11 @@ pub const Object = struct {
const param = wip.arg(llvm_arg_i);
llvm_arg_i += 1;
const alignment = param_ty.abiAlignment(mod).toLlvm();
const alignment = param_ty.abiAlignment(zcu).toLlvm();
const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
_ = try wip.store(.normal, param, arg_ptr, alignment);
args.appendAssumeCapacity(if (isByRef(param_ty, mod))
args.appendAssumeCapacity(if (isByRef(param_ty, zcu))
arg_ptr
else
try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, ""));
@ -1566,11 +1550,11 @@ pub const Object = struct {
const param = wip.arg(llvm_arg_i);
llvm_arg_i += 1;
const alignment = param_ty.abiAlignment(mod).toLlvm();
const alignment = param_ty.abiAlignment(zcu).toLlvm();
const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
_ = try wip.store(.normal, param, arg_ptr, alignment);
args.appendAssumeCapacity(if (isByRef(param_ty, mod))
args.appendAssumeCapacity(if (isByRef(param_ty, zcu))
arg_ptr
else
try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, ""));
@ -1584,14 +1568,12 @@ pub const Object = struct {
var di_file: ?if (build_options.have_llvm) *llvm.DIFile else noreturn = null;
var di_scope: ?if (build_options.have_llvm) *llvm.DIScope else noreturn = null;
const namespace = mod.namespacePtr(decl.src_namespace);
if (o.di_builder) |dib| {
di_file = try o.getDIFile(gpa, namespace.file_scope);
const line_number = decl.src_line + 1;
const is_internal_linkage = decl.val.getExternFunc(mod) == null and
!mod.decl_exports.contains(decl_index);
const is_internal_linkage = decl.val.getExternFunc(zcu) == null and
!zcu.decl_exports.contains(decl_index);
const noret_bit: c_uint = if (fn_info.return_type == .noreturn_type)
llvm.DIFlags.NoReturn
else
@ -1608,7 +1590,7 @@ pub const Object = struct {
true, // is definition
line_number + func.lbrace_line, // scope line
llvm.DIFlags.StaticMember | noret_bit,
mod.comp.bin_file.options.optimize_mode != .Debug,
owner_mod.optimize_mode != .Debug,
null, // decl_subprogram
);
try o.di_map.put(gpa, decl, subprogram.toNode());
@ -1618,8 +1600,6 @@ pub const Object = struct {
di_scope = subprogram.toScope();
}
const single_threaded = namespace.file_scope.mod.single_threaded;
var fg: FuncGen = .{
.gpa = gpa,
.air = air,
@ -1631,7 +1611,7 @@ pub const Object = struct {
.arg_index = 0,
.func_inst_table = .{},
.blocks = .{},
.sync_scope = if (single_threaded) .singlethread else .system,
.sync_scope = if (owner_mod.single_threaded) .singlethread else .system,
.di_scope = di_scope,
.di_file = di_file,
.base_line = dg.decl.src_line,
@ -1645,7 +1625,7 @@ pub const Object = struct {
fg.genBody(air.getMainBody()) catch |err| switch (err) {
error.CodegenFail => {
decl.analysis = .codegen_failure;
try mod.failed_decls.put(mod.gpa, decl_index, dg.err_msg.?);
try zcu.failed_decls.put(zcu.gpa, decl_index, dg.err_msg.?);
dg.err_msg = null;
return;
},
@ -1654,7 +1634,7 @@ pub const Object = struct {
try fg.wip.finish();
try o.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
try o.updateExports(zcu, .{ .decl_index = decl_index }, zcu.getDeclExports(decl_index));
}
pub fn updateDecl(self: *Object, module: *Module, decl_index: InternPool.DeclIndex) !void {
@ -2933,22 +2913,24 @@ pub const Object = struct {
o: *Object,
decl_index: InternPool.DeclIndex,
) Allocator.Error!Builder.Function.Index {
const mod = o.module;
const ip = &mod.intern_pool;
const zcu = o.module;
const ip = &zcu.intern_pool;
const gpa = o.gpa;
const decl = mod.declPtr(decl_index);
const decl = zcu.declPtr(decl_index);
const namespace = zcu.namespacePtr(decl.src_namespace);
const owner_mod = namespace.file_scope.mod;
const zig_fn_type = decl.ty;
const gop = try o.decl_map.getOrPut(gpa, decl_index);
if (gop.found_existing) return gop.value_ptr.ptr(&o.builder).kind.function;
assert(decl.has_tv);
const fn_info = mod.typeToFunc(zig_fn_type).?;
const target = mod.getTarget();
const sret = firstParamSRet(fn_info, mod);
const fn_info = zcu.typeToFunc(zig_fn_type).?;
const target = owner_mod.resolved_target.result;
const sret = firstParamSRet(fn_info, zcu);
const function_index = try o.builder.addFunction(
try o.lowerType(zig_fn_type),
try o.builder.string(ip.stringToSlice(try decl.getFullyQualifiedName(mod))),
try o.builder.string(ip.stringToSlice(try decl.getFullyQualifiedName(zcu))),
toLlvmAddressSpace(decl.@"addrspace", target),
);
gop.value_ptr.* = function_index.ptrConst(&o.builder).global;
@ -2956,7 +2938,7 @@ pub const Object = struct {
var attributes: Builder.FunctionAttributes.Wip = .{};
defer attributes.deinit(&o.builder);
const is_extern = decl.isExtern(mod);
const is_extern = decl.isExtern(zcu);
if (!is_extern) {
function_index.setLinkage(.internal, &o.builder);
function_index.setUnnamedAddr(.unnamed_addr, &o.builder);
@ -2966,7 +2948,7 @@ pub const Object = struct {
.kind = try o.builder.string("wasm-import-name"),
.value = try o.builder.string(ip.stringToSlice(decl.name)),
} }, &o.builder);
if (ip.stringToSliceUnwrap(decl.getOwnedExternFunc(mod).?.lib_name)) |lib_name| {
if (ip.stringToSliceUnwrap(decl.getOwnedExternFunc(zcu).?.lib_name)) |lib_name| {
if (!std.mem.eql(u8, lib_name, "c")) try attributes.addFnAttr(.{ .string = .{
.kind = try o.builder.string("wasm-import-module"),
.value = try o.builder.string(lib_name),
@ -2987,8 +2969,8 @@ pub const Object = struct {
llvm_arg_i += 1;
}
const err_return_tracing = Type.fromInterned(fn_info.return_type).isError(mod) and
mod.comp.config.any_error_tracing;
const err_return_tracing = Type.fromInterned(fn_info.return_type).isError(zcu) and
zcu.comp.config.any_error_tracing;
if (err_return_tracing) {
try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
@ -3009,7 +2991,7 @@ pub const Object = struct {
function_index.setAlignment(fn_info.alignment.toLlvm(), &o.builder);
// Function attributes that are independent of analysis results of the function body.
try o.addCommonFnAttributes(&attributes);
try o.addCommonFnAttributes(&attributes, owner_mod);
if (fn_info.return_type == .noreturn_type) try attributes.addFnAttr(.noreturn, &o.builder);
@ -3022,14 +3004,14 @@ pub const Object = struct {
.byval => {
const param_index = it.zig_index - 1;
const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[param_index]);
if (!isByRef(param_ty, mod)) {
if (!isByRef(param_ty, zcu)) {
try o.addByValParamAttrs(&attributes, param_ty, param_index, fn_info, it.llvm_index - 1);
}
},
.byref => {
const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);
const param_llvm_ty = try o.lowerType(param_ty);
const alignment = param_ty.abiAlignment(mod);
const alignment = param_ty.abiAlignment(zcu);
try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment.toLlvm(), it.byval_attr, param_llvm_ty);
},
.byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder),
@ -3055,13 +3037,14 @@ pub const Object = struct {
fn addCommonFnAttributes(
o: *Object,
attributes: *Builder.FunctionAttributes.Wip,
owner_mod: *Package.Module,
) Allocator.Error!void {
const comp = o.module.comp;
if (!comp.bin_file.options.red_zone) {
if (!owner_mod.red_zone) {
try attributes.addFnAttr(.noredzone, &o.builder);
}
if (comp.bin_file.options.omit_frame_pointer) {
if (owner_mod.omit_frame_pointer) {
try attributes.addFnAttr(.{ .string = .{
.kind = try o.builder.string("frame-pointer"),
.value = try o.builder.string("none"),
@ -3073,7 +3056,7 @@ pub const Object = struct {
} }, &o.builder);
}
try attributes.addFnAttr(.nounwind, &o.builder);
if (comp.unwind_tables) {
if (owner_mod.unwind_tables) {
try attributes.addFnAttr(.{ .uwtable = Builder.Attribute.UwTable.default }, &o.builder);
}
if (comp.skip_linker_dependencies or comp.no_builtin) {
@ -3084,26 +3067,27 @@ pub const Object = struct {
// overflow instead of performing memcpy.
try attributes.addFnAttr(.nobuiltin, &o.builder);
}
if (comp.bin_file.options.optimize_mode == .ReleaseSmall) {
if (owner_mod.optimize_mode == .ReleaseSmall) {
try attributes.addFnAttr(.minsize, &o.builder);
try attributes.addFnAttr(.optsize, &o.builder);
}
if (comp.bin_file.options.tsan) {
if (owner_mod.sanitize_thread) {
try attributes.addFnAttr(.sanitize_thread, &o.builder);
}
if (comp.getTarget().cpu.model.llvm_name) |s| {
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"),
.value = try o.builder.string(s),
} }, &o.builder);
}
if (comp.bin_file.options.llvm_cpu_features) |s| {
if (owner_mod.resolved_target.llvm_cpu_features) |s| {
try attributes.addFnAttr(.{ .string = .{
.kind = try o.builder.string("target-features"),
.value = try o.builder.string(std.mem.span(s)),
} }, &o.builder);
}
if (comp.getTarget().cpu.arch.isBpf()) {
if (target.cpu.arch.isBpf()) {
try attributes.addFnAttr(.{ .string = .{
.kind = try o.builder.string("no-builtins"),
.value = .empty,
@ -4646,6 +4630,100 @@ pub const Object = struct {
.field_index = @intCast(field_index),
});
}
fn getCmpLtErrorsLenFunction(o: *Object) !Builder.Function.Index {
const name = try o.builder.string(lt_errors_fn_name);
if (o.builder.getGlobal(name)) |llvm_fn| return llvm_fn.ptrConst(&o.builder).kind.function;
const zcu = o.module;
const target = zcu.root_mod.resolved_target.result;
const function_index = try o.builder.addFunction(
try o.builder.fnType(.i1, &.{try o.errorIntType()}, .normal),
name,
toLlvmAddressSpace(.generic, target),
);
var attributes: Builder.FunctionAttributes.Wip = .{};
defer attributes.deinit(&o.builder);
try o.addCommonFnAttributes(&attributes, zcu.root_mod);
function_index.setLinkage(.internal, &o.builder);
function_index.setCallConv(.fastcc, &o.builder);
function_index.setAttributes(try attributes.finish(&o.builder), &o.builder);
return function_index;
}
fn getEnumTagNameFunction(o: *Object, enum_ty: Type) !Builder.Function.Index {
const zcu = o.module;
const ip = &zcu.intern_pool;
const enum_type = ip.indexToKey(enum_ty.toIntern()).enum_type;
// TODO: detect when the type changes and re-emit this function.
const gop = try o.decl_map.getOrPut(o.gpa, enum_type.decl);
if (gop.found_existing) return gop.value_ptr.ptrConst(&o.builder).kind.function;
errdefer assert(o.decl_map.remove(enum_type.decl));
const usize_ty = try o.lowerType(Type.usize);
const ret_ty = try o.lowerType(Type.slice_const_u8_sentinel_0);
const fqn = try zcu.declPtr(enum_type.decl).getFullyQualifiedName(zcu);
const target = zcu.root_mod.resolved_target.result;
const function_index = try o.builder.addFunction(
try o.builder.fnType(ret_ty, &.{try o.lowerType(Type.fromInterned(enum_type.tag_ty))}, .normal),
try o.builder.fmt("__zig_tag_name_{}", .{fqn.fmt(ip)}),
toLlvmAddressSpace(.generic, target),
);
var attributes: Builder.FunctionAttributes.Wip = .{};
defer attributes.deinit(&o.builder);
try o.addCommonFnAttributes(&attributes, zcu.root_mod);
function_index.setLinkage(.internal, &o.builder);
function_index.setCallConv(.fastcc, &o.builder);
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);
defer wip.deinit();
wip.cursor = .{ .block = try wip.block(0, "Entry") };
const bad_value_block = try wip.block(1, "BadValue");
const tag_int_value = wip.arg(0);
var wip_switch =
try wip.@"switch"(tag_int_value, bad_value_block, @intCast(enum_type.names.len));
defer wip_switch.finish(&wip);
for (0..enum_type.names.len) |field_index| {
const name = try o.builder.string(ip.stringToSlice(enum_type.names.get(ip)[field_index]));
const name_init = try o.builder.stringNullConst(name);
const name_variable_index =
try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default);
try name_variable_index.setInitializer(name_init, &o.builder);
name_variable_index.setLinkage(.private, &o.builder);
name_variable_index.setMutability(.constant, &o.builder);
name_variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
name_variable_index.setAlignment(comptime Builder.Alignment.fromByteUnits(1), &o.builder);
const name_val = try o.builder.structValue(ret_ty, &.{
name_variable_index.toConst(&o.builder),
try o.builder.intConst(usize_ty, name.slice(&o.builder).?.len),
});
const return_block = try wip.block(1, "Name");
const this_tag_int_value = try o.lowerValue(
(try zcu.enumValueFieldIndex(enum_ty, @intCast(field_index))).toIntern(),
);
try wip_switch.addCase(this_tag_int_value, return_block, &wip);
wip.cursor = .{ .block = return_block };
_ = try wip.ret(name_val);
}
wip.cursor = .{ .block = bad_value_block };
_ = try wip.@"unreachable"();
try wip.finish();
return function_index;
}
};
pub const DeclGen = struct {
@ -4654,6 +4732,13 @@ pub const DeclGen = struct {
decl_index: InternPool.DeclIndex,
err_msg: ?*Module.ErrorMsg,
fn ownerModule(dg: DeclGen) *Package.Module {
const o = dg.object;
const zcu = o.module;
const namespace = zcu.namespacePtr(dg.decl.src_namespace);
return namespace.file_scope.mod;
}
fn todo(dg: *DeclGen, comptime format: []const u8, args: anytype) Error {
@setCold(true);
assert(dg.err_msg == null);
@ -5614,7 +5699,7 @@ pub const FuncGen = struct {
const o = self.dg.object;
const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const operand = try self.resolveInst(un_op);
const llvm_fn = try self.getCmpLtErrorsLenFunction();
const llvm_fn = try o.getCmpLtErrorsLenFunction();
return self.wip.call(
.normal,
.fastcc,
@ -6547,11 +6632,13 @@ pub const FuncGen = struct {
const dib = o.di_builder orelse return .none;
const ty_fn = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn;
const mod = o.module;
const func = mod.funcInfo(ty_fn.func);
const zcu = o.module;
const func = zcu.funcInfo(ty_fn.func);
const decl_index = func.owner_decl;
const decl = mod.declPtr(decl_index);
const di_file = try o.getDIFile(self.gpa, mod.namespacePtr(decl.src_namespace).file_scope);
const decl = zcu.declPtr(decl_index);
const namespace = zcu.namespacePtr(decl.src_namespace);
const owner_mod = namespace.file_scope.mod;
const di_file = try o.getDIFile(self.gpa, zcu.namespacePtr(decl.src_namespace).file_scope);
self.di_file = di_file;
const line_number = decl.src_line + 1;
const cur_debug_location = self.wip.llvm.builder.getCurrentDebugLocation2();
@ -6562,18 +6649,18 @@ pub const FuncGen = struct {
.base_line = self.base_line,
});
const fqn = try decl.getFullyQualifiedName(mod);
const fqn = try decl.getFullyQualifiedName(zcu);
const is_internal_linkage = !mod.decl_exports.contains(decl_index);
const fn_ty = try mod.funcType(.{
const is_internal_linkage = !zcu.decl_exports.contains(decl_index);
const fn_ty = try zcu.funcType(.{
.param_types = &.{},
.return_type = .void_type,
});
const fn_di_ty = try o.lowerDebugType(fn_ty, .full);
const subprogram = dib.createFunction(
di_file.toScope(),
mod.intern_pool.stringToSlice(decl.name),
mod.intern_pool.stringToSlice(fqn),
zcu.intern_pool.stringToSlice(decl.name),
zcu.intern_pool.stringToSlice(fqn),
di_file,
line_number,
fn_di_ty,
@ -6581,7 +6668,7 @@ pub const FuncGen = struct {
true, // is definition
line_number + func.lbrace_line, // scope line
llvm.DIFlags.StaticMember,
mod.comp.bin_file.options.optimize_mode != .Debug,
owner_mod.optimize_mode != .Debug,
null, // decl_subprogram
);
@ -6676,11 +6763,12 @@ pub const FuncGen = struct {
null;
const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?, inlined_at);
const insert_block = self.wip.cursor.block.toLlvm(&self.wip);
const mod = o.module;
if (isByRef(operand_ty, mod)) {
const zcu = o.module;
const owner_mod = self.dg.ownerModule();
if (isByRef(operand_ty, zcu)) {
_ = dib.insertDeclareAtEnd(operand.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
} else if (o.module.comp.bin_file.options.optimize_mode == .Debug) {
const alignment = operand_ty.abiAlignment(mod).toLlvm();
} else if (owner_mod.optimize_mode == .Debug) {
const alignment = operand_ty.abiAlignment(zcu).toLlvm();
const alloca = try self.buildAlloca(operand.typeOfWip(&self.wip), alignment);
_ = try self.wip.store(.normal, operand, alloca, alignment);
_ = dib.insertDeclareAtEnd(alloca.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
@ -8729,9 +8817,10 @@ pub const FuncGen = struct {
const debug_loc = llvm.getDebugLoc(lbrace_line, lbrace_col, self.di_scope.?, null);
const insert_block = self.wip.cursor.block.toLlvm(&self.wip);
const owner_mod = self.dg.ownerModule();
if (isByRef(inst_ty, mod)) {
_ = dib.insertDeclareAtEnd(arg_val.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
} else if (o.module.comp.bin_file.options.optimize_mode == .Debug) {
} else if (owner_mod.optimize_mode == .Debug) {
const alignment = inst_ty.abiAlignment(mod).toLlvm();
const alloca = try self.buildAlloca(arg_val.typeOfWip(&self.wip), alignment);
_ = try self.wip.store(.normal, arg_val, alloca, alignment);
@ -8821,7 +8910,8 @@ pub const FuncGen = struct {
len,
if (ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal,
);
if (safety and mod.comp.bin_file.options.valgrind) {
const owner_mod = self.dg.ownerModule();
if (safety and owner_mod.valgrind) {
try self.valgrindMarkUndef(dest_ptr, len);
}
return .none;
@ -9137,7 +9227,8 @@ pub const FuncGen = struct {
} else {
_ = try self.wip.callMemSet(dest_ptr, dest_ptr_align, fill_byte, len, access_kind);
}
if (safety and mod.comp.bin_file.options.valgrind) {
const owner_mod = self.dg.ownerModule();
if (safety and owner_mod.valgrind) {
try self.valgrindMarkUndef(dest_ptr, len);
}
return .none;
@ -9488,24 +9579,25 @@ pub const FuncGen = struct {
fn getIsNamedEnumValueFunction(self: *FuncGen, enum_ty: Type) !Builder.Function.Index {
const o = self.dg.object;
const mod = o.module;
const enum_type = mod.intern_pool.indexToKey(enum_ty.toIntern()).enum_type;
const zcu = o.module;
const enum_type = zcu.intern_pool.indexToKey(enum_ty.toIntern()).enum_type;
// TODO: detect when the type changes and re-emit this function.
const gop = try o.named_enum_map.getOrPut(o.gpa, enum_type.decl);
if (gop.found_existing) return gop.value_ptr.*;
errdefer assert(o.named_enum_map.remove(enum_type.decl));
const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod);
const fqn = try zcu.declPtr(enum_type.decl).getFullyQualifiedName(zcu);
const target = zcu.root_mod.resolved_target.result;
const function_index = try o.builder.addFunction(
try o.builder.fnType(.i1, &.{try o.lowerType(Type.fromInterned(enum_type.tag_ty))}, .normal),
try o.builder.fmt("__zig_is_named_enum_value_{}", .{fqn.fmt(&mod.intern_pool)}),
toLlvmAddressSpace(.generic, mod.getTarget()),
try o.builder.fmt("__zig_is_named_enum_value_{}", .{fqn.fmt(&zcu.intern_pool)}),
toLlvmAddressSpace(.generic, target),
);
var attributes: Builder.FunctionAttributes.Wip = .{};
defer attributes.deinit(&o.builder);
try o.addCommonFnAttributes(&attributes);
try o.addCommonFnAttributes(&attributes, zcu.root_mod);
function_index.setLinkage(.internal, &o.builder);
function_index.setCallConv(.fastcc, &o.builder);
@ -9524,7 +9616,7 @@ pub const FuncGen = struct {
for (0..enum_type.names.len) |field_index| {
const this_tag_int_value = try o.lowerValue(
(try mod.enumValueFieldIndex(enum_ty, @intCast(field_index))).toIntern(),
(try zcu.enumValueFieldIndex(enum_ty, @intCast(field_index))).toIntern(),
);
try wip_switch.addCase(this_tag_int_value, named_block, &wip);
}
@ -9544,7 +9636,7 @@ pub const FuncGen = struct {
const operand = try self.resolveInst(un_op);
const enum_ty = self.typeOf(un_op);
const llvm_fn = try self.getEnumTagNameFunction(enum_ty);
const llvm_fn = try o.getEnumTagNameFunction(enum_ty);
return self.wip.call(
.normal,
.fastcc,
@ -9556,100 +9648,6 @@ pub const FuncGen = struct {
);
}
fn getEnumTagNameFunction(self: *FuncGen, enum_ty: Type) !Builder.Function.Index {
const o = self.dg.object;
const mod = o.module;
const ip = &mod.intern_pool;
const enum_type = ip.indexToKey(enum_ty.toIntern()).enum_type;
// TODO: detect when the type changes and re-emit this function.
const gop = try o.decl_map.getOrPut(o.gpa, enum_type.decl);
if (gop.found_existing) return gop.value_ptr.ptrConst(&o.builder).kind.function;
errdefer assert(o.decl_map.remove(enum_type.decl));
const usize_ty = try o.lowerType(Type.usize);
const ret_ty = try o.lowerType(Type.slice_const_u8_sentinel_0);
const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod);
const function_index = try o.builder.addFunction(
try o.builder.fnType(ret_ty, &.{try o.lowerType(Type.fromInterned(enum_type.tag_ty))}, .normal),
try o.builder.fmt("__zig_tag_name_{}", .{fqn.fmt(ip)}),
toLlvmAddressSpace(.generic, mod.getTarget()),
);
var attributes: Builder.FunctionAttributes.Wip = .{};
defer attributes.deinit(&o.builder);
try o.addCommonFnAttributes(&attributes);
function_index.setLinkage(.internal, &o.builder);
function_index.setCallConv(.fastcc, &o.builder);
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);
defer wip.deinit();
wip.cursor = .{ .block = try wip.block(0, "Entry") };
const bad_value_block = try wip.block(1, "BadValue");
const tag_int_value = wip.arg(0);
var wip_switch =
try wip.@"switch"(tag_int_value, bad_value_block, @intCast(enum_type.names.len));
defer wip_switch.finish(&wip);
for (0..enum_type.names.len) |field_index| {
const name = try o.builder.string(ip.stringToSlice(enum_type.names.get(ip)[field_index]));
const name_init = try o.builder.stringNullConst(name);
const name_variable_index =
try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default);
try name_variable_index.setInitializer(name_init, &o.builder);
name_variable_index.setLinkage(.private, &o.builder);
name_variable_index.setMutability(.constant, &o.builder);
name_variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
name_variable_index.setAlignment(comptime Builder.Alignment.fromByteUnits(1), &o.builder);
const name_val = try o.builder.structValue(ret_ty, &.{
name_variable_index.toConst(&o.builder),
try o.builder.intConst(usize_ty, name.slice(&o.builder).?.len),
});
const return_block = try wip.block(1, "Name");
const this_tag_int_value = try o.lowerValue(
(try mod.enumValueFieldIndex(enum_ty, @intCast(field_index))).toIntern(),
);
try wip_switch.addCase(this_tag_int_value, return_block, &wip);
wip.cursor = .{ .block = return_block };
_ = try wip.ret(name_val);
}
wip.cursor = .{ .block = bad_value_block };
_ = try wip.@"unreachable"();
try wip.finish();
return function_index;
}
fn getCmpLtErrorsLenFunction(self: *FuncGen) !Builder.Function.Index {
const o = self.dg.object;
const name = try o.builder.string(lt_errors_fn_name);
if (o.builder.getGlobal(name)) |llvm_fn| return llvm_fn.ptrConst(&o.builder).kind.function;
const function_index = try o.builder.addFunction(
try o.builder.fnType(.i1, &.{try o.errorIntType()}, .normal),
name,
toLlvmAddressSpace(.generic, o.module.getTarget()),
);
var attributes: Builder.FunctionAttributes.Wip = .{};
defer attributes.deinit(&o.builder);
try o.addCommonFnAttributes(&attributes);
function_index.setLinkage(.internal, &o.builder);
function_index.setCallConv(.fastcc, &o.builder);
function_index.setAttributes(try attributes.finish(&o.builder), &o.builder);
return function_index;
}
fn airErrorName(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
const o = self.dg.object;
const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;

View File

@ -18,6 +18,7 @@ const Module = @import("Module.zig");
const InternPool = @import("InternPool.zig");
const Type = @import("type.zig").Type;
const TypedValue = @import("TypedValue.zig");
const LlvmObject = @import("codegen/llvm.zig").Object;
/// When adding a new field, remember to update `hashAddSystemLibs`.
/// These are *always* dynamically linked. Static libraries will be
@ -1046,6 +1047,51 @@ pub const File = struct {
return output_mode == .Lib and !self.isStatic();
}
pub fn resolveEmitLoc(
base: File,
arena: Allocator,
opt_loc: ?Compilation.EmitLoc,
) Allocator.Error!?[*:0]u8 {
const loc = opt_loc orelse return null;
const slice = if (loc.directory) |directory|
try directory.joinZ(arena, &.{loc.basename})
else
try base.emit.basenamePath(arena, loc.basename);
return slice.ptr;
}
pub fn emitLlvmObject(
base: File,
arena: Allocator,
llvm_object: *LlvmObject,
prog_node: *std.Progress.Node,
) !void {
const comp = base.comp;
var sub_prog_node = prog_node.start("LLVM Emit Object", 0);
sub_prog_node.activate();
sub_prog_node.context.refresh();
defer sub_prog_node.end();
try llvm_object.emit(comp, .{
.pre_ir_path = comp.verbose_llvm_ir,
.pre_bc_path = comp.verbose_llvm_bc,
.bin_path = try base.resolveEmitLoc(arena, .{
.directory = null,
.basename = base.intermediary_basename.?,
}),
.asm_path = try base.resolveEmitLoc(arena, comp.emit_asm),
.post_llvm_ir_path = try base.resolveEmitLoc(arena, comp.emit_llvm_ir),
.post_llvm_bc_path = try base.resolveEmitLoc(arena, comp.emit_llvm_bc),
.is_debug = comp.root_mod.optimize_mode == .Debug,
.is_small = comp.root_mod.optimize_mode == .ReleaseSmall,
.time_report = comp.time_report,
.sanitize_thread = comp.config.any_sanitize_thread,
.lto = comp.config.lto,
});
}
pub const C = @import("link/C.zig");
pub const Coff = @import("link/Coff.zig");
pub const Plan9 = @import("link/Plan9.zig");

View File

@ -3,7 +3,7 @@
//! LLD for traditional linking (linking relocatable object files).
//! LLD is also the default linker for LLVM.
/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
/// If this is not null, an object file is created by LLVM and emitted to intermediary_basename.
llvm_object: ?*LlvmObject = null,
base: link.File,
@ -1711,17 +1711,22 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
const tracy = trace(@src());
defer tracy.end();
const gpa = comp.gpa;
if (self.llvm_object) |llvm_object| {
return try llvm_object.flushModule(comp, prog_node);
var arena_allocator = std.heap.ArenaAllocator.init(gpa);
defer arena_allocator.deinit();
const arena = arena_allocator.allocator();
try self.base.emitLlvmObject(arena, llvm_object, prog_node);
return;
}
var sub_prog_node = prog_node.start("COFF Flush", 0);
sub_prog_node.activate();
defer sub_prog_node.end();
const gpa = self.base.comp.gpa;
const module = self.base.comp.module orelse return error.LinkingWithoutZigSourceUnimplemented;
const module = comp.module orelse return error.LinkingWithoutZigSourceUnimplemented;
if (self.lazy_syms.getPtr(.none)) |metadata| {
// Most lazy symbols can be updated on first use, but
@ -1822,7 +1827,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
try self.writeDataDirectoriesHeaders();
try self.writeSectionHeaders();
if (self.entry_addr == null and self.base.comp.config.output_mode == .Exe) {
if (self.entry_addr == null and comp.config.output_mode == .Exe) {
log.debug("flushing. no_entry_point_found = true\n", .{});
self.base.error_flags.no_entry_point_found = true;
} else {

View File

@ -27,7 +27,7 @@ version_script: ?[]const u8,
ptr_width: PtrWidth,
/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
/// If this is not null, an object file is created by LLVM and emitted to intermediary_basename.
llvm_object: ?*LlvmObject = null,
/// A list of all input files.
@ -1031,24 +1031,23 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
const tracy = trace(@src());
defer tracy.end();
if (self.llvm_object) |llvm_object| {
try llvm_object.flushModule(comp, prog_node);
const use_lld = build_options.have_llvm and self.base.comp.config.use_lld;
if (use_lld) return;
}
const gpa = self.base.comp.gpa;
var sub_prog_node = prog_node.start("ELF Flush", 0);
sub_prog_node.activate();
defer sub_prog_node.end();
const gpa = comp.gpa;
var arena_allocator = std.heap.ArenaAllocator.init(gpa);
defer arena_allocator.deinit();
const arena = arena_allocator.allocator();
const target = self.base.comp.root_mod.resolved_target.result;
const link_mode = self.base.comp.config.link_mode;
if (self.llvm_object) |llvm_object| {
try self.base.emitLlvmObject(arena, llvm_object, prog_node);
const use_lld = build_options.have_llvm and comp.config.use_lld;
if (use_lld) return;
}
var sub_prog_node = prog_node.start("ELF Flush", 0);
sub_prog_node.activate();
defer sub_prog_node.end();
const target = comp.root_mod.resolved_target.result;
const link_mode = comp.config.link_mode;
const directory = self.base.emit.directory; // Just an alias to make it shorter to type.
const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
const module_obj_path: ?[]const u8 = if (self.base.intermediary_basename) |path| blk: {
@ -1060,7 +1059,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
} else null;
// --verbose-link
if (self.base.comp.verbose_link) try self.dumpArgv(comp);
if (comp.verbose_link) try self.dumpArgv(comp);
const csu = try CsuObjects.init(arena, comp);
const compiler_rt_path: ?[]const u8 = blk: {
@ -1082,8 +1081,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
if (csu.crti) |v| try positionals.append(.{ .path = v });
if (csu.crtbegin) |v| try positionals.append(.{ .path = v });
try positionals.ensureUnusedCapacity(self.base.comp.objects.len);
positionals.appendSliceAssumeCapacity(self.base.comp.objects);
try positionals.ensureUnusedCapacity(comp.objects.len);
positionals.appendSliceAssumeCapacity(comp.objects);
// This is a set of object files emitted by clang in a single `build-exe` invocation.
// For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up
@ -1106,13 +1105,13 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
var test_path = std.ArrayList(u8).init(gpa);
defer test_path.deinit();
for (self.lib_dirs) |lib_dir_path| {
for (self.base.comp.system_libs.keys()) |link_lib| {
for (comp.system_libs.keys()) |link_lib| {
if (!(try self.accessLibPath(&test_path, null, lib_dir_path, link_lib, .Dynamic)))
continue;
_ = try rpath_table.put(lib_dir_path, {});
}
}
for (self.base.comp.objects) |obj| {
for (comp.objects) |obj| {
if (Compilation.classifyFileExt(obj.path) == .shared_library) {
const lib_dir_path = std.fs.path.dirname(obj.path) orelse continue;
if (obj.loption) continue;
@ -1122,7 +1121,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
}
// TSAN
if (self.base.comp.config.any_sanitize_thread) {
if (comp.config.any_sanitize_thread) {
try positionals.append(.{ .path = comp.tsan_static_lib.?.full_object_path });
}
@ -1146,27 +1145,27 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
var system_libs = std.ArrayList(SystemLib).init(arena);
try system_libs.ensureUnusedCapacity(self.base.comp.system_libs.values().len);
for (self.base.comp.system_libs.values()) |lib_info| {
try system_libs.ensureUnusedCapacity(comp.system_libs.values().len);
for (comp.system_libs.values()) |lib_info| {
system_libs.appendAssumeCapacity(.{ .needed = lib_info.needed, .path = lib_info.path.? });
}
// libc++ dep
if (self.base.comp.config.link_libcpp) {
if (comp.config.link_libcpp) {
try system_libs.ensureUnusedCapacity(2);
system_libs.appendAssumeCapacity(.{ .path = comp.libcxxabi_static_lib.?.full_object_path });
system_libs.appendAssumeCapacity(.{ .path = comp.libcxx_static_lib.?.full_object_path });
}
// libunwind dep
if (self.base.comp.config.link_libunwind) {
if (comp.config.link_libunwind) {
try system_libs.append(.{ .path = comp.libunwind_static_lib.?.full_object_path });
}
// libc dep
self.base.error_flags.missing_libc = false;
if (self.base.comp.config.link_libc) {
if (self.base.comp.libc_installation) |lc| {
if (comp.config.link_libc) {
if (comp.libc_installation) |lc| {
const flags = target_util.libcFullLinkFlags(target);
try system_libs.ensureUnusedCapacity(flags.len);
@ -1305,7 +1304,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
// Look for entry address in objects if not set by the incremental compiler.
if (self.entry_index == null) {
const entry: ?[]const u8 = entry: {
if (self.base.comp.config.entry) |entry| break :entry entry;
if (comp.config.entry) |entry| break :entry entry;
if (!self.base.isDynLib()) break :entry "_start";
break :entry null;
};

View File

@ -43,7 +43,7 @@ pub fn outputShndx(symbol: Symbol) ?u16 {
}
pub fn isLocal(symbol: Symbol, elf_file: *Elf) bool {
if (elf_file.isRelocatable()) return symbol.elfSym(elf_file).st_bind() == elf.STB_LOCAL;
if (elf_file.base.isRelocatable()) return symbol.elfSym(elf_file).st_bind() == elf.STB_LOCAL;
return !(symbol.flags.import or symbol.flags.@"export");
}
@ -186,7 +186,7 @@ const GetOrCreateZigGotEntryResult = struct {
};
pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, elf_file: *Elf) !GetOrCreateZigGotEntryResult {
assert(!elf_file.isRelocatable());
assert(!elf_file.base.isRelocatable());
assert(symbol.flags.needs_zig_got);
if (symbol.flags.has_zig_got) return .{ .found_existing = true, .index = symbol.extra(elf_file).?.zig_got };
const index = try elf_file.zig_got.addSymbol(symbol_index, elf_file);
@ -237,7 +237,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
const st_shndx = blk: {
if (symbol.flags.has_copy_rel) break :blk elf_file.copy_rel_section_index.?;
if (file_ptr == .shared_object or esym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF;
if (elf_file.isRelocatable() and esym.st_shndx == elf.SHN_COMMON) break :blk elf.SHN_COMMON;
if (elf_file.base.isRelocatable() and esym.st_shndx == elf.SHN_COMMON) break :blk elf.SHN_COMMON;
if (symbol.atom(elf_file) == null and file_ptr != .linker_defined) break :blk elf.SHN_ABS;
break :blk symbol.outputShndx() orelse elf.SHN_UNDEF;
};

View File

@ -926,7 +926,7 @@ fn updateDeclCode(
sym.value = atom_ptr.value;
esym.st_value = atom_ptr.value;
if (!elf_file.isRelocatable()) {
if (!elf_file.base.isRelocatable()) {
log.debug(" (writing new offset table entry)", .{});
assert(sym.flags.has_zig_got);
const extra = sym.extra(elf_file).?;
@ -944,7 +944,7 @@ fn updateDeclCode(
sym.flags.needs_zig_got = true;
esym.st_value = atom_ptr.value;
if (!elf_file.isRelocatable()) {
if (!elf_file.base.isRelocatable()) {
const gop = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
try elf_file.zig_got.writeOne(elf_file, gop.index);
}
@ -1262,7 +1262,7 @@ fn updateLazySymbol(
local_sym.flags.needs_zig_got = true;
local_esym.st_value = atom_ptr.value;
if (!elf_file.isRelocatable()) {
if (!elf_file.base.isRelocatable()) {
const gop = try local_sym.getOrCreateZigGotEntry(symbol_index, elf_file);
try elf_file.zig_got.writeOne(elf_file, gop.index);
}

View File

@ -1,6 +1,6 @@
base: File,
/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
/// If this is not null, an object file is created by LLVM and emitted to intermediary_basename.
llvm_object: ?*LlvmObject = null,
/// Debug symbols bundle (or dSym).
@ -352,22 +352,23 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
const tracy = trace(@src());
defer tracy.end();
if (self.llvm_object) |llvm_object| {
return try llvm_object.flushModule(comp, prog_node);
}
const gpa = self.base.comp.gpa;
const gpa = comp.gpa;
var arena_allocator = std.heap.ArenaAllocator.init(gpa);
defer arena_allocator.deinit();
const arena = arena_allocator.allocator();
if (self.llvm_object) |llvm_object| {
try self.base.emitLlvmObject(arena, llvm_object, prog_node);
return;
}
var sub_prog_node = prog_node.start("MachO Flush", 0);
sub_prog_node.activate();
defer sub_prog_node.end();
const output_mode = self.base.comp.config.output_mode;
const module = self.base.comp.module orelse return error.LinkingWithoutZigSourceUnimplemented;
const target = self.base.comp.root_mod.resolved_target.result;
const output_mode = comp.config.output_mode;
const module = comp.module orelse return error.LinkingWithoutZigSourceUnimplemented;
const target = comp.root_mod.resolved_target.result;
if (self.lazy_syms.getPtr(.none)) |metadata| {
// Most lazy symbols can be updated on first use, but
@ -619,7 +620,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
.stacksize = self.base.stack_size,
});
},
.Lib => if (self.base.comp.config.link_mode == .Dynamic) {
.Lib => if (comp.config.link_mode == .Dynamic) {
try load_commands.writeDylibIdLC(self, lc_writer);
},
else => {},

View File

@ -3700,8 +3700,15 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
const tracy = trace(@src());
defer tracy.end();
const gpa = comp.gpa;
// Used for all temporary memory allocated during flushin
var arena_instance = std.heap.ArenaAllocator.init(gpa);
defer arena_instance.deinit();
const arena = arena_instance.allocator();
if (wasm.llvm_object) |llvm_object| {
return try llvm_object.flushModule(comp, prog_node);
try wasm.base.emitLlvmObject(arena, llvm_object, prog_node);
return;
}
var sub_prog_node = prog_node.start("Wasm Flush", 0);
@ -3711,13 +3718,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
// ensure the error names table is populated when an error name is referenced
try wasm.populateErrorNameTable();
// Used for all temporary memory allocated during flushin
const gpa = wasm.base.comp.gpa;
var arena_instance = std.heap.ArenaAllocator.init(gpa);
defer arena_instance.deinit();
const arena = arena_instance.allocator();
const objects = wasm.base.comp.objects;
const objects = comp.objects;
// Positional arguments to the linker such as object files and static archives.
var positionals = std.ArrayList([]const u8).init(arena);
@ -3755,7 +3756,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
try wasm.markReferences();
try wasm.setupErrorsLen();
try wasm.setupImports();
if (wasm.base.comp.module) |mod| {
if (comp.module) |mod| {
var decl_it = wasm.decls.iterator();
while (decl_it.next()) |entry| {
const decl = mod.declPtr(entry.key_ptr.*);
@ -3810,7 +3811,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
}
if (wasm.dwarf) |*dwarf| {
try dwarf.flushModule(wasm.base.comp.module.?);
try dwarf.flushModule(comp.module.?);
}
}