aboutsummaryrefslogtreecommitdiff
path: root/src/type.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-10-11 11:00:32 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-10-11 11:39:12 -0700
commit6d6cf598475ab8d2c3259002655ba04f1d056b2e (patch)
treedaf38d2c3c68de0411d9106668bde92cc7e0651b /src/type.zig
parentf42725c39bbbe5db13c1a1706db3f31aa0549307 (diff)
downloadzig-6d6cf598475ab8d2c3259002655ba04f1d056b2e.tar.gz
zig-6d6cf598475ab8d2c3259002655ba04f1d056b2e.zip
stage2: support nested structs and arrays and sret
* Add AIR instructions: ret_ptr, ret_load - This allows Sema to be blissfully unaware of the backend's decision to implement by-val/by-ref semantics for struct/union/array types. Backends can lower these simply as alloc, load, ret instructions, or they can take advantage of them to use a result pointer. * Add AIR instruction: array_elem_val - Allows for better codegen for `Sema.elemVal`. * Implement calculation of ABI alignment and ABI size for unions. * Before appending the following AIR instructions to a block, resolveTypeLayout is called on the type: - call - return type - ret - return type - store_ptr - elem type * Sema: fix memory leak in `zirArrayInit` and other cleanups to this function. * x86_64: implement the full x86_64 C ABI according to the spec * Type: implement `intInfo` for error sets. * Type: implement `intTagType` for tagged unions. The Zig type tag `Fn` is now used exclusively for function bodies. Function pointers are modeled as `*const T` where `T` is a `Fn` type. * The `call` AIR instruction now allows a function pointer operand as well as a function operand. * Sema now has a coercion from function body to function pointer. * Function type syntax, e.g. `fn()void`, now returns zig tag type of Pointer with child Fn, rather than Fn directly. - I think this should probably be reverted. Will discuss the lang specs before doing this. Idea being that function pointers would need to be specified as `*const fn()void` rather than `fn() void`. LLVM backend: * Enable calling the panic handler (previously this just emitted `@breakpoint()` since the backend could not handle the panic function). * Implement sret * Introduce `isByRef` and implement it for structs and arrays. Types that are `isByRef` are now passed as pointers to functions, and e.g. `elem_val` will return a pointer instead of doing a load. * Move the function type creating code from `resolveLlvmFunction` to `llvmType` where it belongs; now there is only 1 instance of this logic instead of two. * Add the `nonnull` attribute to non-optional pointer parameters. * Fix `resolveGlobalDecl` not using fully-qualified names and not using the `decl_map`. * Implement `genTypedValue` for pointer-like optionals. * Fix memory leak when lowering `block` instruction and OOM occurs. * Implement volatile checks where relevant.
Diffstat (limited to 'src/type.zig')
-rw-r--r--src/type.zig76
1 files changed, 39 insertions, 37 deletions
diff --git a/src/type.zig b/src/type.zig
index e7356e4842..2abf7e9baf 100644
--- a/src/type.zig
+++ b/src/type.zig
@@ -1707,32 +1707,10 @@ pub const Type = extern union {
const int_tag_ty = self.intTagType(&buffer);
return int_tag_ty.abiAlignment(target);
},
- .union_tagged => {
- const union_obj = self.castTag(.union_tagged).?.data;
- var biggest: u32 = union_obj.tag_ty.abiAlignment(target);
- for (union_obj.fields.values()) |field| {
- if (!field.ty.hasCodeGenBits()) continue;
- const field_align = field.ty.abiAlignment(target);
- if (field_align > biggest) {
- biggest = field_align;
- }
- }
- assert(biggest != 0);
- return biggest;
- },
- .@"union" => {
- const union_obj = self.castTag(.@"union").?.data;
- var biggest: u32 = 0;
- for (union_obj.fields.values()) |field| {
- if (!field.ty.hasCodeGenBits()) continue;
- const field_align = field.ty.abiAlignment(target);
- if (field_align > biggest) {
- biggest = field_align;
- }
- }
- assert(biggest != 0);
- return biggest;
- },
+ // TODO pass `true` for have_tag when unions have a safety tag
+ .@"union" => return self.castTag(.@"union").?.data.abiAlignment(target, false),
+ .union_tagged => return self.castTag(.union_tagged).?.data.abiAlignment(target, true),
+
.c_void,
.void,
.type,
@@ -1790,6 +1768,7 @@ pub const Type = extern union {
const is_packed = s.layout == .Packed;
if (is_packed) @panic("TODO packed structs");
var size: u64 = 0;
+ var big_align: u32 = 0;
for (s.fields.values()) |field| {
if (!field.ty.hasCodeGenBits()) continue;
@@ -1797,12 +1776,14 @@ pub const Type = extern union {
if (field.abi_align.tag() == .abi_align_default) {
break :a field.ty.abiAlignment(target);
} else {
- break :a field.abi_align.toUnsignedInt();
+ break :a @intCast(u32, field.abi_align.toUnsignedInt());
}
};
+ big_align = @maximum(big_align, field_align);
size = std.mem.alignForwardGeneric(u64, size, field_align);
size += field.ty.abiSize(target);
}
+ size = std.mem.alignForwardGeneric(u64, size, big_align);
return size;
},
.enum_simple, .enum_full, .enum_nonexhaustive, .enum_numbered => {
@@ -1810,9 +1791,9 @@ pub const Type = extern union {
const int_tag_ty = self.intTagType(&buffer);
return int_tag_ty.abiSize(target);
},
- .@"union", .union_tagged => {
- @panic("TODO abiSize unions");
- },
+ // TODO pass `true` for have_tag when unions have a safety tag
+ .@"union" => return self.castTag(.@"union").?.data.abiSize(target, false),
+ .union_tagged => return self.castTag(.union_tagged).?.data.abiSize(target, true),
.u1,
.u8,
@@ -2550,6 +2531,11 @@ pub const Type = extern union {
};
}
+ pub fn unionFields(ty: Type) Module.Union.Fields {
+ const union_obj = ty.cast(Payload.Union).?.data;
+ return union_obj.fields;
+ }
+
pub fn unionFieldType(ty: Type, enum_tag: Value) Type {
const union_obj = ty.cast(Payload.Union).?.data;
const index = union_obj.tag_ty.enumTagFieldIndex(enum_tag).?;
@@ -2657,7 +2643,7 @@ pub const Type = extern union {
};
}
- /// Asserts the type is an integer or enum.
+ /// Asserts the type is an integer, enum, or error set.
pub fn intInfo(self: Type, target: Target) struct { signedness: std.builtin.Signedness, bits: u16 } {
var ty = self;
while (true) switch (ty.tag()) {
@@ -2700,6 +2686,11 @@ pub const Type = extern union {
return .{ .signedness = .unsigned, .bits = smallestUnsignedBits(field_count - 1) };
},
+ .error_set, .error_set_single, .anyerror, .error_set_inferred => {
+ // TODO revisit this when error sets support custom int types
+ return .{ .signedness = .unsigned, .bits = 16 };
+ },
+
else => unreachable,
};
}
@@ -3151,12 +3142,12 @@ pub const Type = extern union {
/// Asserts the type is an enum or a union.
/// TODO support unions
- pub fn intTagType(self: Type, buffer: *Payload.Bits) Type {
- switch (self.tag()) {
- .enum_full, .enum_nonexhaustive => return self.cast(Payload.EnumFull).?.data.tag_ty,
- .enum_numbered => return self.castTag(.enum_numbered).?.data.tag_ty,
+ pub fn intTagType(ty: Type, buffer: *Payload.Bits) Type {
+ switch (ty.tag()) {
+ .enum_full, .enum_nonexhaustive => return ty.cast(Payload.EnumFull).?.data.tag_ty,
+ .enum_numbered => return ty.castTag(.enum_numbered).?.data.tag_ty,
.enum_simple => {
- const enum_simple = self.castTag(.enum_simple).?.data;
+ const enum_simple = ty.castTag(.enum_simple).?.data;
const bits = std.math.log2_int_ceil(usize, enum_simple.fields.count());
buffer.* = .{
.base = .{ .tag = .int_unsigned },
@@ -3164,6 +3155,7 @@ pub const Type = extern union {
};
return Type.initPayload(&buffer.base);
},
+ .union_tagged => return ty.castTag(.union_tagged).?.data.tag_ty.intTagType(buffer),
else => unreachable,
}
}
@@ -3317,6 +3309,16 @@ pub const Type = extern union {
}
}
+ pub fn structFields(ty: Type) Module.Struct.Fields {
+ switch (ty.tag()) {
+ .@"struct" => {
+ const struct_obj = ty.castTag(.@"struct").?.data;
+ return struct_obj.fields;
+ },
+ else => unreachable,
+ }
+ }
+
pub fn structFieldCount(ty: Type) usize {
switch (ty.tag()) {
.@"struct" => {
@@ -3815,7 +3817,7 @@ pub const Type = extern union {
bit_offset: u16 = 0,
host_size: u16 = 0,
@"allowzero": bool = false,
- mutable: bool = true, // TODO change this to const, not mutable
+ mutable: bool = true, // TODO rename this to const, not mutable
@"volatile": bool = false,
size: std.builtin.TypeInfo.Pointer.Size = .One,
};