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.
This commit is contained in:
Andrew Kelley 2021-03-27 23:55:19 -07:00
parent 95cc457d97
commit 68f4eb0f67
3 changed files with 204 additions and 53 deletions

View File

@ -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

View File

@ -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),

View File

@ -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 {