Commit 9568248450

Vexu <git@vexu.eu>
2020-08-20 12:52:18
stage2: complex pointer types
1 parent ebfe723
Changed files (5)
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);
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: {
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,
+        };
     };
 };
 
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,
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);
 }