diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-10-11 11:00:32 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-10-11 11:39:12 -0700 |
| commit | 6d6cf598475ab8d2c3259002655ba04f1d056b2e (patch) | |
| tree | daf38d2c3c68de0411d9106668bde92cc7e0651b /src/type.zig | |
| parent | f42725c39bbbe5db13c1a1706db3f31aa0549307 (diff) | |
| download | zig-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.zig | 76 |
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, }; |
