authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-27 23:55:19-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-27 23:55:19-07:00
log68f4eb0f67b6e5f7c20332e79c8e8decb07748ee
tree7830086e80412e46fecee38de9c6c43844dbc4be
parent95cc457d977c3a4671adfe61d482465cd262d17f

stage2: fully implement Type.eql for pointers

Also fixed abiAlignment - for pointers it was returning the abi alignment inside the type, rather than of the pointer itself. There is now `ptrAlignment` for getting the alignment inside the type of pointers.

3 files changed, 204 insertions(+), 53 deletions(-)

BRANCH_TODO+5-9
...@@ -1,22 +1,14 @@...@@ -1,22 +1,14 @@
1this is my WIP branch scratch pad, to be deleted before merging into master1this is my WIP branch scratch pad, to be deleted before merging into master
22
3Merge TODO list:3Merge TODO list:
4 * don't have an explicit dbg_stmt zir instruction - instead merge it with4 * uncomment the commented out stage2 tests
5 var decl and assignment instructions, etc.
6 - make it set sema.src where appropriate
7 * remove the LazySrcLoc.todo tag5 * remove the LazySrcLoc.todo tag
8 * update astgen.zig6 * update astgen.zig
9 * finish updating Sema.zig7 * finish updating Sema.zig
10 * finish implementing SrcLoc byteOffset function8 * finish implementing SrcLoc byteOffset function
11 * audit Module.zig for use of token_starts - it should only be when
12 resolving LazySrcLoc
13 * audit astgen.zig for use of token_starts - I think there should be no uses
14 * audit all the .unneeded src locations9 * audit all the .unneeded src locations
15 * audit the calls in codegen toSrcLocWithDecl specifically if there is inlined function10 * audit the calls in codegen toSrcLocWithDecl specifically if there is inlined function
16 calls from other files.11 calls from other files.
17 * uncomment the commented out stage2 tests
18 * memory leaks on --watch update
19 * memory leaks on test-stage2
2012
21Performance optimizations to look into:13Performance optimizations to look into:
22 * astgen: pass *GenZir as the first arg, not *Module14 * astgen: pass *GenZir as the first arg, not *Module
...@@ -41,3 +33,7 @@ Performance optimizations to look into:...@@ -41,3 +33,7 @@ Performance optimizations to look into:
41 * in astgen, if a decl_val would be to a const variable or to a function, there could be33 * in astgen, if a decl_val would be to a const variable or to a function, there could be
42 a special zir.Inst.Ref form that means to refer to a decl as the operand. This34 a special zir.Inst.Ref form that means to refer to a decl as the operand. This
43 would elide all the decl_val instructions in the ZIR.35 would elide all the decl_val instructions in the ZIR.
36 * don't have an explicit dbg_stmt zir instruction - instead merge it with
37 var decl and assignment instructions, etc.
38 - make it set sema.src where appropriate
39 * look into not emitting redundant dbg stmts to TZIR
src/type.zig+178-23
...@@ -169,6 +169,125 @@ pub const Type = extern union {...@@ -169,6 +169,125 @@ pub const Type = extern union {
169 };169 };
170 }170 }
171171
172 pub fn ptrInfo(self: Type) Payload.Pointer {
173 switch (self.tag()) {
174 .single_const_pointer_to_comptime_int => return .{ .data = .{
175 .pointee_type = Type.initTag(.comptime_int),
176 .sentinel = null,
177 .@"align" = 0,
178 .bit_offset = 0,
179 .host_size = 0,
180 .@"allowzero" = false,
181 .mutable = false,
182 .@"volatile" = false,
183 .size = .One,
184 } },
185 .const_slice_u8 => return .{ .data = .{
186 .pointee_type = Type.initTag(.u8),
187 .sentinel = null,
188 .@"align" = 0,
189 .bit_offset = 0,
190 .host_size = 0,
191 .@"allowzero" = false,
192 .mutable = false,
193 .@"volatile" = false,
194 .size = .Slice,
195 } },
196 .single_const_pointer => return .{ .data = .{
197 .pointee_type = self.castPointer().?.data,
198 .sentinel = null,
199 .@"align" = 0,
200 .bit_offset = 0,
201 .host_size = 0,
202 .@"allowzero" = false,
203 .mutable = false,
204 .@"volatile" = false,
205 .size = .One,
206 } },
207 .single_mut_pointer => return .{ .data = .{
208 .pointee_type = self.castPointer().?.data,
209 .sentinel = null,
210 .@"align" = 0,
211 .bit_offset = 0,
212 .host_size = 0,
213 .@"allowzero" = false,
214 .mutable = true,
215 .@"volatile" = false,
216 .size = .One,
217 } },
218 .many_const_pointer => return .{ .data = .{
219 .pointee_type = self.castPointer().?.data,
220 .sentinel = null,
221 .@"align" = 0,
222 .bit_offset = 0,
223 .host_size = 0,
224 .@"allowzero" = false,
225 .mutable = false,
226 .@"volatile" = false,
227 .size = .Many,
228 } },
229 .many_mut_pointer => return .{ .data = .{
230 .pointee_type = self.castPointer().?.data,
231 .sentinel = null,
232 .@"align" = 0,
233 .bit_offset = 0,
234 .host_size = 0,
235 .@"allowzero" = false,
236 .mutable = true,
237 .@"volatile" = false,
238 .size = .Many,
239 } },
240 .c_const_pointer => return .{ .data = .{
241 .pointee_type = self.castPointer().?.data,
242 .sentinel = null,
243 .@"align" = 0,
244 .bit_offset = 0,
245 .host_size = 0,
246 .@"allowzero" = false,
247 .mutable = false,
248 .@"volatile" = false,
249 .size = .C,
250 } },
251 .c_mut_pointer => return .{ .data = .{
252 .pointee_type = self.castPointer().?.data,
253 .sentinel = null,
254 .@"align" = 0,
255 .bit_offset = 0,
256 .host_size = 0,
257 .@"allowzero" = false,
258 .mutable = true,
259 .@"volatile" = false,
260 .size = .C,
261 } },
262 .const_slice => return .{ .data = .{
263 .pointee_type = self.castPointer().?.data,
264 .sentinel = null,
265 .@"align" = 0,
266 .bit_offset = 0,
267 .host_size = 0,
268 .@"allowzero" = false,
269 .mutable = false,
270 .@"volatile" = false,
271 .size = .Slice,
272 } },
273 .mut_slice => return .{ .data = .{
274 .pointee_type = self.castPointer().?.data,
275 .sentinel = null,
276 .@"align" = 0,
277 .bit_offset = 0,
278 .host_size = 0,
279 .@"allowzero" = false,
280 .mutable = true,
281 .@"volatile" = false,
282 .size = .Slice,
283 } },
284
285 .pointer => return self.castTag(.pointer).?.*,
286
287 else => unreachable,
288 }
289 }
290
172 pub fn eql(a: Type, b: Type) bool {291 pub fn eql(a: Type, b: Type) bool {
173 // As a shortcut, if the small tags / addresses match, we're done.292 // As a shortcut, if the small tags / addresses match, we're done.
174 if (a.tag_if_small_enough == b.tag_if_small_enough)293 if (a.tag_if_small_enough == b.tag_if_small_enough)
...@@ -191,25 +310,38 @@ pub const Type = extern union {...@@ -191,25 +310,38 @@ pub const Type = extern union {
191 return a.elemType().eql(b.elemType());310 return a.elemType().eql(b.elemType());
192 },311 },
193 .Pointer => {312 .Pointer => {
194 // Hot path for common case:313 const info_a = a.ptrInfo().data;
195 if (a.castPointer()) |a_payload| {314 const info_b = b.ptrInfo().data;
196 if (b.castPointer()) |b_payload| {315 if (!info_a.pointee_type.eql(info_b.pointee_type))
197 return a.tag() == b.tag() and eql(a_payload.data, b_payload.data);
198 }
199 }
200 const is_slice_a = isSlice(a);
201 const is_slice_b = isSlice(b);
202 if (is_slice_a != is_slice_b)
203 return false;316 return false;
204317 if (info_a.size != info_b.size)
205 const ptr_size_a = ptrSize(a);318 return false;
206 const ptr_size_b = ptrSize(b);319 if (info_a.mutable != info_b.mutable)
207 if (ptr_size_a != ptr_size_b)320 return false;
321 if (info_a.@"volatile" != info_b.@"volatile")
322 return false;
323 if (info_a.@"allowzero" != info_b.@"allowzero")
324 return false;
325 if (info_a.bit_offset != info_b.bit_offset)
326 return false;
327 if (info_a.host_size != info_b.host_size)
208 return false;328 return false;
209329
210 std.debug.panic("TODO implement more pointer Type equality comparison: {} and {}", .{330 const sentinel_a = info_a.sentinel;
211 a, b,331 const sentinel_b = info_b.sentinel;
212 });332 if (sentinel_a) |sa| {
333 if (sentinel_b) |sb| {
334 if (!sa.eql(sb))
335 return false;
336 } else {
337 return false;
338 }
339 } else {
340 if (sentinel_b != null)
341 return false;
342 }
343
344 return true;
213 },345 },
214 .Int => {346 .Int => {
215 // Detect that e.g. u64 != usize, even if the bits match on a particular target.347 // Detect that e.g. u64 != usize, even if the bits match on a particular target.
...@@ -844,6 +976,35 @@ pub const Type = extern union {...@@ -844,6 +976,35 @@ pub const Type = extern union {
844 return fast_result;976 return fast_result;
845 }977 }
846978
979 pub fn ptrAlignment(self: Type, target: Target) u32 {
980 switch (self.tag()) {
981 .single_const_pointer,
982 .single_mut_pointer,
983 .many_const_pointer,
984 .many_mut_pointer,
985 .c_const_pointer,
986 .c_mut_pointer,
987 .const_slice,
988 .mut_slice,
989 .optional_single_const_pointer,
990 .optional_single_mut_pointer,
991 => return self.cast(Payload.ElemType).?.data.abiAlignment(target),
992
993 .const_slice_u8 => return 1,
994
995 .pointer => {
996 const ptr_info = self.castTag(.pointer).?.data;
997 if (ptr_info.@"align" != 0) {
998 return ptr_info.@"align";
999 } else {
1000 return ptr_info.pointee_type.abiAlignment();
1001 }
1002 },
1003
1004 else => unreachable,
1005 }
1006 }
1007
847 /// Asserts that hasCodeGenBits() is true.1008 /// Asserts that hasCodeGenBits() is true.
848 pub fn abiAlignment(self: Type, target: Target) u32 {1009 pub fn abiAlignment(self: Type, target: Target) u32 {
849 return switch (self.tag()) {1010 return switch (self.tag()) {
...@@ -885,15 +1046,9 @@ pub const Type = extern union {...@@ -885,15 +1046,9 @@ pub const Type = extern union {
885 .mut_slice,1046 .mut_slice,
886 .optional_single_const_pointer,1047 .optional_single_const_pointer,
887 .optional_single_mut_pointer,1048 .optional_single_mut_pointer,
1049 .pointer,
888 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),1050 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
8891051
890 .pointer => {
891 const payload = self.castTag(.pointer).?.data;
892
893 if (payload.@"align" != 0) return payload.@"align";
894 return @divExact(target.cpu.arch.ptrBitWidth(), 8);
895 },
896
897 .c_short => return @divExact(CType.short.sizeInBits(target), 8),1052 .c_short => return @divExact(CType.short.sizeInBits(target), 8),
898 .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8),1053 .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8),
899 .c_int => return @divExact(CType.int.sizeInBits(target), 8),1054 .c_int => return @divExact(CType.int.sizeInBits(target), 8),
test/stage2/test.zig+21-21
...@@ -1502,27 +1502,27 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1502,27 +1502,27 @@ pub fn addCases(ctx: *TestContext) !void {
1502 "",1502 "",
1503 );1503 );
15041504
1505 //case.addCompareOutput(1505 case.addCompareOutput(
1506 // \\export fn _start() noreturn {1506 \\export fn _start() noreturn {
1507 // \\ const a: anyerror!comptime_int = 42;1507 \\ const a: anyerror!comptime_int = 42;
1508 // \\ const b: *const comptime_int = &(a catch unreachable);1508 \\ const b: *const comptime_int = &(a catch unreachable);
1509 // \\ assert(b.* == 42);1509 \\ assert(b.* == 42);
1510 // \\1510 \\
1511 // \\ exit();1511 \\ exit();
1512 // \\}1512 \\}
1513 // \\fn assert(b: bool) void {1513 \\fn assert(b: bool) void {
1514 // \\ if (!b) unreachable; // assertion failure1514 \\ if (!b) unreachable; // assertion failure
1515 // \\}1515 \\}
1516 // \\fn exit() noreturn {1516 \\fn exit() noreturn {
1517 // \\ asm volatile ("syscall"1517 \\ asm volatile ("syscall"
1518 // \\ :1518 \\ :
1519 // \\ : [number] "{rax}" (231),1519 \\ : [number] "{rax}" (231),
1520 // \\ [arg1] "{rdi}" (0)1520 \\ [arg1] "{rdi}" (0)
1521 // \\ : "rcx", "r11", "memory"1521 \\ : "rcx", "r11", "memory"
1522 // \\ );1522 \\ );
1523 // \\ unreachable;1523 \\ unreachable;
1524 // \\}1524 \\}
1525 //, "");1525 , "");
15261526
1527 case.addCompareOutput(1527 case.addCompareOutput(
1528 \\export fn _start() noreturn {1528 \\export fn _start() noreturn {