Commit b54ad93175
Changed files (8)
src
src/codegen/llvm.zig
@@ -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;
src/link/Elf/Symbol.zig
@@ -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;
};
src/link/Elf/ZigObject.zig
@@ -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);
}
src/link/Coff.zig
@@ -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 {
src/link/Elf.zig
@@ -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 gpa = comp.gpa;
+ var arena_allocator = std.heap.ArenaAllocator.init(gpa);
+ defer arena_allocator.deinit();
+ const arena = arena_allocator.allocator();
- const use_lld = build_options.have_llvm and self.base.comp.config.use_lld;
+ 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;
}
- 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();
- 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;
+ 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;
};
src/link/MachO.zig
@@ -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 => {},
src/link/Wasm.zig
@@ -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.?);
}
}
src/link.zig
@@ -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");