Commit 6329f4e47a

Robin Voetter <robin@voetter.nl>
2021-10-20 02:23:09
stage2: union field value
1 parent d6f048c
Changed files (2)
src
src/codegen/llvm.zig
@@ -2236,17 +2236,34 @@ pub const FuncGen = struct {
         const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;
         const struct_ty = self.air.typeOf(struct_field.struct_operand);
         const struct_llvm_val = try self.resolveInst(struct_field.struct_operand);
-        const field_index = llvmFieldIndex(struct_ty, struct_field.field_index);
-        if (isByRef(struct_ty)) {
-            const field_ptr = self.builder.buildStructGEP(struct_llvm_val, field_index, "");
-            const field_ty = struct_ty.structFieldType(struct_field.field_index);
-            if (isByRef(field_ty)) {
-                return field_ptr;
-            } else {
-                return self.builder.buildLoad(field_ptr, "");
-            }
+        const field_index = struct_field.field_index;
+        const field_ty = struct_ty.structFieldType(field_index);
+        if (!field_ty.hasCodeGenBits()) {
+            return null;
+        }
+
+        assert(isByRef(struct_ty));
+
+        const field_ptr = switch (struct_ty.zigTypeTag()) {
+            .Struct => blk: {
+                const llvm_field_index = llvmFieldIndex(struct_ty, field_index);
+                break :blk self.builder.buildStructGEP(struct_llvm_val, llvm_field_index, "");
+            },
+            .Union => blk: {
+                const llvm_field_ty = try self.dg.llvmType(field_ty);
+                const target = self.dg.module.getTarget();
+                const layout = struct_ty.unionGetLayout(target);
+                const payload_index = @boolToInt(layout.tag_align >= layout.payload_align);
+                const union_field_ptr = self.builder.buildStructGEP(struct_llvm_val, payload_index, "");
+                break :blk self.builder.buildBitCast(union_field_ptr, llvm_field_ty.pointerType(0), "");
+            },
+            else => unreachable,
+        };
+
+        if (isByRef(field_ty)) {
+            return field_ptr;
         } else {
-            return self.builder.buildExtractValue(struct_llvm_val, field_index, "");
+            return self.builder.buildLoad(field_ptr, "");
         }
     }
 
src/Sema.zig
@@ -300,7 +300,7 @@ pub const Block = struct {
                         .ty = ty,
                         .payload = try block.sema.addExtra(Air.StructField{
                             .struct_operand = struct_ptr,
-                            .field_index = @intCast(u32, field_index),
+                            .field_index = field_index,
                         }),
                     } },
                 });
@@ -315,6 +315,24 @@ pub const Block = struct {
         });
     }
 
+    pub fn addStructFieldVal(
+        block: *Block,
+        struct_val: Air.Inst.Ref,
+        field_index: u32,
+        field_ty: Type,
+    ) !Air.Inst.Ref {
+        return block.addInst(.{
+            .tag = .struct_field_val,
+            .data = .{ .ty_pl = .{
+                .ty = try block.sema.addType(field_ty),
+                .payload = try block.sema.addExtra(Air.StructField{
+                    .struct_operand = struct_val,
+                    .field_index = field_index,
+                }),
+            } },
+        });
+    }
+
     pub fn addInst(block: *Block, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Ref {
         return Air.indexToRef(try block.addInstAsIndex(inst));
     }
@@ -11261,8 +11279,10 @@ fn structFieldVal(
     const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_ty);
     const struct_obj = struct_ty.castTag(.@"struct").?.data;
 
-    const field_index = struct_obj.fields.getIndex(field_name) orelse
+    const field_index_big = struct_obj.fields.getIndex(field_name) orelse
         return sema.failWithBadFieldAccess(block, struct_obj, field_name_src, field_name);
+    const field_index = @intCast(u32, field_index_big);
+
     const field = struct_obj.fields.values()[field_index];
 
     if (try sema.resolveMaybeUndefVal(block, src, struct_byval)) |struct_val| {
@@ -11273,16 +11293,7 @@ fn structFieldVal(
     }
 
     try sema.requireRuntimeBlock(block, src);
-    return block.addInst(.{
-        .tag = .struct_field_val,
-        .data = .{ .ty_pl = .{
-            .ty = try sema.addType(field.ty),
-            .payload = try sema.addExtra(Air.StructField{
-                .struct_operand = struct_byval,
-                .field_index = @intCast(u32, field_index),
-            }),
-        } },
-    });
+    return block.addStructFieldVal(struct_byval, field_index, field.ty);
 }
 
 fn unionFieldPtr(
@@ -11341,8 +11352,9 @@ fn unionFieldVal(
     const union_ty = try sema.resolveTypeFields(block, src, unresolved_union_ty);
     const union_obj = union_ty.cast(Type.Payload.Union).?.data;
 
-    const field_index = union_obj.fields.getIndex(field_name) orelse
+    const field_index_big = union_obj.fields.getIndex(field_name) orelse
         return sema.failWithBadUnionFieldAccess(block, union_obj, field_name_src, field_name);
+    const field_index = @intCast(u32, field_index_big);
 
     const field = union_obj.fields.values()[field_index];
 
@@ -11355,7 +11367,7 @@ fn unionFieldVal(
     }
 
     try sema.requireRuntimeBlock(block, src);
-    return sema.fail(block, src, "TODO implement runtime union field access", .{});
+    return block.addStructFieldVal(union_byval, field_index, field.ty);
 }
 
 fn elemPtr(