From 68f4eb0f67b6e5f7c20332e79c8e8decb07748ee Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 27 Mar 2021 23:55:19 -0700 Subject: [PATCH] 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. --- BRANCH_TODO | 14 ++- src/type.zig | 201 ++++++++++++++++++++++++++++++++++++++----- test/stage2/test.zig | 42 ++++----- 3 files changed, 204 insertions(+), 53 deletions(-) diff --git a/BRANCH_TODO b/BRANCH_TODO index 96f7cd4f83..3c6ebdb769 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,22 +1,14 @@ this is my WIP branch scratch pad, to be deleted before merging into master Merge TODO list: - * don't have an explicit dbg_stmt zir instruction - instead merge it with - var decl and assignment instructions, etc. - - make it set sema.src where appropriate + * uncomment the commented out stage2 tests * remove the LazySrcLoc.todo tag * update astgen.zig * finish updating Sema.zig * finish implementing SrcLoc byteOffset function - * audit Module.zig for use of token_starts - it should only be when - resolving LazySrcLoc - * audit astgen.zig for use of token_starts - I think there should be no uses * audit all the .unneeded src locations * audit the calls in codegen toSrcLocWithDecl specifically if there is inlined function calls from other files. - * uncomment the commented out stage2 tests - * memory leaks on --watch update - * memory leaks on test-stage2 Performance optimizations to look into: * astgen: pass *GenZir as the first arg, not *Module @@ -41,3 +33,7 @@ Performance optimizations to look into: * in astgen, if a decl_val would be to a const variable or to a function, there could be a special zir.Inst.Ref form that means to refer to a decl as the operand. This would elide all the decl_val instructions in the ZIR. + * don't have an explicit dbg_stmt zir instruction - instead merge it with + var decl and assignment instructions, etc. + - make it set sema.src where appropriate + * look into not emitting redundant dbg stmts to TZIR diff --git a/src/type.zig b/src/type.zig index 331994fe1e..817fe171cc 100644 --- a/src/type.zig +++ b/src/type.zig @@ -169,6 +169,125 @@ pub const Type = extern union { }; } + pub fn ptrInfo(self: Type) Payload.Pointer { + switch (self.tag()) { + .single_const_pointer_to_comptime_int => return .{ .data = .{ + .pointee_type = Type.initTag(.comptime_int), + .sentinel = null, + .@"align" = 0, + .bit_offset = 0, + .host_size = 0, + .@"allowzero" = false, + .mutable = false, + .@"volatile" = false, + .size = .One, + } }, + .const_slice_u8 => return .{ .data = .{ + .pointee_type = Type.initTag(.u8), + .sentinel = null, + .@"align" = 0, + .bit_offset = 0, + .host_size = 0, + .@"allowzero" = false, + .mutable = false, + .@"volatile" = false, + .size = .Slice, + } }, + .single_const_pointer => return .{ .data = .{ + .pointee_type = self.castPointer().?.data, + .sentinel = null, + .@"align" = 0, + .bit_offset = 0, + .host_size = 0, + .@"allowzero" = false, + .mutable = false, + .@"volatile" = false, + .size = .One, + } }, + .single_mut_pointer => return .{ .data = .{ + .pointee_type = self.castPointer().?.data, + .sentinel = null, + .@"align" = 0, + .bit_offset = 0, + .host_size = 0, + .@"allowzero" = false, + .mutable = true, + .@"volatile" = false, + .size = .One, + } }, + .many_const_pointer => return .{ .data = .{ + .pointee_type = self.castPointer().?.data, + .sentinel = null, + .@"align" = 0, + .bit_offset = 0, + .host_size = 0, + .@"allowzero" = false, + .mutable = false, + .@"volatile" = false, + .size = .Many, + } }, + .many_mut_pointer => return .{ .data = .{ + .pointee_type = self.castPointer().?.data, + .sentinel = null, + .@"align" = 0, + .bit_offset = 0, + .host_size = 0, + .@"allowzero" = false, + .mutable = true, + .@"volatile" = false, + .size = .Many, + } }, + .c_const_pointer => return .{ .data = .{ + .pointee_type = self.castPointer().?.data, + .sentinel = null, + .@"align" = 0, + .bit_offset = 0, + .host_size = 0, + .@"allowzero" = false, + .mutable = false, + .@"volatile" = false, + .size = .C, + } }, + .c_mut_pointer => return .{ .data = .{ + .pointee_type = self.castPointer().?.data, + .sentinel = null, + .@"align" = 0, + .bit_offset = 0, + .host_size = 0, + .@"allowzero" = false, + .mutable = true, + .@"volatile" = false, + .size = .C, + } }, + .const_slice => return .{ .data = .{ + .pointee_type = self.castPointer().?.data, + .sentinel = null, + .@"align" = 0, + .bit_offset = 0, + .host_size = 0, + .@"allowzero" = false, + .mutable = false, + .@"volatile" = false, + .size = .Slice, + } }, + .mut_slice => return .{ .data = .{ + .pointee_type = self.castPointer().?.data, + .sentinel = null, + .@"align" = 0, + .bit_offset = 0, + .host_size = 0, + .@"allowzero" = false, + .mutable = true, + .@"volatile" = false, + .size = .Slice, + } }, + + .pointer => return self.castTag(.pointer).?.*, + + else => unreachable, + } + } + pub fn eql(a: Type, b: Type) bool { // As a shortcut, if the small tags / addresses match, we're done. if (a.tag_if_small_enough == b.tag_if_small_enough) @@ -191,25 +310,38 @@ pub const Type = extern union { return a.elemType().eql(b.elemType()); }, .Pointer => { - // Hot path for common case: - if (a.castPointer()) |a_payload| { - if (b.castPointer()) |b_payload| { - return a.tag() == b.tag() and eql(a_payload.data, b_payload.data); + const info_a = a.ptrInfo().data; + const info_b = b.ptrInfo().data; + if (!info_a.pointee_type.eql(info_b.pointee_type)) + return false; + if (info_a.size != info_b.size) + return false; + if (info_a.mutable != info_b.mutable) + return false; + if (info_a.@"volatile" != info_b.@"volatile") + return false; + if (info_a.@"allowzero" != info_b.@"allowzero") + return false; + if (info_a.bit_offset != info_b.bit_offset) + return false; + if (info_a.host_size != info_b.host_size) + return false; + + const sentinel_a = info_a.sentinel; + const sentinel_b = info_b.sentinel; + if (sentinel_a) |sa| { + if (sentinel_b) |sb| { + if (!sa.eql(sb)) + return false; + } else { + return false; } + } else { + if (sentinel_b != null) + return false; } - const is_slice_a = isSlice(a); - const is_slice_b = isSlice(b); - if (is_slice_a != is_slice_b) - return false; - const ptr_size_a = ptrSize(a); - const ptr_size_b = ptrSize(b); - if (ptr_size_a != ptr_size_b) - return false; - - std.debug.panic("TODO implement more pointer Type equality comparison: {} and {}", .{ - a, b, - }); + return true; }, .Int => { // Detect that e.g. u64 != usize, even if the bits match on a particular target. @@ -844,6 +976,35 @@ pub const Type = extern union { return fast_result; } + pub fn ptrAlignment(self: Type, target: Target) u32 { + switch (self.tag()) { + .single_const_pointer, + .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, + .const_slice, + .mut_slice, + .optional_single_const_pointer, + .optional_single_mut_pointer, + => return self.cast(Payload.ElemType).?.data.abiAlignment(target), + + .const_slice_u8 => return 1, + + .pointer => { + const ptr_info = self.castTag(.pointer).?.data; + if (ptr_info.@"align" != 0) { + return ptr_info.@"align"; + } else { + return ptr_info.pointee_type.abiAlignment(); + } + }, + + else => unreachable, + } + } + /// Asserts that hasCodeGenBits() is true. pub fn abiAlignment(self: Type, target: Target) u32 { return switch (self.tag()) { @@ -885,15 +1046,9 @@ pub const Type = extern union { .mut_slice, .optional_single_const_pointer, .optional_single_mut_pointer, + .pointer, => return @divExact(target.cpu.arch.ptrBitWidth(), 8), - .pointer => { - const payload = self.castTag(.pointer).?.data; - - if (payload.@"align" != 0) return payload.@"align"; - return @divExact(target.cpu.arch.ptrBitWidth(), 8); - }, - .c_short => return @divExact(CType.short.sizeInBits(target), 8), .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8), .c_int => return @divExact(CType.int.sizeInBits(target), 8), diff --git a/test/stage2/test.zig b/test/stage2/test.zig index 6df8789334..6628db9ed5 100644 --- a/test/stage2/test.zig +++ b/test/stage2/test.zig @@ -1502,27 +1502,27 @@ pub fn addCases(ctx: *TestContext) !void { "", ); - //case.addCompareOutput( - // \\export fn _start() noreturn { - // \\ const a: anyerror!comptime_int = 42; - // \\ const b: *const comptime_int = &(a catch unreachable); - // \\ assert(b.* == 42); - // \\ - // \\ exit(); - // \\} - // \\fn assert(b: bool) void { - // \\ if (!b) unreachable; // assertion failure - // \\} - // \\fn exit() noreturn { - // \\ asm volatile ("syscall" - // \\ : - // \\ : [number] "{rax}" (231), - // \\ [arg1] "{rdi}" (0) - // \\ : "rcx", "r11", "memory" - // \\ ); - // \\ unreachable; - // \\} - //, ""); + case.addCompareOutput( + \\export fn _start() noreturn { + \\ const a: anyerror!comptime_int = 42; + \\ const b: *const comptime_int = &(a catch unreachable); + \\ assert(b.* == 42); + \\ + \\ exit(); + \\} + \\fn assert(b: bool) void { + \\ if (!b) unreachable; // assertion failure + \\} + \\fn exit() noreturn { + \\ asm volatile ("syscall" + \\ : + \\ : [number] "{rax}" (231), + \\ [arg1] "{rdi}" (0) + \\ : "rcx", "r11", "memory" + \\ ); + \\ unreachable; + \\} + , ""); case.addCompareOutput( \\export fn _start() noreturn {