aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-03-27 23:55:19 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-03-27 23:55:19 -0700
commit68f4eb0f67b6e5f7c20332e79c8e8decb07748ee (patch)
tree7830086e80412e46fecee38de9c6c43844dbc4be
parent95cc457d977c3a4671adfe61d482465cd262d17f (diff)
downloadzig-68f4eb0f67b6e5f7c20332e79c8e8decb07748ee.tar.gz
zig-68f4eb0f67b6e5f7c20332e79c8e8decb07748ee.zip
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.
-rw-r--r--BRANCH_TODO14
-rw-r--r--src/type.zig201
-rw-r--r--test/stage2/test.zig42
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 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),
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 {