mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-04-27 19:09:47 +03:00
llvm: incremental updates for "is named enum value" functions
It was fairly straightforward to at least theoretically handle incremental updates to the fields of an enum type correctly: we just build a new set of instructions, and `std.zig.llvm.Builder` already knows how to replace the old function body with the new one when we call `WipFunction.finish`. Also tightened a few error sets.
This commit is contained in:
committed by
Andrew Kelley
parent
6f7840d589
commit
6ae30662dc
+67
-58
@@ -1625,13 +1625,7 @@ pub const Object = struct {
|
||||
.pt = pt,
|
||||
.err_msg = null,
|
||||
};
|
||||
ng.genDecl() catch |err| switch (err) {
|
||||
error.CodegenFail => switch (pt.zcu.codegenFailMsg(nav_index, ng.err_msg.?)) {
|
||||
error.CodegenFail => return,
|
||||
error.OutOfMemory => |e| return e,
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
try ng.genDecl();
|
||||
try self.flushTypePool(pt);
|
||||
}
|
||||
|
||||
@@ -1713,10 +1707,7 @@ pub const Object = struct {
|
||||
const global_index = variable_index.ptrConst(&o.builder).global;
|
||||
gop.value_ptr.* = global_index;
|
||||
// This line invalidates `gop`.
|
||||
const init_val = o.lowerValue(pt, exported_value) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
error.CodegenFail => return error.AnalysisFail,
|
||||
};
|
||||
const init_val = try o.lowerValue(pt, exported_value);
|
||||
try variable_index.setInitializer(init_val, &o.builder);
|
||||
break :i global_index;
|
||||
};
|
||||
@@ -1834,6 +1825,9 @@ pub const Object = struct {
|
||||
|
||||
pub fn updateContainerType(o: *Object, pt: Zcu.PerThread, ty: InternPool.Index, success: bool) Allocator.Error!void {
|
||||
try o.type_pool.updateContainerType(pt, .{ .llvm = o }, ty, success);
|
||||
if (o.named_enum_map.get(ty)) |function_index| {
|
||||
try o.updateIsNamedEnumValueFunction(pt, .fromInterned(ty), function_index);
|
||||
}
|
||||
}
|
||||
|
||||
/// Should only be called by the `link.ConstPool` implementation.
|
||||
@@ -2907,7 +2901,7 @@ pub const Object = struct {
|
||||
uav: InternPool.Index,
|
||||
llvm_addr_space: Builder.AddrSpace,
|
||||
alignment: InternPool.Alignment,
|
||||
) Error!Builder.Variable.Index {
|
||||
) Allocator.Error!Builder.Variable.Index {
|
||||
assert(alignment != .none);
|
||||
// TODO: Add address space to the anon_decl_map
|
||||
const gop = try o.uav_map.getOrPut(o.gpa, uav);
|
||||
@@ -3506,7 +3500,7 @@ pub const Object = struct {
|
||||
);
|
||||
}
|
||||
|
||||
fn lowerValue(o: *Object, pt: Zcu.PerThread, arg_val: InternPool.Index) Error!Builder.Constant {
|
||||
fn lowerValue(o: *Object, pt: Zcu.PerThread, arg_val: InternPool.Index) Allocator.Error!Builder.Constant {
|
||||
const zcu = pt.zcu;
|
||||
const ip = &zcu.intern_pool;
|
||||
const target = zcu.getTarget();
|
||||
@@ -4019,7 +4013,7 @@ pub const Object = struct {
|
||||
pt: Zcu.PerThread,
|
||||
ptr_val: InternPool.Index,
|
||||
prev_offset: u64,
|
||||
) Error!Builder.Constant {
|
||||
) Allocator.Error!Builder.Constant {
|
||||
const zcu = pt.zcu;
|
||||
const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr;
|
||||
const offset: u64 = prev_offset + ptr.byte_offset;
|
||||
@@ -4086,7 +4080,7 @@ pub const Object = struct {
|
||||
o: *Object,
|
||||
pt: Zcu.PerThread,
|
||||
uav: InternPool.Key.Ptr.BaseAddr.Uav,
|
||||
) Error!Builder.Constant {
|
||||
) Allocator.Error!Builder.Constant {
|
||||
const zcu = pt.zcu;
|
||||
const ip = &zcu.intern_pool;
|
||||
const uav_val = uav.val;
|
||||
@@ -4363,6 +4357,58 @@ pub const Object = struct {
|
||||
const index = try o.type_pool.get(pt, .{ .llvm = o }, ty.toIntern());
|
||||
return o.lazy_abi_aligns.items[@intFromEnum(index)];
|
||||
}
|
||||
|
||||
fn updateIsNamedEnumValueFunction(
|
||||
o: *Object,
|
||||
pt: Zcu.PerThread,
|
||||
enum_ty: Type,
|
||||
function_index: Builder.Function.Index,
|
||||
) Allocator.Error!void {
|
||||
const zcu = pt.zcu;
|
||||
const builder = &o.builder;
|
||||
const loaded_enum = zcu.intern_pool.loadEnumType(enum_ty.toIntern());
|
||||
function_index.ptrConst(builder).global.ptr(builder).type = try builder.fnType(
|
||||
.i1,
|
||||
&.{try o.lowerType(pt, .fromInterned(loaded_enum.int_tag_type))},
|
||||
.normal,
|
||||
);
|
||||
|
||||
var attributes: Builder.FunctionAttributes.Wip = .{};
|
||||
defer attributes.deinit(builder);
|
||||
try o.addCommonFnAttributes(&attributes, zcu.root_mod, zcu.root_mod.omit_frame_pointer);
|
||||
|
||||
function_index.setLinkage(.internal, builder);
|
||||
function_index.setCallConv(.fastcc, builder);
|
||||
function_index.setAttributes(try attributes.finish(builder), builder);
|
||||
|
||||
var wip: Builder.WipFunction = try .init(builder, .{
|
||||
.function = function_index,
|
||||
.strip = true,
|
||||
});
|
||||
defer wip.deinit();
|
||||
wip.cursor = .{ .block = try wip.block(0, "Entry") };
|
||||
|
||||
const named_block = try wip.block(@intCast(loaded_enum.field_names.len), "Named");
|
||||
const unnamed_block = try wip.block(1, "Unnamed");
|
||||
const tag_int_value = wip.arg(0);
|
||||
var wip_switch = try wip.@"switch"(tag_int_value, unnamed_block, @intCast(loaded_enum.field_names.len), .none);
|
||||
defer wip_switch.finish(&wip);
|
||||
|
||||
for (0..loaded_enum.field_names.len) |field_index| {
|
||||
const this_tag_int_value = try o.lowerValue(
|
||||
pt,
|
||||
(try pt.enumValueFieldIndex(enum_ty, @intCast(field_index))).toIntern(),
|
||||
);
|
||||
try wip_switch.addCase(this_tag_int_value, named_block, &wip);
|
||||
}
|
||||
wip.cursor = .{ .block = named_block };
|
||||
_ = try wip.ret(.true);
|
||||
|
||||
wip.cursor = .{ .block = unnamed_block };
|
||||
_ = try wip.ret(.false);
|
||||
|
||||
try wip.finish();
|
||||
}
|
||||
};
|
||||
|
||||
pub const NavGen = struct {
|
||||
@@ -10106,56 +10152,19 @@ pub const FuncGen = struct {
|
||||
const pt = self.ng.pt;
|
||||
const zcu = pt.zcu;
|
||||
const ip = &zcu.intern_pool;
|
||||
const enum_type = ip.loadEnumType(enum_ty.toIntern());
|
||||
|
||||
// TODO: detect when the type changes (`updateContainerType` will be called) and re-emit this function
|
||||
const gop = try o.named_enum_map.getOrPut(o.gpa, enum_ty.toIntern());
|
||||
if (gop.found_existing) return gop.value_ptr.*;
|
||||
errdefer assert(o.named_enum_map.remove(enum_ty.toIntern()));
|
||||
|
||||
const target = &zcu.root_mod.resolved_target.result;
|
||||
const function_index = try o.builder.addFunction(
|
||||
try o.builder.fnType(.i1, &.{try o.lowerType(pt, Type.fromInterned(enum_type.int_tag_type))}, .normal),
|
||||
try o.builder.strtabStringFmt("__zig_is_named_enum_value_{f}", .{enum_type.name.fmt(ip)}),
|
||||
toLlvmAddressSpace(.generic, target),
|
||||
// Dummy function type; `updateIsNamedEnumValue` will replace it with the correct type.
|
||||
// TODO: change the builder API so we don't need to do this.
|
||||
try o.builder.fnType(.void, &.{}, .normal),
|
||||
try o.builder.strtabStringFmt("__zig_is_named_enum_value_{f}", .{enum_ty.containerTypeName(ip).fmt(ip)}),
|
||||
toLlvmAddressSpace(.generic, zcu.getTarget()),
|
||||
);
|
||||
|
||||
var attributes: Builder.FunctionAttributes.Wip = .{};
|
||||
defer attributes.deinit(&o.builder);
|
||||
try o.addCommonFnAttributes(&attributes, zcu.root_mod, zcu.root_mod.omit_frame_pointer);
|
||||
|
||||
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;
|
||||
|
||||
var wip = try Builder.WipFunction.init(&o.builder, .{
|
||||
.function = function_index,
|
||||
.strip = true,
|
||||
});
|
||||
defer wip.deinit();
|
||||
wip.cursor = .{ .block = try wip.block(0, "Entry") };
|
||||
|
||||
const named_block = try wip.block(@intCast(enum_type.field_names.len), "Named");
|
||||
const unnamed_block = try wip.block(1, "Unnamed");
|
||||
const tag_int_value = wip.arg(0);
|
||||
var wip_switch = try wip.@"switch"(tag_int_value, unnamed_block, @intCast(enum_type.field_names.len), .none);
|
||||
defer wip_switch.finish(&wip);
|
||||
|
||||
for (0..enum_type.field_names.len) |field_index| {
|
||||
const this_tag_int_value = try o.lowerValue(
|
||||
pt,
|
||||
(try pt.enumValueFieldIndex(enum_ty, @intCast(field_index))).toIntern(),
|
||||
);
|
||||
try wip_switch.addCase(this_tag_int_value, named_block, &wip);
|
||||
}
|
||||
wip.cursor = .{ .block = named_block };
|
||||
_ = try wip.ret(.true);
|
||||
|
||||
wip.cursor = .{ .block = unnamed_block };
|
||||
_ = try wip.ret(.false);
|
||||
|
||||
try wip.finish();
|
||||
try o.updateIsNamedEnumValueFunction(pt, enum_ty, function_index);
|
||||
return function_index;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user