aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2022-03-14 21:11:49 -0700
committerAndrew Kelley <andrew@ziglang.org>2022-03-14 21:43:03 -0700
commit2f92d1a0264b6827cb67a55726c4c9a082337508 (patch)
treed6691a25a828b44cb4c17365fb8549d339046810 /src
parent50a1ca24ca2a4311097132d660b8244f252da82f (diff)
downloadzig-2f92d1a0264b6827cb67a55726c4c9a082337508.tar.gz
zig-2f92d1a0264b6827cb67a55726c4c9a082337508.zip
stage2: fixups for topolarity-comptime-memory-reinterp branch
* don't store `has_well_defined_layout` in memory. * remove struct `hasWellDefinedLayout` logic. it's just `layout != .Auto`. This means we only need one implementation, in Type. * fix some of the cases being wrong in `hasWellDefinedLayout`, such as optional pointers. * move `tag_ty_inferred` field into a position that makes it more obvious how the struct layout will be done. Also we don't have a compiler that intelligently moves fields around so this layout is better. * Sema: don't `resolveTypeLayout` in `zirCoerceResultPtr` unless necessary. * Rename `ComptimePtrLoadKit` `target` field to `pointee` to avoid confusion with `target`.
Diffstat (limited to 'src')
-rw-r--r--src/Module.zig6
-rw-r--r--src/Sema.zig235
-rw-r--r--src/codegen/llvm.zig5
-rw-r--r--src/type.zig51
-rw-r--r--src/value.zig4
5 files changed, 53 insertions, 248 deletions
diff --git a/src/Module.zig b/src/Module.zig
index 7c6c654660..20bf25af03 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -885,7 +885,6 @@ pub const Struct = struct {
/// one possible value.
known_non_opv: bool,
requires_comptime: PropertyBoolean = .unknown,
- has_well_defined_layout: PropertyBoolean = .unknown,
pub const Fields = std.StringArrayHashMapUnmanaged(Field);
@@ -1080,8 +1079,6 @@ pub const EnumFull = struct {
/// An integer type which is used for the numerical value of the enum.
/// Whether zig chooses this type or the user specifies it, it is stored here.
tag_ty: Type,
- /// true if zig inferred this tag type, false if user specified it
- tag_ty_inferred: bool,
/// Set of field names in declaration order.
fields: NameMap,
/// Maps integer tag value to field index.
@@ -1092,6 +1089,8 @@ pub const EnumFull = struct {
namespace: Namespace,
/// Offset from `owner_decl`, points to the enum decl AST node.
node_offset: i32,
+ /// true if zig inferred this tag type, false if user specified it
+ tag_ty_inferred: bool,
pub const NameMap = std.StringArrayHashMapUnmanaged(void);
pub const ValueMap = std.ArrayHashMapUnmanaged(Value, void, Value.ArrayHashContext, false);
@@ -1136,7 +1135,6 @@ pub const Union = struct {
fully_resolved,
},
requires_comptime: PropertyBoolean = .unknown,
- has_well_defined_layout: PropertyBoolean = .unknown,
pub const Field = struct {
/// undefined until `status` is `have_field_types` or `have_layout`.
diff --git a/src/Sema.zig b/src/Sema.zig
index ad96aea7ab..57522bcfd5 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -1579,8 +1579,6 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
const target = sema.mod.getTarget();
const addr_space = target_util.defaultAddressSpace(target, .local);
- try sema.resolveTypeLayout(block, src, pointee_ty);
-
if (Air.refToIndex(ptr)) |ptr_inst| {
if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) {
const air_datas = sema.air_instructions.items(.data);
@@ -1617,6 +1615,9 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
try pointee_ty.copy(anon_decl.arena()),
Value.undef,
);
+ if (iac.data.alignment != 0) {
+ try sema.resolveTypeLayout(block, src, pointee_ty);
+ }
const ptr_ty = try Type.ptr(sema.arena, target, .{
.pointee_type = pointee_ty,
.@"align" = iac.data.alignment,
@@ -1886,7 +1887,7 @@ fn zirEnumDecl(
enum_obj.* = .{
.owner_decl = new_decl,
- .tag_ty = Type.initTag(.@"null"),
+ .tag_ty = Type.@"null",
.tag_ty_inferred = true,
.fields = .{},
.values = .{},
@@ -17867,13 +17868,13 @@ const TypedValueAndOffset = struct {
};
const ComptimePtrLoadKit = struct {
- /// The Value and Type corresponding to the target of the provided pointer.
+ /// The Value and Type corresponding to the pointee of the provided pointer.
/// If a direct dereference is not possible, this is null.
- target: ?TypedValue,
- /// The largest parent Value containing `target` and having a well-defined memory layout.
- /// This is used for bitcasting, if direct dereferencing failed (i.e. `target` is null).
+ pointee: ?TypedValue,
+ /// The largest parent Value containing `pointee` and having a well-defined memory layout.
+ /// This is used for bitcasting, if direct dereferencing failed (i.e. `pointee` is null).
parent: ?TypedValueAndOffset,
- /// Whether the `target` could be mutated by further
+ /// Whether the `pointee` could be mutated by further
/// semantic analysis and a copy must be performed.
is_mutable: bool,
/// If the root decl could not be used as `parent`, this is the type that
@@ -17885,7 +17886,7 @@ const ComptimePtrLoadError = CompileError || error{
RuntimeLoad,
};
-/// If `maybe_array_ty` is provided, it will be used to directly dereference an
+/// If `maybe_array_ty` is provided, it will be used to directly dereference an
/// .elem_ptr of type T to a value of [N]T, if necessary.
fn beginComptimePtrLoad(
sema: *Sema,
@@ -17908,10 +17909,10 @@ fn beginComptimePtrLoad(
const decl_tv = try decl.typedValue();
if (decl_tv.val.tag() == .variable) return error.RuntimeLoad;
- const layout_defined = try sema.typeHasWellDefinedLayout(block, src, decl.ty);
+ const layout_defined = decl.ty.hasWellDefinedLayout();
break :blk ComptimePtrLoadKit{
.parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null,
- .target = decl_tv,
+ .pointee = decl_tv,
.is_mutable = is_mutable,
.ty_without_well_defined_layout = if (!layout_defined) decl.ty else null,
};
@@ -17923,7 +17924,7 @@ fn beginComptimePtrLoad(
var deref = try beginComptimePtrLoad(sema, block, src, elem_ptr.array_ptr, null);
if (elem_ptr.index != 0) {
- if (try sema.typeHasWellDefinedLayout(block, src, elem_ty)) {
+ if (elem_ty.hasWellDefinedLayout()) {
if (deref.parent) |*parent| {
// Update the byte offset (in-place)
const elem_size = try sema.typeAbiSize(block, src, elem_ty);
@@ -17938,17 +17939,17 @@ fn beginComptimePtrLoad(
// If we're loading an elem_ptr that was derived from a different type
// than the true type of the underlying decl, we cannot deref directly
- const ty_matches = if (deref.target != null and deref.target.?.ty.isArrayLike()) x: {
- const deref_elem_ty = deref.target.?.ty.childType();
+ const ty_matches = if (deref.pointee != null and deref.pointee.?.ty.isArrayLike()) x: {
+ const deref_elem_ty = deref.pointee.?.ty.childType();
break :x (try sema.coerceInMemoryAllowed(block, deref_elem_ty, elem_ty, false, target, src, src)) == .ok or
(try sema.coerceInMemoryAllowed(block, elem_ty, deref_elem_ty, false, target, src, src)) == .ok;
} else false;
if (!ty_matches) {
- deref.target = null;
+ deref.pointee = null;
break :blk deref;
}
- var array_tv = deref.target.?;
+ var array_tv = deref.pointee.?;
const check_len = array_tv.ty.arrayLenIncludingSentinel();
if (elem_ptr.index >= check_len) {
// TODO have the deref include the decl so we can say "declared here"
@@ -17959,10 +17960,10 @@ fn beginComptimePtrLoad(
if (maybe_array_ty) |load_ty| {
// It's possible that we're loading a [N]T, in which case we'd like to slice
- // the target array directly from our parent array.
+ // the pointee array directly from our parent array.
if (load_ty.isArrayLike() and load_ty.childType().eql(elem_ty)) {
const N = try sema.usizeCast(block, src, load_ty.arrayLenIncludingSentinel());
- deref.target = if (elem_ptr.index + N <= check_len) TypedValue{
+ deref.pointee = if (elem_ptr.index + N <= check_len) TypedValue{
.ty = try Type.array(sema.arena, N, null, elem_ty),
.val = try array_tv.val.sliceArray(sema.arena, elem_ptr.index, elem_ptr.index + N),
} else null;
@@ -17970,7 +17971,7 @@ fn beginComptimePtrLoad(
}
}
- deref.target = .{
+ deref.pointee = .{
.ty = elem_ty,
.val = try array_tv.val.elemValue(sema.arena, elem_ptr.index),
};
@@ -17983,7 +17984,7 @@ fn beginComptimePtrLoad(
const field_ty = field_ptr.container_ty.structFieldType(field_index);
var deref = try beginComptimePtrLoad(sema, block, src, field_ptr.container_ptr, field_ptr.container_ty);
- if (try sema.typeHasWellDefinedLayout(block, src, field_ptr.container_ty)) {
+ if (field_ptr.container_ty.hasWellDefinedLayout()) {
if (deref.parent) |*parent| {
// Update the byte offset (in-place)
try sema.resolveTypeLayout(block, src, field_ptr.container_ty);
@@ -17995,19 +17996,19 @@ fn beginComptimePtrLoad(
deref.ty_without_well_defined_layout = field_ptr.container_ty;
}
- if (deref.target) |*tv| {
+ if (deref.pointee) |*tv| {
const coerce_in_mem_ok =
(try sema.coerceInMemoryAllowed(block, field_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or
(try sema.coerceInMemoryAllowed(block, tv.ty, field_ptr.container_ty, false, target, src, src)) == .ok;
if (coerce_in_mem_ok) {
- deref.target = TypedValue{
+ deref.pointee = TypedValue{
.ty = field_ty,
.val = try tv.val.fieldValue(sema.arena, field_index),
};
break :blk deref;
}
}
- deref.target = null;
+ deref.pointee = null;
break :blk deref;
},
@@ -18028,7 +18029,7 @@ fn beginComptimePtrLoad(
deref.ty_without_well_defined_layout = payload_ptr.container_ty;
}
- if (deref.target) |*tv| {
+ if (deref.pointee) |*tv| {
const coerce_in_mem_ok =
(try sema.coerceInMemoryAllowed(block, payload_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or
(try sema.coerceInMemoryAllowed(block, tv.ty, payload_ptr.container_ty, false, target, src, src)) == .ok;
@@ -18042,7 +18043,7 @@ fn beginComptimePtrLoad(
break :blk deref;
}
}
- deref.target = null;
+ deref.pointee = null;
break :blk deref;
},
@@ -18060,7 +18061,7 @@ fn beginComptimePtrLoad(
else => unreachable,
};
- if (deref.target) |tv| {
+ if (deref.pointee) |tv| {
if (deref.parent == null and tv.ty.hasWellDefinedLayout()) {
deref.parent = .{ .tv = tv, .byte_offset = 0 };
}
@@ -21157,7 +21158,7 @@ fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr
else => |e| return e,
};
- if (deref.target) |tv| {
+ if (deref.pointee) |tv| {
const coerce_in_mem_ok =
(try sema.coerceInMemoryAllowed(block, load_ty, tv.ty, false, target, src, src)) == .ok or
(try sema.coerceInMemoryAllowed(block, tv.ty, load_ty, false, target, src, src)) == .ok;
@@ -21176,13 +21177,13 @@ fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr
// The type is not in-memory coercible or the direct dereference failed, so it must
// be bitcast according to the pointer type we are performing the load through.
- if (!(try sema.typeHasWellDefinedLayout(block, src, load_ty)))
+ if (!load_ty.hasWellDefinedLayout())
return sema.fail(block, src, "comptime dereference requires {} to have a well-defined layout, but it does not.", .{load_ty});
const load_sz = try sema.typeAbiSize(block, src, load_ty);
// Try the smaller bit-cast first, since that's more efficient than using the larger `parent`
- if (deref.target) |tv| if (load_sz <= try sema.typeAbiSize(block, src, tv.ty))
+ if (deref.pointee) |tv| if (load_sz <= try sema.typeAbiSize(block, src, tv.ty))
return try sema.bitCastVal(block, src, tv.val, tv.ty, load_ty, 0);
// If that fails, try to bit-cast from the largest parent value with a well-defined layout
@@ -21271,182 +21272,6 @@ fn typePtrOrOptionalPtrTy(
}
}
-fn typeHasWellDefinedLayout(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {
- return switch (ty.tag()) {
- .u1,
- .u8,
- .i8,
- .u16,
- .i16,
- .u32,
- .i32,
- .u64,
- .i64,
- .u128,
- .i128,
- .usize,
- .isize,
- .c_short,
- .c_ushort,
- .c_int,
- .c_uint,
- .c_long,
- .c_ulong,
- .c_longlong,
- .c_ulonglong,
- .c_longdouble,
- .f16,
- .f32,
- .f64,
- .f80,
- .f128,
- .bool,
- .void,
- .manyptr_u8,
- .manyptr_const_u8,
- .manyptr_const_u8_sentinel_0,
- .anyerror_void_error_union,
- .empty_struct_literal,
- .empty_struct,
- .array_u8,
- .array_u8_sentinel_0,
- .int_signed,
- .int_unsigned,
- .pointer,
- .single_const_pointer,
- .single_mut_pointer,
- .many_const_pointer,
- .many_mut_pointer,
- .c_const_pointer,
- .c_mut_pointer,
- .single_const_pointer_to_comptime_int,
- .enum_numbered,
- => true,
-
- .anyopaque,
- .anyerror,
- .noreturn,
- .@"null",
- .@"anyframe",
- .@"undefined",
- .atomic_order,
- .atomic_rmw_op,
- .calling_convention,
- .address_space,
- .float_mode,
- .reduce_op,
- .call_options,
- .prefetch_options,
- .export_options,
- .extern_options,
- .error_set,
- .error_set_single,
- .error_set_inferred,
- .error_set_merged,
- .@"opaque",
- .generic_poison,
- .type,
- .comptime_int,
- .comptime_float,
- .enum_literal,
- .type_info,
- // These are function bodies, not function pointers.
- .fn_noreturn_no_args,
- .fn_void_no_args,
- .fn_naked_noreturn_no_args,
- .fn_ccc_void_no_args,
- .function,
- .const_slice_u8,
- .const_slice_u8_sentinel_0,
- .const_slice,
- .mut_slice,
- .enum_simple,
- .error_union,
- .anyframe_T,
- .tuple,
- .anon_struct,
- => false,
-
- .enum_full,
- .enum_nonexhaustive,
- => !ty.cast(Type.Payload.EnumFull).?.data.tag_ty_inferred,
-
- .var_args_param => unreachable,
- .inferred_alloc_mut => unreachable,
- .inferred_alloc_const => unreachable,
- .bound_fn => unreachable,
-
- .array,
- .array_sentinel,
- .vector,
- => sema.typeHasWellDefinedLayout(block, src, ty.childType()),
-
- .optional,
- .optional_single_mut_pointer,
- .optional_single_const_pointer,
- => blk: {
- var buf: Type.Payload.ElemType = undefined;
- break :blk sema.typeHasWellDefinedLayout(block, src, ty.optionalChild(&buf));
- },
-
- .@"struct" => {
- const struct_obj = ty.castTag(.@"struct").?.data;
- if (struct_obj.layout == .Auto) {
- struct_obj.has_well_defined_layout = .no;
- return false;
- }
- switch (struct_obj.has_well_defined_layout) {
- .no => return false,
- .yes, .wip => return true,
- .unknown => {
- if (struct_obj.status == .field_types_wip)
- return true;
-
- try sema.resolveTypeFieldsStruct(block, src, ty, struct_obj);
-
- struct_obj.has_well_defined_layout = .wip;
- for (struct_obj.fields.values()) |field| {
- if (!(try sema.typeHasWellDefinedLayout(block, src, field.ty))) {
- struct_obj.has_well_defined_layout = .no;
- return false;
- }
- }
- struct_obj.has_well_defined_layout = .yes;
- return true;
- },
- }
- },
-
- .@"union", .union_tagged => {
- const union_obj = ty.cast(Type.Payload.Union).?.data;
- if (union_obj.layout == .Auto) {
- union_obj.has_well_defined_layout = .no;
- return false;
- }
- switch (union_obj.has_well_defined_layout) {
- .no => return false,
- .yes, .wip => return true,
- .unknown => {
- if (union_obj.status == .field_types_wip)
- return true;
-
- try sema.resolveTypeFieldsUnion(block, src, ty, union_obj);
-
- union_obj.has_well_defined_layout = .wip;
- for (union_obj.fields.values()) |field| {
- if (!(try sema.typeHasWellDefinedLayout(block, src, field.ty))) {
- union_obj.has_well_defined_layout = .no;
- return false;
- }
- }
- union_obj.has_well_defined_layout = .yes;
- return true;
- },
- }
- },
- };
-}
-
/// `generic_poison` will return false.
/// This function returns false negatives when structs and unions are having their
/// field types resolved.
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index 08cfe4a258..94dacf61e8 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -2829,7 +2829,10 @@ pub const DeclGen = struct {
// (void) payload is the same.
break :blk parent_llvm_ptr;
}
- const llvm_pl_index = if (layout.tag_size == 0) 0 else @boolToInt(layout.tag_align >= layout.payload_align);
+ const llvm_pl_index = if (layout.tag_size == 0)
+ 0
+ else
+ @boolToInt(layout.tag_align >= layout.payload_align);
const indices: [2]*const llvm.Value = .{
llvm_u32.constInt(0, .False),
llvm_u32.constInt(llvm_pl_index, .False),
diff --git a/src/type.zig b/src/type.zig
index 3f6e3ef282..2df7cc83d8 100644
--- a/src/type.zig
+++ b/src/type.zig
@@ -2210,9 +2210,6 @@ pub const Type = extern union {
.manyptr_u8,
.manyptr_const_u8,
.manyptr_const_u8_sentinel_0,
- .anyerror_void_error_union,
- .empty_struct_literal,
- .empty_struct,
.array_u8,
.array_u8_sentinel_0,
.int_signed,
@@ -2226,6 +2223,9 @@ pub const Type = extern union {
.c_mut_pointer,
.single_const_pointer_to_comptime_int,
.enum_numbered,
+ .vector,
+ .optional_single_mut_pointer,
+ .optional_single_const_pointer,
=> true,
.anyopaque,
@@ -2267,9 +2267,12 @@ pub const Type = extern union {
.mut_slice,
.enum_simple,
.error_union,
+ .anyerror_void_error_union,
.anyframe_T,
.tuple,
.anon_struct,
+ .empty_struct_literal,
+ .empty_struct,
=> false,
.enum_full,
@@ -2283,36 +2286,12 @@ pub const Type = extern union {
.array,
.array_sentinel,
- .vector,
=> ty.childType().hasWellDefinedLayout(),
- .optional,
- .optional_single_mut_pointer,
- .optional_single_const_pointer,
- => {
- var buf: Type.Payload.ElemType = undefined;
- return ty.optionalChild(&buf).hasWellDefinedLayout();
- },
-
- .@"struct" => {
- const struct_obj = ty.castTag(.@"struct").?.data;
- if (struct_obj.layout == .Auto) return false;
- switch (struct_obj.has_well_defined_layout) {
- .wip, .unknown => unreachable, // This function asserts types already resolved.
- .no => return false,
- .yes => return true,
- }
- },
-
- .@"union", .union_tagged => {
- const union_obj = ty.cast(Type.Payload.Union).?.data;
- if (union_obj.layout == .Auto) return false;
- switch (union_obj.has_well_defined_layout) {
- .wip, .unknown => unreachable, // This function asserts types already resolved.
- .no => return false,
- .yes => return true,
- }
- },
+ .optional => ty.isPtrLikeOptional(),
+ .@"struct" => ty.castTag(.@"struct").?.data.layout != .Auto,
+ .@"union" => ty.castTag(.@"union").?.data.layout != .Auto,
+ .union_tagged => false,
};
}
@@ -3299,13 +3278,12 @@ pub const Type = extern union {
=> return true,
.optional => {
- var buf: Payload.ElemType = undefined;
- const child_type = self.optionalChild(&buf);
+ const child_ty = self.castTag(.optional).?.data;
// optionals of zero sized types behave like bools, not pointers
- if (!child_type.hasRuntimeBits()) return false;
- if (child_type.zigTypeTag() != .Pointer) return false;
+ if (!child_ty.hasRuntimeBits()) return false;
+ if (child_ty.zigTypeTag() != .Pointer) return false;
- const info = child_type.ptrInfo().data;
+ const info = child_ty.ptrInfo().data;
switch (info.size) {
.Slice, .C => return false,
.Many, .One => return !info.@"allowzero",
@@ -5496,6 +5474,7 @@ pub const Type = extern union {
pub const @"type" = initTag(.type);
pub const @"anyerror" = initTag(.anyerror);
pub const @"anyopaque" = initTag(.anyopaque);
+ pub const @"null" = initTag(.@"null");
pub fn ptr(arena: Allocator, target: Target, data: Payload.Pointer.Data) !Type {
var d = data;
diff --git a/src/value.zig b/src/value.zig
index af5ee75737..24cec0396e 100644
--- a/src/value.zig
+++ b/src/value.zig
@@ -2417,7 +2417,7 @@ pub const Value = extern union {
return switch (val.tag()) {
.empty_array_sentinel => if (start == 0 and end == 1) val else Value.initTag(.empty_array),
.bytes => Tag.bytes.create(arena, val.castTag(.bytes).?.data[start..end]),
- .array => Tag.array.create(arena, val.castTag(.array).?.data[start..end]),
+ .aggregate => Tag.aggregate.create(arena, val.castTag(.aggregate).?.data[start..end]),
.slice => sliceArray(val.castTag(.slice).?.data.ptr, arena, start, end),
.decl_ref => sliceArray(val.castTag(.decl_ref).?.data.val, arena, start, end),
@@ -2466,7 +2466,7 @@ pub const Value = extern union {
pub fn elemPtr(val: Value, ty: Type, arena: Allocator, index: usize) Allocator.Error!Value {
const elem_ty = ty.elemType2();
const ptr_val = switch (val.tag()) {
- .slice => val.slicePtr(),
+ .slice => val.castTag(.slice).?.data.ptr,
else => val,
};