aboutsummaryrefslogtreecommitdiff
path: root/src/Module.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-09-27 19:48:42 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-09-27 19:53:29 -0700
commitc0aa4a1a42b3e0d312bd274799be67d60a1c0238 (patch)
tree6af32089a5fd3b6f79d7eb8a5fcb26bd0a46c39b /src/Module.zig
parent25266d08046df6032007b46346faf01a2f40ef31 (diff)
downloadzig-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.zig107
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));
}