diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index 9b27f38fbe..2dd64c64bc 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -3153,7 +3153,7 @@ pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mu type_payload.* = .{ .base = .{ .tag = switch (size) { - .One => if (mutable) .single_mut_pointer else T.many_const_pointer, + .One => if (mutable) T.single_mut_pointer else T.single_const_pointer, .Many => if (mutable) T.many_mut_pointer else T.many_const_pointer, .C => if (mutable) T.c_mut_pointer else T.c_const_pointer, else => unreachable, @@ -3164,6 +3164,38 @@ pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mu return Type.initPayload(&type_payload.base); } +pub fn ptrType( + self: *Module, + scope: *Scope, + src: usize, + elem_ty: Type, + sentinel: ?Value, + @"align": u32, + bit_offset: u16, + host_size: u16, + mutable: bool, + @"allowzero": bool, + @"volatile": bool, + size: std.builtin.TypeInfo.Pointer.Size, +) Allocator.Error!Type { + assert(host_size == 0 or bit_offset < host_size * 8); + + // TODO check if type can be represented by simplePtrType + const type_payload = try scope.arena().create(Type.Payload.Pointer); + type_payload.* = .{ + .pointee_type = elem_ty, + .sentinel = sentinel, + .@"align" = @"align", + .bit_offset = bit_offset, + .host_size = host_size, + .@"allowzero" = @"allowzero", + .mutable = mutable, + .@"volatile" = @"volatile", + .size = size, + }; + return Type.initPayload(&type_payload.base); +} + pub fn optionalType(self: *Module, scope: *Scope, child_type: Type) Allocator.Error!Type { return Type.initPayload(switch (child_type.tag()) { .single_const_pointer => blk: { diff --git a/src-self-hosted/astgen.zig b/src-self-hosted/astgen.zig index bb42b746ad..832e6848b3 100644 --- a/src-self-hosted/astgen.zig +++ b/src-self-hosted/astgen.zig @@ -582,8 +582,7 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir // TODO stage1 type inference bug .LBracket => @as(std.builtin.TypeInfo.Pointer.Size, switch (tree.token_ids[node.op_token + 2]) { .Identifier => .C, - .RBracket => .Many, - else => unreachable, + else => .Many, }), else => unreachable, }; @@ -616,7 +615,7 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir kw_args.align_bit_end = try expr(mod, scope, .none, bit_range.end); } } - kw_args.@"const" = node.ptr_info.const_token != null; + kw_args.mutable = node.ptr_info.const_token == null; kw_args.@"volatile" = node.ptr_info.volatile_token != null; if (node.ptr_info.sentinel) |some| { kw_args.sentinel = try expr(mod, scope, .none, some); diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index 233e479297..2c326b9308 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -74,6 +74,7 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .pointer, => return .Pointer, .optional, @@ -390,6 +391,25 @@ pub const Type = extern union { .optional_single_mut_pointer, .optional_single_const_pointer, => return self.copyPayloadSingleField(allocator, Payload.PointerSimple, "pointee_type"), + + .pointer => { + const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise); + const new_payload = try allocator.create(Payload.Pointer); + new_payload.* = .{ + .base = payload.base, + + .pointee_type = try payload.pointee_type.copy(allocator), + .sentinel = if (payload.sentinel) |some| try some.copy(allocator) else null, + .@"align" = payload.@"align", + .bit_offset = payload.bit_offset, + .host_size = payload.host_size, + .@"allowzero" = payload.@"allowzero", + .mutable = payload.mutable, + .@"volatile" = payload.@"volatile", + .size = payload.size, + }; + return Type{ .ptr_otherwise = &new_payload.base }; + }, } } @@ -556,6 +576,34 @@ pub const Type = extern union { ty = payload.pointee_type; continue; }, + + .pointer => { + const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise); + if (payload.sentinel) |some| switch (payload.size) { + .One, .C => unreachable, + .Many => try out_stream.writeAll("[*:{}]"), + .Slice => try out_stream.writeAll("[:{}]"), + } else switch (payload.size) { + .One => try out_stream.writeAll("*"), + .Many => try out_stream.writeAll("[*]"), + .C => try out_stream.writeAll("[*c]"), + .Slice => try out_stream.writeAll("[]"), + } + if (payload.@"align" != 0) { + try out_stream.print("align({}", .{payload.@"align"}); + + if (payload.bit_offset != 0) { + try out_stream.print(":{}:{}", .{ payload.bit_offset, payload.host_size }); + } + try out_stream.writeAll(") "); + } + if (!payload.mutable) try out_stream.writeAll("const "); + if (payload.@"volatile") try out_stream.writeAll("volatile "); + if (payload.@"allowzero") try out_stream.writeAll("allowzero "); + + ty = payload.pointee_type; + continue; + }, } unreachable; } @@ -660,6 +708,7 @@ pub const Type = extern union { .many_mut_pointer => self.elemType().hasCodeGenBits(), .c_const_pointer => self.elemType().hasCodeGenBits(), .c_mut_pointer => self.elemType().hasCodeGenBits(), + .pointer => self.elemType().hasCodeGenBits(), .int_signed => self.cast(Payload.IntSigned).?.bits == 0, .int_unsigned => self.cast(Payload.IntUnsigned).?.bits == 0, @@ -718,6 +767,13 @@ pub const Type = extern union { .optional_single_mut_pointer, => return @divExact(target.cpu.arch.ptrBitWidth(), 8), + .pointer => { + const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise); + + 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), @@ -789,6 +845,7 @@ pub const Type = extern union { .@"null" => unreachable, .@"undefined" => unreachable, .enum_literal => unreachable, + .single_const_pointer_to_comptime_int => unreachable, .u8, .i8, @@ -812,18 +869,28 @@ pub const Type = extern union { .i64, .u64 => return 8, .isize, - .usize, - .single_const_pointer_to_comptime_int, - .const_slice_u8, + .usize + => return @divExact(target.cpu.arch.ptrBitWidth(), 8), + .const_slice_u8 => return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2, + + .optional_single_const_pointer, + .optional_single_mut_pointer, + => { + if (self.elemType().hasCodeGenBits()) return 1; + return @divExact(target.cpu.arch.ptrBitWidth(), 8); + }, + .single_const_pointer, .single_mut_pointer, .many_const_pointer, .many_mut_pointer, .c_const_pointer, .c_mut_pointer, - .optional_single_const_pointer, - .optional_single_mut_pointer, - => return @divExact(target.cpu.arch.ptrBitWidth(), 8), + .pointer, + => { + if (self.elemType().hasCodeGenBits()) return 0; + 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), @@ -931,6 +998,8 @@ pub const Type = extern union { .single_mut_pointer, .single_const_pointer_to_comptime_int, => true, + + .pointer => self.cast(Payload.Pointer).?.size == .One, }; } @@ -994,6 +1063,8 @@ pub const Type = extern union { => false, .const_slice_u8 => true, + + .pointer => self.cast(Payload.Pointer).?.size == .Slice, }; } @@ -1058,6 +1129,8 @@ pub const Type = extern union { .single_const_pointer_to_comptime_int, .const_slice_u8, => true, + + .pointer => !self.cast(Payload.Pointer).?.mutable, }; } @@ -1120,6 +1193,11 @@ pub const Type = extern union { .optional_single_const_pointer, .enum_literal, => false, + + .pointer => { + const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise); + return payload.@"volatile"; + }, }; } @@ -1237,6 +1315,7 @@ pub const Type = extern union { .c_mut_pointer => self.castPointer().?.pointee_type, .array_u8, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8), .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int), + .pointer => self.cast(Payload.Pointer).?.pointee_type, }; } @@ -1325,6 +1404,7 @@ pub const Type = extern union { .fn_naked_noreturn_no_args, .fn_ccc_void_no_args, .function, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1389,6 +1469,7 @@ pub const Type = extern union { .fn_naked_noreturn_no_args, .fn_ccc_void_no_args, .function, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1443,6 +1524,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1508,6 +1590,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1573,6 +1656,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1636,6 +1720,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1728,6 +1813,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1796,6 +1882,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1863,6 +1950,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1930,6 +2018,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1994,6 +2083,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -2058,6 +2148,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -2142,6 +2233,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -2241,6 +2333,10 @@ pub const Type = extern union { ty = ptr.pointee_type; continue; }, + .pointer => { + ty = ty.cast(Payload.Pointer).?.pointee_type; + continue; + }, }; } @@ -2305,6 +2401,8 @@ pub const Type = extern union { .c_const_pointer, .c_mut_pointer, => return true, + + .pointer => self.cast(Payload.Pointer).?.size == .C, }; } @@ -2362,6 +2460,7 @@ pub const Type = extern union { array_u8_sentinel_0, array, array_sentinel, + pointer, single_const_pointer, single_mut_pointer, many_const_pointer, @@ -2440,6 +2539,21 @@ pub const Type = extern union { child_type: Type, }; + + pub const Pointer = struct { + base: Payload = .{ .tag = .pointer }, + + pointee_type: Type, + sentinel: ?Value, + /// If zero use pointee_type.AbiAlign() + @"align": u32, + bit_offset: u16, + host_size: u16, + @"allowzero": bool, + mutable: bool, + @"volatile": bool, + size: std.builtin.TypeInfo.Pointer.Size, + }; }; }; diff --git a/src-self-hosted/zir.zig b/src-self-hosted/zir.zig index 62c0c73f3f..db0ec242cc 100644 --- a/src-self-hosted/zir.zig +++ b/src-self-hosted/zir.zig @@ -872,7 +872,7 @@ pub const Inst = struct { @"align": ?*Inst = null, align_bit_start: ?*Inst = null, align_bit_end: ?*Inst = null, - @"const": bool = true, + mutable: bool = true, @"volatile": bool = false, sentinel: ?*Inst = null, size: std.builtin.TypeInfo.Pointer.Size = .One, diff --git a/src-self-hosted/zir_sema.zig b/src-self-hosted/zir_sema.zig index 0e331d1979..ea3b85b29a 100644 --- a/src-self-hosted/zir_sema.zig +++ b/src-self-hosted/zir_sema.zig @@ -271,6 +271,14 @@ fn resolveType(mod: *Module, scope: *Scope, old_inst: *zir.Inst) !Type { return val.toType(); } +fn resolveInt(mod: *Module, scope: *Scope, old_inst: *zir.Inst, dest_type: Type) !u64 { + const new_inst = try resolveInst(mod, scope, old_inst); + const coerced = try mod.coerce(scope, dest_type, new_inst); + const val = try mod.resolveConstValue(scope, coerced); + + return val.toUnsignedInt(); +} + pub fn resolveInstConst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!TypedValue { const new_inst = try resolveInst(mod, scope, old_inst); const val = try mod.resolveConstValue(scope, new_inst); @@ -1322,5 +1330,42 @@ fn analyzeInstSimplePtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, m } fn analyzeInstPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.PtrType) InnerError!*Inst { - return mod.fail(scope, inst.base.src, "TODO implement ptr_type", .{}); + // TODO lazy values + const @"align" = if (inst.kw_args.@"align") |some| + @truncate(u32, try resolveInt(mod, scope, some, Type.initTag(.u32))) + else + 0; + const bit_offset = if (inst.kw_args.align_bit_start) |some| + @truncate(u16, try resolveInt(mod, scope, some, Type.initTag(.u16))) + else + 0; + const host_size = if (inst.kw_args.align_bit_end) |some| + @truncate(u16, try resolveInt(mod, scope, some, Type.initTag(.u16))) + else + 0; + + if (host_size != 0 and bit_offset >= host_size * 8) + return mod.fail(scope, inst.base.src, "bit offset starts after end of host integer", .{}); + + const sentinel = if (inst.kw_args.sentinel) |some| + (try resolveInstConst(mod, scope, some)).val + else + null; + + const elem_type = try resolveType(mod, scope, inst.positionals.child_type); + + const ty = try mod.ptrType( + scope, + inst.base.src, + elem_type, + sentinel, + @"align", + bit_offset, + host_size, + inst.kw_args.mutable, + inst.kw_args.@"allowzero", + inst.kw_args.@"volatile", + inst.kw_args.size, + ); + return mod.constType(scope, inst.base.src, ty); }