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 @@
11this is my WIP branch scratch pad, to be deleted before merging into master
22
33Merge TODO list:
4 * don't have an explicit dbg_stmt zir instruction - instead merge it with
5 var decl and assignment instructions, etc.
6 - make it set sema.src where appropriate
4 * uncomment the commented out stage2 tests
75 * remove the LazySrcLoc.todo tag
86 * update astgen.zig
97 * finish updating Sema.zig
108 * 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
149 * audit all the .unneeded src locations
1510 * audit the calls in codegen toSrcLocWithDecl specifically if there is inlined function
1611 calls from other files.
17 * uncomment the commented out stage2 tests
18 * memory leaks on --watch update
19 * memory leaks on test-stage2
2012
2113Performance optimizations to look into:
2214 * astgen: pass *GenZir as the first arg, not *Module
......@@ -41,3 +33,7 @@ Performance optimizations to look into:
4133 * in astgen, if a decl_val would be to a const variable or to a function, there could be
4234 a special zir.Inst.Ref form that means to refer to a decl as the operand. This
4335 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 {
169169 };
170170 }
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
172291 pub fn eql(a: Type, b: Type) bool {
173292 // As a shortcut, if the small tags / addresses match, we're done.
174293 if (a.tag_if_small_enough == b.tag_if_small_enough)
......@@ -191,25 +310,38 @@ pub const Type = extern union {
191310 return a.elemType().eql(b.elemType());
192311 },
193312 .Pointer => {
194 // Hot path for common case:
195 if (a.castPointer()) |a_payload| {
196 if (b.castPointer()) |b_payload| {
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)
313 const info_a = a.ptrInfo().data;
314 const info_b = b.ptrInfo().data;
315 if (!info_a.pointee_type.eql(info_b.pointee_type))
203316 return false;
204
205 const ptr_size_a = ptrSize(a);
206 const ptr_size_b = ptrSize(b);
207 if (ptr_size_a != ptr_size_b)
317 if (info_a.size != info_b.size)
318 return false;
319 if (info_a.mutable != info_b.mutable)
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)
208328 return false;
209329
210 std.debug.panic("TODO implement more pointer Type equality comparison: {} and {}", .{
211 a, b,
212 });
330 const sentinel_a = info_a.sentinel;
331 const sentinel_b = info_b.sentinel;
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;
213345 },
214346 .Int => {
215347 // Detect that e.g. u64 != usize, even if the bits match on a particular target.
......@@ -844,6 +976,35 @@ pub const Type = extern union {
844976 return fast_result;
845977 }
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
8471008 /// Asserts that hasCodeGenBits() is true.
8481009 pub fn abiAlignment(self: Type, target: Target) u32 {
8491010 return switch (self.tag()) {
......@@ -885,15 +1046,9 @@ pub const Type = extern union {
8851046 .mut_slice,
8861047 .optional_single_const_pointer,
8871048 .optional_single_mut_pointer,
1049 .pointer,
8881050 => 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
8971052 .c_short => return @divExact(CType.short.sizeInBits(target), 8),
8981053 .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8),
8991054 .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 {
15021502 "",
15031503 );
15041504
1505 //case.addCompareOutput(
1506 // \\export fn _start() noreturn {
1507 // \\ const a: anyerror!comptime_int = 42;
1508 // \\ const b: *const comptime_int = &(a catch unreachable);
1509 // \\ assert(b.* == 42);
1510 // \\
1511 // \\ exit();
1512 // \\}
1513 // \\fn assert(b: bool) void {
1514 // \\ if (!b) unreachable; // assertion failure
1515 // \\}
1516 // \\fn exit() noreturn {
1517 // \\ asm volatile ("syscall"
1518 // \\ :
1519 // \\ : [number] "{rax}" (231),
1520 // \\ [arg1] "{rdi}" (0)
1521 // \\ : "rcx", "r11", "memory"
1522 // \\ );
1523 // \\ unreachable;
1524 // \\}
1525 //, "");
1505 case.addCompareOutput(
1506 \\export fn _start() noreturn {
1507 \\ const a: anyerror!comptime_int = 42;
1508 \\ const b: *const comptime_int = &(a catch unreachable);
1509 \\ assert(b.* == 42);
1510 \\
1511 \\ exit();
1512 \\}
1513 \\fn assert(b: bool) void {
1514 \\ if (!b) unreachable; // assertion failure
1515 \\}
1516 \\fn exit() noreturn {
1517 \\ asm volatile ("syscall"
1518 \\ :
1519 \\ : [number] "{rax}" (231),
1520 \\ [arg1] "{rdi}" (0)
1521 \\ : "rcx", "r11", "memory"
1522 \\ );
1523 \\ unreachable;
1524 \\}
1525 , "");
15261526
15271527 case.addCompareOutput(
15281528 \\export fn _start() noreturn {