mirror of
https://github.com/ziglang/zig.git
synced 2025-12-22 22:23:10 +00:00
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:
parent
95cc457d97
commit
68f4eb0f67
14
BRANCH_TODO
14
BRANCH_TODO
@ -1,22 +1,14 @@
|
|||||||
this is my WIP branch scratch pad, to be deleted before merging into master
|
this is my WIP branch scratch pad, to be deleted before merging into master
|
||||||
|
|
||||||
Merge TODO list:
|
Merge TODO list:
|
||||||
* don't have an explicit dbg_stmt zir instruction - instead merge it with
|
* uncomment the commented out stage2 tests
|
||||||
var decl and assignment instructions, etc.
|
|
||||||
- make it set sema.src where appropriate
|
|
||||||
* remove the LazySrcLoc.todo tag
|
* remove the LazySrcLoc.todo tag
|
||||||
* update astgen.zig
|
* update astgen.zig
|
||||||
* finish updating Sema.zig
|
* finish updating Sema.zig
|
||||||
* finish implementing SrcLoc byteOffset function
|
* 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 all the .unneeded src locations
|
||||||
* audit the calls in codegen toSrcLocWithDecl specifically if there is inlined function
|
* audit the calls in codegen toSrcLocWithDecl specifically if there is inlined function
|
||||||
calls from other files.
|
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:
|
Performance optimizations to look into:
|
||||||
* astgen: pass *GenZir as the first arg, not *Module
|
* 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
|
* 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
|
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.
|
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
|
||||||
|
|||||||
201
src/type.zig
201
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 {
|
pub fn eql(a: Type, b: Type) bool {
|
||||||
// As a shortcut, if the small tags / addresses match, we're done.
|
// As a shortcut, if the small tags / addresses match, we're done.
|
||||||
if (a.tag_if_small_enough == b.tag_if_small_enough)
|
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());
|
return a.elemType().eql(b.elemType());
|
||||||
},
|
},
|
||||||
.Pointer => {
|
.Pointer => {
|
||||||
// Hot path for common case:
|
const info_a = a.ptrInfo().data;
|
||||||
if (a.castPointer()) |a_payload| {
|
const info_b = b.ptrInfo().data;
|
||||||
if (b.castPointer()) |b_payload| {
|
if (!info_a.pointee_type.eql(info_b.pointee_type))
|
||||||
return a.tag() == b.tag() and eql(a_payload.data, b_payload.data);
|
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);
|
return true;
|
||||||
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,
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
.Int => {
|
.Int => {
|
||||||
// Detect that e.g. u64 != usize, even if the bits match on a particular target.
|
// 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;
|
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.
|
/// Asserts that hasCodeGenBits() is true.
|
||||||
pub fn abiAlignment(self: Type, target: Target) u32 {
|
pub fn abiAlignment(self: Type, target: Target) u32 {
|
||||||
return switch (self.tag()) {
|
return switch (self.tag()) {
|
||||||
@ -885,15 +1046,9 @@ pub const Type = extern union {
|
|||||||
.mut_slice,
|
.mut_slice,
|
||||||
.optional_single_const_pointer,
|
.optional_single_const_pointer,
|
||||||
.optional_single_mut_pointer,
|
.optional_single_mut_pointer,
|
||||||
|
.pointer,
|
||||||
=> return @divExact(target.cpu.arch.ptrBitWidth(), 8),
|
=> 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_short => return @divExact(CType.short.sizeInBits(target), 8),
|
||||||
.c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8),
|
.c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8),
|
||||||
.c_int => return @divExact(CType.int.sizeInBits(target), 8),
|
.c_int => return @divExact(CType.int.sizeInBits(target), 8),
|
||||||
|
|||||||
@ -1502,27 +1502,27 @@ pub fn addCases(ctx: *TestContext) !void {
|
|||||||
"",
|
"",
|
||||||
);
|
);
|
||||||
|
|
||||||
//case.addCompareOutput(
|
case.addCompareOutput(
|
||||||
// \\export fn _start() noreturn {
|
\\export fn _start() noreturn {
|
||||||
// \\ const a: anyerror!comptime_int = 42;
|
\\ const a: anyerror!comptime_int = 42;
|
||||||
// \\ const b: *const comptime_int = &(a catch unreachable);
|
\\ const b: *const comptime_int = &(a catch unreachable);
|
||||||
// \\ assert(b.* == 42);
|
\\ assert(b.* == 42);
|
||||||
// \\
|
\\
|
||||||
// \\ exit();
|
\\ exit();
|
||||||
// \\}
|
\\}
|
||||||
// \\fn assert(b: bool) void {
|
\\fn assert(b: bool) void {
|
||||||
// \\ if (!b) unreachable; // assertion failure
|
\\ if (!b) unreachable; // assertion failure
|
||||||
// \\}
|
\\}
|
||||||
// \\fn exit() noreturn {
|
\\fn exit() noreturn {
|
||||||
// \\ asm volatile ("syscall"
|
\\ asm volatile ("syscall"
|
||||||
// \\ :
|
\\ :
|
||||||
// \\ : [number] "{rax}" (231),
|
\\ : [number] "{rax}" (231),
|
||||||
// \\ [arg1] "{rdi}" (0)
|
\\ [arg1] "{rdi}" (0)
|
||||||
// \\ : "rcx", "r11", "memory"
|
\\ : "rcx", "r11", "memory"
|
||||||
// \\ );
|
\\ );
|
||||||
// \\ unreachable;
|
\\ unreachable;
|
||||||
// \\}
|
\\}
|
||||||
//, "");
|
, "");
|
||||||
|
|
||||||
case.addCompareOutput(
|
case.addCompareOutput(
|
||||||
\\export fn _start() noreturn {
|
\\export fn _start() noreturn {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user