authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-17 17:02:20-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-17 17:02:20-07:00
loge9d1e5e533d12abe14582736d90e4cb173addc56
treecb284bafd08c6287cb2ea50312d2cb13f4c91091
parent07691db3ae061d8122f6c53c1f34c2fb0df2f7ef

stage2: LLVM backend: lower constant field/elem ptrs


4 files changed, 125 insertions(+), 39 deletions(-)

src/codegen/llvm.zig+84-1
...@@ -1085,6 +1085,26 @@ pub const DeclGen = struct {...@@ -1085,6 +1085,26 @@ pub const DeclGen = struct {
1085 const llvm_int = llvm_usize.constInt(tv.val.toUnsignedInt(), .False);1085 const llvm_int = llvm_usize.constInt(tv.val.toUnsignedInt(), .False);
1086 return llvm_int.constIntToPtr(try self.llvmType(tv.ty));1086 return llvm_int.constIntToPtr(try self.llvmType(tv.ty));
1087 },1087 },
1088 .field_ptr => {
1089 const field_ptr = tv.val.castTag(.field_ptr).?.data;
1090 const parent_ptr = try self.lowerParentPtr(field_ptr.container_ptr);
1091 const llvm_u32 = self.context.intType(32);
1092 const indices: [2]*const llvm.Value = .{
1093 llvm_u32.constInt(0, .False),
1094 llvm_u32.constInt(field_ptr.field_index, .False),
1095 };
1096 return parent_ptr.constInBoundsGEP(&indices, indices.len);
1097 },
1098 .elem_ptr => {
1099 const elem_ptr = tv.val.castTag(.elem_ptr).?.data;
1100 const parent_ptr = try self.lowerParentPtr(elem_ptr.array_ptr);
1101 const llvm_usize = try self.llvmType(Type.usize);
1102 const indices: [2]*const llvm.Value = .{
1103 llvm_usize.constInt(0, .False),
1104 llvm_usize.constInt(elem_ptr.index, .False),
1105 };
1106 return parent_ptr.constInBoundsGEP(&indices, indices.len);
1107 },
1088 else => |tag| return self.todo("implement const of pointer type '{}' ({})", .{ tv.ty, tag }),1108 else => |tag| return self.todo("implement const of pointer type '{}' ({})", .{ tv.ty, tag }),
1089 },1109 },
1090 .Array => switch (tv.val.tag()) {1110 .Array => switch (tv.val.tag()) {
...@@ -1298,6 +1318,68 @@ pub const DeclGen = struct {...@@ -1298,6 +1318,68 @@ pub const DeclGen = struct {
1298 }1318 }
1299 }1319 }
13001320
1321 const ParentPtr = struct {
1322 ty: Type,
1323 llvm_ptr: *const llvm.Value,
1324 };
1325
1326 fn lowerParentPtrDecl(
1327 dg: *DeclGen,
1328 ptr_val: Value,
1329 decl: *Module.Decl,
1330 ) Error!ParentPtr {
1331 var ptr_ty_payload: Type.Payload.ElemType = .{
1332 .base = .{ .tag = .single_mut_pointer },
1333 .data = decl.ty,
1334 };
1335 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
1336 const llvm_ptr = try dg.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl);
1337 return ParentPtr{
1338 .llvm_ptr = llvm_ptr,
1339 .ty = decl.ty,
1340 };
1341 }
1342
1343 fn lowerParentPtr(dg: *DeclGen, ptr_val: Value) Error!*const llvm.Value {
1344 switch (ptr_val.tag()) {
1345 .decl_ref_mut => {
1346 const decl = ptr_val.castTag(.decl_ref_mut).?.data.decl;
1347 return (try dg.lowerParentPtrDecl(ptr_val, decl)).llvm_ptr;
1348 },
1349 .decl_ref => {
1350 const decl = ptr_val.castTag(.decl_ref).?.data;
1351 return (try dg.lowerParentPtrDecl(ptr_val, decl)).llvm_ptr;
1352 },
1353 .variable => {
1354 const decl = ptr_val.castTag(.variable).?.data.owner_decl;
1355 return (try dg.lowerParentPtrDecl(ptr_val, decl)).llvm_ptr;
1356 },
1357 .field_ptr => {
1358 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
1359 const parent_ptr = try dg.lowerParentPtr(field_ptr.container_ptr);
1360 const llvm_u32 = dg.context.intType(32);
1361 const indices: [2]*const llvm.Value = .{
1362 llvm_u32.constInt(0, .False),
1363 llvm_u32.constInt(field_ptr.field_index, .False),
1364 };
1365 return parent_ptr.constInBoundsGEP(&indices, indices.len);
1366 },
1367 .elem_ptr => {
1368 const elem_ptr = ptr_val.castTag(.elem_ptr).?.data;
1369 const parent_ptr = try dg.lowerParentPtr(elem_ptr.array_ptr);
1370 const llvm_usize = try dg.llvmType(Type.usize);
1371 const indices: [2]*const llvm.Value = .{
1372 llvm_usize.constInt(0, .False),
1373 llvm_usize.constInt(elem_ptr.index, .False),
1374 };
1375 return parent_ptr.constInBoundsGEP(&indices, indices.len);
1376 },
1377 .opt_payload_ptr => return dg.todo("implement lowerParentPtr for optional payload", .{}),
1378 .eu_payload_ptr => return dg.todo("implement lowerParentPtr for error union payload", .{}),
1379 else => unreachable,
1380 }
1381 }
1382
1301 fn lowerDeclRefValue(1383 fn lowerDeclRefValue(
1302 self: *DeclGen,1384 self: *DeclGen,
1303 tv: TypedValue,1385 tv: TypedValue,
...@@ -1323,12 +1405,13 @@ pub const DeclGen = struct {...@@ -1323,12 +1405,13 @@ pub const DeclGen = struct {
1323 return self.context.constStruct(&fields, fields.len, .False);1405 return self.context.constStruct(&fields, fields.len, .False);
1324 }1406 }
13251407
1326 decl.alive = true;
1327 const llvm_type = try self.llvmType(tv.ty);1408 const llvm_type = try self.llvmType(tv.ty);
1328 if (!tv.ty.childType().hasCodeGenBits()) {1409 if (!tv.ty.childType().hasCodeGenBits()) {
1329 return self.lowerPtrToVoid(tv.ty);1410 return self.lowerPtrToVoid(tv.ty);
1330 }1411 }
13311412
1413 decl.alive = true;
1414
1332 const llvm_val = if (decl.ty.zigTypeTag() == .Fn)1415 const llvm_val = if (decl.ty.zigTypeTag() == .Fn)
1333 try self.resolveLlvmFunction(decl)1416 try self.resolveLlvmFunction(decl)
1334 else1417 else
test/behavior.zig+2-1
...@@ -39,6 +39,7 @@ test {...@@ -39,6 +39,7 @@ test {
39 _ = @import("behavior/math.zig");39 _ = @import("behavior/math.zig");
40 _ = @import("behavior/maximum_minimum.zig");40 _ = @import("behavior/maximum_minimum.zig");
41 _ = @import("behavior/member_func.zig");41 _ = @import("behavior/member_func.zig");
42 _ = @import("behavior/null.zig");
42 _ = @import("behavior/optional.zig");43 _ = @import("behavior/optional.zig");
43 _ = @import("behavior/pointers.zig");44 _ = @import("behavior/pointers.zig");
44 _ = @import("behavior/pub_enum.zig");45 _ = @import("behavior/pub_enum.zig");
...@@ -137,7 +138,7 @@ test {...@@ -137,7 +138,7 @@ test {
137 _ = @import("behavior/misc.zig");138 _ = @import("behavior/misc.zig");
138 _ = @import("behavior/muladd.zig");139 _ = @import("behavior/muladd.zig");
139 _ = @import("behavior/namespace_depends_on_compile_var.zig");140 _ = @import("behavior/namespace_depends_on_compile_var.zig");
140 _ = @import("behavior/null.zig");141 _ = @import("behavior/null_stage1.zig");
141 _ = @import("behavior/optional_stage1.zig");142 _ = @import("behavior/optional_stage1.zig");
142 _ = @import("behavior/pointers_stage1.zig");143 _ = @import("behavior/pointers_stage1.zig");
143 _ = @import("behavior/popcount.zig");144 _ = @import("behavior/popcount.zig");
test/behavior/null.zig+2-37
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const expect = @import("std").testing.expect;1const std = @import("std");
2const expect = std.testing.expect;
23
3test "optional type" {4test "optional type" {
4 const x: ?bool = true;5 const x: ?bool = true;
...@@ -58,31 +59,6 @@ fn foo(x: ?i32) ?bool {...@@ -58,31 +59,6 @@ fn foo(x: ?i32) ?bool {
58 return value > 1234;59 return value > 1234;
59}60}
6061
61test "if var maybe pointer" {
62 try expect(shouldBeAPlus1(Particle{
63 .a = 14,
64 .b = 1,
65 .c = 1,
66 .d = 1,
67 }) == 15);
68}
69fn shouldBeAPlus1(p: Particle) u64 {
70 var maybe_particle: ?Particle = p;
71 if (maybe_particle) |*particle| {
72 particle.a += 1;
73 }
74 if (maybe_particle) |particle| {
75 return particle.a;
76 }
77 return 0;
78}
79const Particle = struct {
80 a: u64,
81 b: u64,
82 c: u64,
83 d: u64,
84};
85
86test "null literal outside function" {62test "null literal outside function" {
87 const is_null = here_is_a_null_literal.context == null;63 const is_null = here_is_a_null_literal.context == null;
88 try expect(is_null);64 try expect(is_null);
...@@ -146,17 +122,6 @@ test "null with default unwrap" {...@@ -146,17 +122,6 @@ test "null with default unwrap" {
146 try expect(x == 1);122 try expect(x == 1);
147}123}
148124
149test "optional types" {
150 comptime {
151 const opt_type_struct = StructWithOptionalType{ .t = u8 };
152 try expect(opt_type_struct.t != null and opt_type_struct.t.? == u8);
153 }
154}
155
156const StructWithOptionalType = struct {
157 t: ?type,
158};
159
160test "optional pointer to 0 bit type null value at runtime" {125test "optional pointer to 0 bit type null value at runtime" {
161 const EmptyStruct = struct {};126 const EmptyStruct = struct {};
162 var x: ?*EmptyStruct = null;127 var x: ?*EmptyStruct = null;
test/behavior/null_stage1.zig created+37
...@@ -0,0 +1,37 @@
1const expect = @import("std").testing.expect;
2
3test "if var maybe pointer" {
4 try expect(shouldBeAPlus1(Particle{
5 .a = 14,
6 .b = 1,
7 .c = 1,
8 .d = 1,
9 }) == 15);
10}
11fn shouldBeAPlus1(p: Particle) u64 {
12 var maybe_particle: ?Particle = p;
13 if (maybe_particle) |*particle| {
14 particle.a += 1;
15 }
16 if (maybe_particle) |particle| {
17 return particle.a;
18 }
19 return 0;
20}
21const Particle = struct {
22 a: u64,
23 b: u64,
24 c: u64,
25 d: u64,
26};
27
28test "optional types" {
29 comptime {
30 const opt_type_struct = StructWithOptionalType{ .t = u8 };
31 try expect(opt_type_struct.t != null and opt_type_struct.t.? == u8);
32 }
33}
34
35const StructWithOptionalType = struct {
36 t: ?type,
37};