diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-09-27 19:48:42 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-09-27 19:53:29 -0700 |
| commit | c0aa4a1a42b3e0d312bd274799be67d60a1c0238 (patch) | |
| tree | 6af32089a5fd3b6f79d7eb8a5fcb26bd0a46c39b /src/Module.zig | |
| parent | 25266d08046df6032007b46346faf01a2f40ef31 (diff) | |
| download | zig-c0aa4a1a42b3e0d312bd274799be67d60a1c0238.tar.gz zig-c0aa4a1a42b3e0d312bd274799be67d60a1c0238.zip | |
stage2: implement basic unions
* AIR instructions struct_field_ptr and related functions now are also
emitted by the frontend for unions. Backends must inspect the type
of the pointer operand to lower the instructions correctly.
- These will be renamed to `agg_field_ptr` (short for "aggregate") in
the future.
* Introduce the new `set_union_tag` AIR instruction.
* Introduce `Module.EnumNumbered` and associated `Type` methods. This
is for enums which have no decls, but do have the possibility of
overriding the integer tag type and tag values.
* Sema: Implement support for union tag types in both the
auto-generated and explicitly-provided cases, as well as explicitly
provided enum tag values in union declarations.
* LLVM backend: implement lowering union types, union field pointer
instructions, and the new `set_union_tag` instruction.
Diffstat (limited to 'src/Module.zig')
| -rw-r--r-- | src/Module.zig | 107 |
1 files changed, 105 insertions, 2 deletions
diff --git a/src/Module.zig b/src/Module.zig index dbece09255..83bbbb6366 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -859,6 +859,36 @@ pub const EnumSimple = struct { } }; +/// Represents the data that an enum declaration provides, when there are no +/// declarations. However an integer tag type is provided, and the enum tag values +/// are explicitly provided. +pub const EnumNumbered = struct { + /// The Decl that corresponds to the enum itself. + owner_decl: *Decl, + /// 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, + /// Set of field names in declaration order. + fields: NameMap, + /// Maps integer tag value to field index. + /// Entries are in declaration order, same as `fields`. + /// If this hash map is empty, it means the enum tags are auto-numbered. + values: ValueMap, + /// Offset from `owner_decl`, points to the enum decl AST node. + node_offset: i32, + + pub const NameMap = EnumFull.NameMap; + pub const ValueMap = EnumFull.ValueMap; + + pub fn srcLoc(self: EnumNumbered) SrcLoc { + return .{ + .file_scope = self.owner_decl.getFileScope(), + .parent_decl_node = self.owner_decl.src_node, + .lazy = .{ .node_offset = self.node_offset }, + }; + } +}; + /// Represents the data that an enum declaration provides, when there is /// at least one tag value explicitly specified, or at least one declaration. pub const EnumFull = struct { @@ -868,16 +898,17 @@ pub const EnumFull = struct { /// Whether zig chooses this type or the user specifies it, it is stored here. tag_ty: Type, /// Set of field names in declaration order. - fields: std.StringArrayHashMapUnmanaged(void), + fields: NameMap, /// Maps integer tag value to field index. /// Entries are in declaration order, same as `fields`. /// If this hash map is empty, it means the enum tags are auto-numbered. values: ValueMap, - /// Represents the declarations inside this struct. + /// Represents the declarations inside this enum. namespace: Scope.Namespace, /// Offset from `owner_decl`, points to the enum decl AST node. node_offset: i32, + pub const NameMap = std.StringArrayHashMapUnmanaged(void); pub const ValueMap = std.ArrayHashMapUnmanaged(Value, void, Value.ArrayHashContext, false); pub fn srcLoc(self: EnumFull) SrcLoc { @@ -933,6 +964,44 @@ pub const Union = struct { .lazy = .{ .node_offset = self.node_offset }, }; } + + pub fn haveFieldTypes(u: Union) bool { + return switch (u.status) { + .none, + .field_types_wip, + => false, + .have_field_types, + .layout_wip, + .have_layout, + => true, + }; + } + + pub fn onlyTagHasCodegenBits(u: Union) bool { + assert(u.haveFieldTypes()); + for (u.fields.values()) |field| { + if (field.ty.hasCodeGenBits()) return false; + } + return true; + } + + pub fn mostAlignedField(u: Union, target: Target) u32 { + assert(u.haveFieldTypes()); + var most_alignment: u64 = 0; + var most_index: usize = undefined; + for (u.fields.values()) |field, i| { + if (!field.ty.hasCodeGenBits()) continue; + const field_align = if (field.abi_align.tag() == .abi_align_default) + field.ty.abiAlignment(target) + else + field.abi_align.toUnsignedInt(); + if (field_align > most_alignment) { + most_alignment = field_align; + most_index = i; + } + } + return @intCast(u32, most_index); + } }; /// Some Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator. @@ -1543,6 +1612,40 @@ pub const Scope = struct { }); } + pub fn addStructFieldPtr( + block: *Block, + struct_ptr: Air.Inst.Ref, + field_index: u32, + ptr_field_ty: Type, + ) !Air.Inst.Ref { + const ty = try block.sema.addType(ptr_field_ty); + const tag: Air.Inst.Tag = switch (field_index) { + 0 => .struct_field_ptr_index_0, + 1 => .struct_field_ptr_index_1, + 2 => .struct_field_ptr_index_2, + 3 => .struct_field_ptr_index_3, + else => { + return block.addInst(.{ + .tag = .struct_field_ptr, + .data = .{ .ty_pl = .{ + .ty = ty, + .payload = try block.sema.addExtra(Air.StructField{ + .struct_operand = struct_ptr, + .field_index = @intCast(u32, field_index), + }), + } }, + }); + }, + }; + return block.addInst(.{ + .tag = tag, + .data = .{ .ty_op = .{ + .ty = ty, + .operand = struct_ptr, + } }, + }); + } + pub fn addInst(block: *Block, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Ref { return Air.indexToRef(try block.addInstAsIndex(inst)); } |
