diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-10-17 17:02:20 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-10-17 17:02:20 -0700 |
| commit | e9d1e5e533d12abe14582736d90e4cb173addc56 (patch) | |
| tree | cb284bafd08c6287cb2ea50312d2cb13f4c91091 | |
| parent | 07691db3ae061d8122f6c53c1f34c2fb0df2f7ef (diff) | |
| download | zig-e9d1e5e533d12abe14582736d90e4cb173addc56.tar.gz zig-e9d1e5e533d12abe14582736d90e4cb173addc56.zip | |
stage2: LLVM backend: lower constant field/elem ptrs
| -rw-r--r-- | src/codegen/llvm.zig | 85 | ||||
| -rw-r--r-- | test/behavior.zig | 3 | ||||
| -rw-r--r-- | test/behavior/null.zig | 39 | ||||
| -rw-r--r-- | test/behavior/null_stage1.zig | 37 |
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, +}; |
