stage2: complex pointer types

This commit is contained in:
Vexu 2020-08-20 13:52:18 +03:00 committed by Andrew Kelley
parent ebfe723f3c
commit 9568248450
5 changed files with 202 additions and 12 deletions

View File

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

View File

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

View File

@ -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,
};
};
};

View File

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

View File

@ -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);
}