Commit e9d1e5e533

Andrew Kelley <andrew@ziglang.org>
2021-10-18 02:02:20
stage2: LLVM backend: lower constant field/elem ptrs
1 parent 07691db
Changed files (4)
src/codegen/llvm.zig
@@ -1085,6 +1085,26 @@ pub const DeclGen = struct {
                     const llvm_int = llvm_usize.constInt(tv.val.toUnsignedInt(), .False);
                     return llvm_int.constIntToPtr(try self.llvmType(tv.ty));
                 },
+                .field_ptr => {
+                    const field_ptr = tv.val.castTag(.field_ptr).?.data;
+                    const parent_ptr = try self.lowerParentPtr(field_ptr.container_ptr);
+                    const llvm_u32 = self.context.intType(32);
+                    const indices: [2]*const llvm.Value = .{
+                        llvm_u32.constInt(0, .False),
+                        llvm_u32.constInt(field_ptr.field_index, .False),
+                    };
+                    return parent_ptr.constInBoundsGEP(&indices, indices.len);
+                },
+                .elem_ptr => {
+                    const elem_ptr = tv.val.castTag(.elem_ptr).?.data;
+                    const parent_ptr = try self.lowerParentPtr(elem_ptr.array_ptr);
+                    const llvm_usize = try self.llvmType(Type.usize);
+                    const indices: [2]*const llvm.Value = .{
+                        llvm_usize.constInt(0, .False),
+                        llvm_usize.constInt(elem_ptr.index, .False),
+                    };
+                    return parent_ptr.constInBoundsGEP(&indices, indices.len);
+                },
                 else => |tag| return self.todo("implement const of pointer type '{}' ({})", .{ tv.ty, tag }),
             },
             .Array => switch (tv.val.tag()) {
@@ -1298,6 +1318,68 @@ pub const DeclGen = struct {
         }
     }
 
+    const ParentPtr = struct {
+        ty: Type,
+        llvm_ptr: *const llvm.Value,
+    };
+
+    fn lowerParentPtrDecl(
+        dg: *DeclGen,
+        ptr_val: Value,
+        decl: *Module.Decl,
+    ) Error!ParentPtr {
+        var ptr_ty_payload: Type.Payload.ElemType = .{
+            .base = .{ .tag = .single_mut_pointer },
+            .data = decl.ty,
+        };
+        const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
+        const llvm_ptr = try dg.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl);
+        return ParentPtr{
+            .llvm_ptr = llvm_ptr,
+            .ty = decl.ty,
+        };
+    }
+
+    fn lowerParentPtr(dg: *DeclGen, ptr_val: Value) Error!*const llvm.Value {
+        switch (ptr_val.tag()) {
+            .decl_ref_mut => {
+                const decl = ptr_val.castTag(.decl_ref_mut).?.data.decl;
+                return (try dg.lowerParentPtrDecl(ptr_val, decl)).llvm_ptr;
+            },
+            .decl_ref => {
+                const decl = ptr_val.castTag(.decl_ref).?.data;
+                return (try dg.lowerParentPtrDecl(ptr_val, decl)).llvm_ptr;
+            },
+            .variable => {
+                const decl = ptr_val.castTag(.variable).?.data.owner_decl;
+                return (try dg.lowerParentPtrDecl(ptr_val, decl)).llvm_ptr;
+            },
+            .field_ptr => {
+                const field_ptr = ptr_val.castTag(.field_ptr).?.data;
+                const parent_ptr = try dg.lowerParentPtr(field_ptr.container_ptr);
+                const llvm_u32 = dg.context.intType(32);
+                const indices: [2]*const llvm.Value = .{
+                    llvm_u32.constInt(0, .False),
+                    llvm_u32.constInt(field_ptr.field_index, .False),
+                };
+                return parent_ptr.constInBoundsGEP(&indices, indices.len);
+            },
+            .elem_ptr => {
+                const elem_ptr = ptr_val.castTag(.elem_ptr).?.data;
+                const parent_ptr = try dg.lowerParentPtr(elem_ptr.array_ptr);
+                const llvm_usize = try dg.llvmType(Type.usize);
+                const indices: [2]*const llvm.Value = .{
+                    llvm_usize.constInt(0, .False),
+                    llvm_usize.constInt(elem_ptr.index, .False),
+                };
+                return parent_ptr.constInBoundsGEP(&indices, indices.len);
+            },
+            .opt_payload_ptr => return dg.todo("implement lowerParentPtr for optional payload", .{}),
+            .eu_payload_ptr => return dg.todo("implement lowerParentPtr for error union payload", .{}),
+            else => unreachable,
+        }
+    }
+
     fn lowerDeclRefValue(
         self: *DeclGen,
         tv: TypedValue,
@@ -1323,12 +1405,13 @@ pub const DeclGen = struct {
             return self.context.constStruct(&fields, fields.len, .False);
         }
 
-        decl.alive = true;
         const llvm_type = try self.llvmType(tv.ty);
         if (!tv.ty.childType().hasCodeGenBits()) {
             return self.lowerPtrToVoid(tv.ty);
         }
 
+        decl.alive = true;
+
         const llvm_val = if (decl.ty.zigTypeTag() == .Fn)
             try self.resolveLlvmFunction(decl)
         else
test/behavior/null.zig
@@ -1,4 +1,5 @@
-const expect = @import("std").testing.expect;
+const std = @import("std");
+const expect = std.testing.expect;
 
 test "optional type" {
     const x: ?bool = true;
@@ -58,31 +59,6 @@ fn foo(x: ?i32) ?bool {
     return value > 1234;
 }
 
-test "if var maybe pointer" {
-    try expect(shouldBeAPlus1(Particle{
-        .a = 14,
-        .b = 1,
-        .c = 1,
-        .d = 1,
-    }) == 15);
-}
-fn shouldBeAPlus1(p: Particle) u64 {
-    var maybe_particle: ?Particle = p;
-    if (maybe_particle) |*particle| {
-        particle.a += 1;
-    }
-    if (maybe_particle) |particle| {
-        return particle.a;
-    }
-    return 0;
-}
-const Particle = struct {
-    a: u64,
-    b: u64,
-    c: u64,
-    d: u64,
-};
-
 test "null literal outside function" {
     const is_null = here_is_a_null_literal.context == null;
     try expect(is_null);
@@ -146,17 +122,6 @@ test "null with default unwrap" {
     try expect(x == 1);
 }
 
-test "optional types" {
-    comptime {
-        const opt_type_struct = StructWithOptionalType{ .t = u8 };
-        try expect(opt_type_struct.t != null and opt_type_struct.t.? == u8);
-    }
-}
-
-const StructWithOptionalType = struct {
-    t: ?type,
-};
-
 test "optional pointer to 0 bit type null value at runtime" {
     const EmptyStruct = struct {};
     var x: ?*EmptyStruct = null;
test/behavior/null_stage1.zig
@@ -0,0 +1,37 @@
+const expect = @import("std").testing.expect;
+
+test "if var maybe pointer" {
+    try expect(shouldBeAPlus1(Particle{
+        .a = 14,
+        .b = 1,
+        .c = 1,
+        .d = 1,
+    }) == 15);
+}
+fn shouldBeAPlus1(p: Particle) u64 {
+    var maybe_particle: ?Particle = p;
+    if (maybe_particle) |*particle| {
+        particle.a += 1;
+    }
+    if (maybe_particle) |particle| {
+        return particle.a;
+    }
+    return 0;
+}
+const Particle = struct {
+    a: u64,
+    b: u64,
+    c: u64,
+    d: u64,
+};
+
+test "optional types" {
+    comptime {
+        const opt_type_struct = StructWithOptionalType{ .t = u8 };
+        try expect(opt_type_struct.t != null and opt_type_struct.t.? == u8);
+    }
+}
+
+const StructWithOptionalType = struct {
+    t: ?type,
+};
test/behavior.zig
@@ -39,6 +39,7 @@ test {
     _ = @import("behavior/math.zig");
     _ = @import("behavior/maximum_minimum.zig");
     _ = @import("behavior/member_func.zig");
+    _ = @import("behavior/null.zig");
     _ = @import("behavior/optional.zig");
     _ = @import("behavior/pointers.zig");
     _ = @import("behavior/pub_enum.zig");
@@ -137,7 +138,7 @@ test {
         _ = @import("behavior/misc.zig");
         _ = @import("behavior/muladd.zig");
         _ = @import("behavior/namespace_depends_on_compile_var.zig");
-        _ = @import("behavior/null.zig");
+        _ = @import("behavior/null_stage1.zig");
         _ = @import("behavior/optional_stage1.zig");
         _ = @import("behavior/pointers_stage1.zig");
         _ = @import("behavior/popcount.zig");