aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-10-17 17:02:20 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-10-17 17:02:20 -0700
commite9d1e5e533d12abe14582736d90e4cb173addc56 (patch)
treecb284bafd08c6287cb2ea50312d2cb13f4c91091
parent07691db3ae061d8122f6c53c1f34c2fb0df2f7ef (diff)
downloadzig-e9d1e5e533d12abe14582736d90e4cb173addc56.tar.gz
zig-e9d1e5e533d12abe14582736d90e4cb173addc56.zip
stage2: LLVM backend: lower constant field/elem ptrs
-rw-r--r--src/codegen/llvm.zig85
-rw-r--r--test/behavior.zig3
-rw-r--r--test/behavior/null.zig39
-rw-r--r--test/behavior/null_stage1.zig37
4 files changed, 125 insertions, 39 deletions
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index e8bfbef587..68b0f6b635 100644
--- a/src/codegen/llvm.zig
+++ b/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
diff --git a/test/behavior.zig b/test/behavior.zig
index f94f47c703..c728825621 100644
--- a/test/behavior.zig
+++ b/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");
diff --git a/test/behavior/null.zig b/test/behavior/null.zig
index 3bd652772b..98018c79bc 100644
--- a/test/behavior/null.zig
+++ b/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;
diff --git a/test/behavior/null_stage1.zig b/test/behavior/null_stage1.zig
new file mode 100644
index 0000000000..2b8feea242
--- /dev/null
+++ b/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,
+};