Commit 68f4eb0f67

Andrew Kelley <andrew@ziglang.org>
2021-03-28 08:55:19
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.
1 parent 95cc457
Changed files (3)
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 is_slice_a = isSlice(a);
-                const is_slice_b = isSlice(b);
-                if (is_slice_a != is_slice_b)
+                const info_a = a.ptrInfo().data;
+                const info_b = b.ptrInfo().data;
+                if (!info_a.pointee_type.eql(info_b.pointee_type))
                     return false;
-
-                const ptr_size_a = ptrSize(a);
-                const ptr_size_b = ptrSize(b);
-                if (ptr_size_a != ptr_size_b)
+                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;
 
-                std.debug.panic("TODO implement more pointer Type equality comparison: {} and {}", .{
-                    a, b,
-                });
+                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;
+                }
+
+                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),
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 {
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