Type.isSlice: make it InternPool aware

This commit is contained in:
Andrew Kelley 2023-05-03 20:04:47 -07:00
parent fb16ad3add
commit 85c69c5194
16 changed files with 339 additions and 285 deletions

View File

@ -629,7 +629,7 @@ pub const Tag = enum(u8) {
/// A vector type.
/// data is payload to Vector.
type_vector,
/// A pointer type along with all its bells and whistles.
/// A fully explicitly specified pointer type.
/// data is payload to Pointer.
type_pointer,
/// An optional type.
@ -682,13 +682,13 @@ pub const Tag = enum(u8) {
/// An enum tag identified by a negative integer value.
/// data is a limbs index to Int.
enum_tag_negative,
/// A float value that can be represented by f32.
/// An f32 value.
/// data is float value bitcasted to u32.
float_f32,
/// A float value that can be represented by f64.
/// An f64 value.
/// data is payload index to Float64.
float_f64,
/// A float value that can be represented by f128.
/// An f128 value.
/// data is payload index to Float128.
float_f128,
/// An extern function.
@ -871,7 +871,47 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
.simple_type => .{ .simple_type = @intToEnum(SimpleType, data) },
.simple_value => .{ .simple_value = @intToEnum(SimpleValue, data) },
else => @panic("TODO"),
.type_vector => {
const vector_info = ip.extraData(Vector, data);
return .{ .vector_type = .{
.len = vector_info.len,
.child = vector_info.child,
} };
},
.type_pointer => {
const ptr_info = ip.extraData(Pointer, data);
return .{ .ptr_type = .{
.elem_type = ptr_info.child,
.sentinel = ptr_info.sentinel,
.alignment = ptr_info.flags.alignment,
.size = ptr_info.flags.size,
.is_const = ptr_info.flags.is_const,
.is_volatile = ptr_info.flags.is_volatile,
.is_allowzero = ptr_info.flags.is_allowzero,
.address_space = ptr_info.flags.address_space,
} };
},
.type_optional => .{ .optional_type = .{ .payload_type = @intToEnum(Index, data) } },
.type_error_union => @panic("TODO"),
.type_enum_simple => @panic("TODO"),
.simple_internal => @panic("TODO"),
.int_small_u32 => @panic("TODO"),
.int_small_i32 => @panic("TODO"),
.int_small_usize => @panic("TODO"),
.int_small_comptime_unsigned => @panic("TODO"),
.int_small_comptime_signed => @panic("TODO"),
.int_positive => @panic("TODO"),
.int_negative => @panic("TODO"),
.enum_tag_positive => @panic("TODO"),
.enum_tag_negative => @panic("TODO"),
.float_f32 => @panic("TODO"),
.float_f64 => @panic("TODO"),
.float_f128 => @panic("TODO"),
.extern_func => @panic("TODO"),
.func => @panic("TODO"),
};
}

View File

@ -2030,7 +2030,7 @@ fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty
ty.fmt(mod),
});
errdefer msg.destroy(sema.gpa);
if (ty.isSlice()) {
if (ty.isSlice(mod)) {
try sema.errNote(block, src, msg, "inferred array length is specified with an underscore: '[_]{}'", .{ty.elemType2(mod).fmt(mod)});
}
break :msg msg;
@ -10359,7 +10359,7 @@ fn zirSwitchCond(
.ErrorSet,
.Enum,
=> {
if (operand_ty.isSlice()) {
if (operand_ty.isSlice(mod)) {
return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(sema.mod)});
}
if ((try sema.typeHasOnePossibleValue(operand_ty))) |opv| {
@ -12017,7 +12017,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const ty = try sema.resolveTypeFields(unresolved_ty);
const has_field = hf: {
if (ty.isSlice()) {
if (ty.isSlice(mod)) {
if (mem.eql(u8, field_name, "ptr")) break :hf true;
if (mem.eql(u8, field_name, "len")) break :hf true;
break :hf false;
@ -20020,8 +20020,8 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
return sema.failWithOwnedErrorMsg(msg);
}
const dest_is_slice = dest_ty.isSlice();
const operand_is_slice = operand_ty.isSlice();
const dest_is_slice = dest_ty.isSlice(mod);
const operand_is_slice = operand_ty.isSlice(mod);
if (dest_is_slice and !operand_is_slice) {
return sema.fail(block, dest_ty_src, "illegal pointer cast to slice", .{});
}
@ -20274,14 +20274,14 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
Type.usize,
Value.initPayload(&val_payload.base),
);
const actual_ptr = if (ptr_ty.isSlice())
const actual_ptr = if (ptr_ty.isSlice(mod))
try sema.analyzeSlicePtr(block, ptr_src, ptr, ptr_ty)
else
ptr;
const ptr_int = try block.addUnOp(.ptrtoint, actual_ptr);
const remainder = try block.addBinOp(.bit_and, ptr_int, align_minus_1);
const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
const ok = if (ptr_ty.isSlice()) ok: {
const ok = if (ptr_ty.isSlice(mod)) ok: {
const len = try sema.analyzeSliceLen(block, ptr_src, ptr);
const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);
break :ok try block.addBinOp(.bit_or, len_zero, is_aligned);
@ -22336,7 +22336,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
// Change the src from slice to a many pointer, to avoid multiple ptr
// slice extractions in AIR instructions.
const new_src_ptr_ty = sema.typeOf(new_src_ptr);
if (new_src_ptr_ty.isSlice()) {
if (new_src_ptr_ty.isSlice(mod)) {
new_src_ptr = try sema.analyzeSlicePtr(block, src_src, new_src_ptr, new_src_ptr_ty);
}
} else if (dest_len == .none and len_val == null) {
@ -22344,7 +22344,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
const dest_ptr_ptr = try sema.analyzeRef(block, dest_src, new_dest_ptr);
new_dest_ptr = try sema.analyzeSlice(block, dest_src, dest_ptr_ptr, .zero, src_len, .none, .unneeded, dest_src, dest_src, dest_src, false);
const new_src_ptr_ty = sema.typeOf(new_src_ptr);
if (new_src_ptr_ty.isSlice()) {
if (new_src_ptr_ty.isSlice(mod)) {
new_src_ptr = try sema.analyzeSlicePtr(block, src_src, new_src_ptr, new_src_ptr_ty);
}
}
@ -22363,7 +22363,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
// Extract raw pointer from dest slice. The AIR instructions could support them, but
// it would cause redundant machine code instructions.
const new_dest_ptr_ty = sema.typeOf(new_dest_ptr);
const raw_dest_ptr = if (new_dest_ptr_ty.isSlice())
const raw_dest_ptr = if (new_dest_ptr_ty.isSlice(mod))
try sema.analyzeSlicePtr(block, dest_src, new_dest_ptr, new_dest_ptr_ty)
else
new_dest_ptr;
@ -23383,7 +23383,7 @@ fn validateExternType(
.Float,
.AnyFrame,
=> return true,
.Pointer => return !(ty.isSlice() or try sema.typeRequiresComptime(ty)),
.Pointer => return !(ty.isSlice(mod) or try sema.typeRequiresComptime(ty)),
.Int => switch (ty.intInfo(mod).bits) {
8, 16, 32, 64, 128 => return true,
else => return false,
@ -23448,7 +23448,7 @@ fn explainWhyTypeIsNotExtern(
=> return,
.Pointer => {
if (ty.isSlice()) {
if (ty.isSlice(mod)) {
try mod.errNoteNonLazy(src_loc, msg, "slices have no guaranteed in-memory representation", .{});
} else {
const pointee_ty = ty.childType();
@ -23523,7 +23523,7 @@ fn validatePackedType(ty: Type, mod: *const Module) bool {
.Vector,
.Enum,
=> return true,
.Pointer => return !ty.isSlice(),
.Pointer => return !ty.isSlice(mod),
.Struct, .Union => return ty.containerLayout() == .Packed,
}
}
@ -23803,7 +23803,7 @@ fn panicSentinelMismatch(
const expected_sentinel = try sema.addConstant(sentinel_ty, expected_sentinel_val);
const ptr_ty = sema.typeOf(ptr);
const actual_sentinel = if (ptr_ty.isSlice())
const actual_sentinel = if (ptr_ty.isSlice(mod))
try parent_block.addBinOp(.slice_elem_val, ptr, sentinel_index)
else blk: {
const elem_ptr_ty = try sema.elemPtrType(ptr_ty, null);
@ -24064,7 +24064,7 @@ fn fieldVal(
const msg = msg: {
const msg = try sema.errMsg(block, src, "type '{}' has no members", .{child_type.fmt(sema.mod)});
errdefer msg.destroy(sema.gpa);
if (child_type.isSlice()) try sema.errNote(block, src, msg, "slice values have 'len' and 'ptr' members", .{});
if (child_type.isSlice(mod)) try sema.errNote(block, src, msg, "slice values have 'len' and 'ptr' members", .{});
if (child_type.zigTypeTag(mod) == .Array) try sema.errNote(block, src, msg, "array values have 'len' member", .{});
break :msg msg;
};
@ -24140,7 +24140,7 @@ fn fieldPtr(
);
}
},
.Pointer => if (inner_ty.isSlice()) {
.Pointer => if (inner_ty.isSlice(mod)) {
const inner_ptr = if (is_pointer_to)
try sema.analyzeLoad(block, src, object_ptr, object_ptr_src)
else
@ -25743,8 +25743,8 @@ fn coerceExtra(
} };
break :pointer;
}
if (dest_ty.isSlice()) break :to_anyopaque;
if (inst_ty.isSlice()) {
if (dest_ty.isSlice(mod)) break :to_anyopaque;
if (inst_ty.isSlice(mod)) {
in_memory_result = .{ .slice_to_anyopaque = .{
.actual = inst_ty,
.wanted = dest_ty,
@ -25885,7 +25885,7 @@ fn coerceExtra(
return sema.coerceTupleToSlicePtrs(block, dest_ty, dest_ty_src, inst, inst_src);
},
.Many => p: {
if (!inst_ty.isSlice()) break :p;
if (!inst_ty.isSlice(mod)) break :p;
if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :p;
const inst_info = inst_ty.ptrInfo().data;
@ -26651,7 +26651,7 @@ fn coerceInMemoryAllowed(
}
// Slices
if (dest_ty.isSlice() and src_ty.isSlice()) {
if (dest_ty.isSlice(mod) and src_ty.isSlice(mod)) {
return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ty, src_ty, dest_is_mut, target, dest_src, src_src);
}
@ -27744,7 +27744,7 @@ fn beginComptimePtrMutation(
);
},
.Pointer => {
assert(parent.ty.isSlice());
assert(parent.ty.isSlice(mod));
val_ptr.* = try Value.Tag.slice.create(arena, .{
.ptr = Value.undef,
.len = Value.undef,
@ -28187,7 +28187,7 @@ fn beginComptimePtrLoad(
break :blk deref;
}
if (field_ptr.container_ty.isSlice()) {
if (field_ptr.container_ty.isSlice(mod)) {
const slice_val = tv.val.castTag(.slice).?.data;
deref.pointee = switch (field_index) {
Value.Payload.Slice.ptr_index => TypedValue{
@ -28442,13 +28442,13 @@ fn coerceCompatiblePtrs(
if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero(mod) and
(try sema.typeHasRuntimeBits(dest_ty.elemType2(mod)) or dest_ty.elemType2(mod).zigTypeTag(mod) == .Fn))
{
const actual_ptr = if (inst_ty.isSlice())
const actual_ptr = if (inst_ty.isSlice(mod))
try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty)
else
inst;
const ptr_int = try block.addUnOp(.ptrtoint, actual_ptr);
const is_non_zero = try block.addBinOp(.cmp_neq, ptr_int, .zero_usize);
const ok = if (inst_ty.isSlice()) ok: {
const ok = if (inst_ty.isSlice(mod)) ok: {
const len = try sema.analyzeSliceLen(block, inst_src, inst);
const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);
break :ok try block.addBinOp(.bit_or, len_zero, is_non_zero);
@ -29548,7 +29548,7 @@ fn analyzeSlice(
else => return sema.fail(block, src, "slice of non-array type '{}'", .{ptr_ptr_child_ty.fmt(mod)}),
}
const ptr = if (slice_ty.isSlice())
const ptr = if (slice_ty.isSlice(mod))
try sema.analyzeSlicePtr(block, ptr_src, ptr_or_slice, slice_ty)
else
ptr_or_slice;
@ -29605,7 +29605,7 @@ fn analyzeSlice(
}
break :e try sema.addConstant(Type.usize, len_val);
} else if (slice_ty.isSlice()) {
} else if (slice_ty.isSlice(mod)) {
if (!end_is_len) {
const end = if (by_length) end: {
const len = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src);
@ -29778,7 +29778,7 @@ fn analyzeSlice(
try sema.addSafetyCheck(block, is_non_null, .unwrap_null);
}
if (slice_ty.isSlice()) {
if (slice_ty.isSlice(mod)) {
const slice_len_inst = try block.addTyOp(.slice_len, Type.usize, ptr_or_slice);
const actual_len = if (slice_ty.sentinel() == null)
slice_len_inst
@ -29840,7 +29840,7 @@ fn analyzeSlice(
// requirement: end <= len
const opt_len_inst = if (array_ty.zigTypeTag(mod) == .Array)
try sema.addIntUnsigned(Type.usize, array_ty.arrayLenIncludingSentinel())
else if (slice_ty.isSlice()) blk: {
else if (slice_ty.isSlice(mod)) blk: {
if (try sema.resolveDefinedValue(block, src, ptr_or_slice)) |slice_val| {
// we don't need to add one for sentinels because the
// underlying value data includes the sentinel

View File

@ -259,7 +259,7 @@ pub fn print(
} else if (field_ptr.container_ty.zigTypeTag(mod) == .Union) {
const field_name = field_ptr.container_ty.unionFields().keys()[field_ptr.field_index];
return writer.print(".{s}", .{field_name});
} else if (field_ptr.container_ty.isSlice()) {
} else if (field_ptr.container_ty.isSlice(mod)) {
switch (field_ptr.field_index) {
Value.Payload.Slice.ptr_index => return writer.writeAll(".ptr"),
Value.Payload.Slice.len_index => return writer.writeAll(".len"),

View File

@ -52,7 +52,7 @@ pub fn classifyType(ty: Type, mod: *const Module) Class {
return .byval;
},
.Pointer => {
std.debug.assert(!ty.isSlice());
std.debug.assert(!ty.isSlice(mod));
return .byval;
},
.ErrorUnion,

View File

@ -94,7 +94,7 @@ pub fn classifyType(ty: Type, mod: *const Module, ctx: Context) Class {
return .byval;
},
.Pointer => {
assert(!ty.isSlice());
assert(!ty.isSlice(mod));
return .byval;
},
.ErrorUnion,

View File

@ -52,7 +52,7 @@ pub fn classifyType(ty: Type, mod: *const Module) Class {
return .byval;
},
.Pointer => {
std.debug.assert(!ty.isSlice());
std.debug.assert(!ty.isSlice(mod));
return .byval;
},
.ErrorUnion,

View File

@ -1773,7 +1773,7 @@ fn isByRef(ty: Type, mod: *const Module) bool {
},
.Pointer => {
// Slices act like struct and will be passed by reference
if (ty.isSlice()) return true;
if (ty.isSlice(mod)) return true;
return false;
},
}
@ -2396,7 +2396,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
},
},
.Pointer => {
if (ty.isSlice()) {
if (ty.isSlice(mod)) {
// store pointer first
// lower it to the stack so we do not have to store rhs into a local first
try func.emitWValue(lhs);
@ -3010,11 +3010,11 @@ fn lowerParentPtrDecl(func: *CodeGen, ptr_val: Value, decl_index: Module.Decl.In
}
fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: Module.Decl.Index, offset: u32) InnerError!WValue {
if (tv.ty.isSlice()) {
const mod = func.bin_file.base.options.module.?;
if (tv.ty.isSlice(mod)) {
return WValue{ .memory = try func.bin_file.lowerUnnamedConst(tv, decl_index) };
}
const mod = func.bin_file.base.options.module.?;
const decl = mod.declPtr(decl_index);
if (decl.ty.zigTypeTag(mod) != .Fn and !decl.ty.hasRuntimeBitsIgnoreComptime(mod)) {
return WValue{ .imm32 = 0xaaaaaaaa };
@ -4182,7 +4182,7 @@ fn isNull(func: *CodeGen, operand: WValue, optional_ty: Type, opcode: wasm.Opcod
};
try func.addMemArg(.i32_load8_u, .{ .offset = operand.offset() + offset, .alignment = 1 });
}
} else if (payload_ty.isSlice()) {
} else if (payload_ty.isSlice(mod)) {
switch (func.arch()) {
.wasm32 => try func.addMemArg(.i32_load, .{ .offset = operand.offset(), .alignment = 4 }),
.wasm64 => try func.addMemArg(.i64_load, .{ .offset = operand.offset(), .alignment = 8 }),
@ -4455,10 +4455,11 @@ fn airArrayToSlice(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
}
fn airPtrToInt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
const mod = func.bin_file.base.options.module.?;
const un_op = func.air.instructions.items(.data)[inst].un_op;
const operand = try func.resolveInst(un_op);
const ptr_ty = func.typeOf(un_op);
const result = if (ptr_ty.isSlice())
const result = if (ptr_ty.isSlice(mod))
try func.slicePtr(operand)
else switch (operand) {
// for stack offset, return a pointer to this offset.
@ -4479,7 +4480,7 @@ fn airPtrElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
const elem_size = elem_ty.abiSize(mod);
// load pointer onto the stack
if (ptr_ty.isSlice()) {
if (ptr_ty.isSlice(mod)) {
_ = try func.load(ptr, Type.usize, 0);
} else {
try func.lowerToStack(ptr);
@ -4518,7 +4519,7 @@ fn airPtrElemPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
const index = try func.resolveInst(bin_op.rhs);
// load pointer onto the stack
if (ptr_ty.isSlice()) {
if (ptr_ty.isSlice(mod)) {
_ = try func.load(ptr, Type.usize, 0);
} else {
try func.lowerToStack(ptr);
@ -5441,7 +5442,8 @@ fn airFieldParentPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
}
fn sliceOrArrayPtr(func: *CodeGen, ptr: WValue, ptr_ty: Type) InnerError!WValue {
if (ptr_ty.isSlice()) {
const mod = func.bin_file.base.options.module.?;
if (ptr_ty.isSlice(mod)) {
return func.slicePtr(ptr);
} else {
return ptr;

View File

@ -60,7 +60,7 @@ pub fn classifyType(ty: Type, mod: *const Module) [2]Class {
return direct;
},
.Pointer => {
std.debug.assert(!ty.isSlice());
std.debug.assert(!ty.isSlice(mod));
return direct;
},
.Union => {

View File

@ -8688,7 +8688,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined;
const some_info: struct { off: i32, ty: Type } = if (opt_ty.optionalReprIsPayload(mod))
.{ .off = 0, .ty = if (pl_ty.isSlice()) pl_ty.slicePtrFieldType(&ptr_buf) else pl_ty }
.{ .off = 0, .ty = if (pl_ty.isSlice(mod)) pl_ty.slicePtrFieldType(&ptr_buf) else pl_ty }
else
.{ .off = @intCast(i32, pl_ty.abiSize(mod)), .ty = Type.bool };
@ -8781,7 +8781,7 @@ fn isNullPtr(self: *Self, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue)
var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined;
const some_info: struct { off: i32, ty: Type } = if (opt_ty.optionalReprIsPayload(mod))
.{ .off = 0, .ty = if (pl_ty.isSlice()) pl_ty.slicePtrFieldType(&ptr_buf) else pl_ty }
.{ .off = 0, .ty = if (pl_ty.isSlice(mod)) pl_ty.slicePtrFieldType(&ptr_buf) else pl_ty }
else
.{ .off = @intCast(i32, pl_ty.abiSize(mod)), .ty = Type.bool };

View File

@ -317,11 +317,11 @@ pub fn generateSymbol(
switch (target.ptrBitWidth()) {
32 => {
mem.writeInt(u32, try code.addManyAsArray(4), 0, endian);
if (typed_value.ty.isSlice()) try code.appendNTimes(0xaa, 4);
if (typed_value.ty.isSlice(mod)) try code.appendNTimes(0xaa, 4);
},
64 => {
mem.writeInt(u64, try code.addManyAsArray(8), 0, endian);
if (typed_value.ty.isSlice()) try code.appendNTimes(0xaa, 8);
if (typed_value.ty.isSlice(mod)) try code.appendNTimes(0xaa, 8);
},
else => unreachable,
}
@ -845,7 +845,7 @@ fn lowerParentPtr(
debug_output,
reloc_info.offset(@intCast(u32, switch (field_ptr.container_ty.zigTypeTag(mod)) {
.Pointer => offset: {
assert(field_ptr.container_ty.isSlice());
assert(field_ptr.container_ty.isSlice(mod));
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
break :offset switch (field_ptr.field_index) {
0 => 0,
@ -946,7 +946,7 @@ fn lowerDeclRef(
) CodeGenError!Result {
const target = bin_file.options.target;
const mod = bin_file.options.module.?;
if (typed_value.ty.isSlice()) {
if (typed_value.ty.isSlice(mod)) {
// generate ptr
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
const slice_ptr_field_type = typed_value.ty.slicePtrFieldType(&buf);
@ -1174,7 +1174,7 @@ pub fn genTypedValue(
const target = bin_file.options.target;
const ptr_bits = target.ptrBitWidth();
if (!typed_value.ty.isSlice()) {
if (!typed_value.ty.isSlice(mod)) {
if (typed_value.val.castTag(.variable)) |payload| {
return genDeclRef(bin_file, src_loc, typed_value, payload.data.owner_decl);
}

View File

@ -556,7 +556,7 @@ pub const DeclGen = struct {
if (decl.val.castTag(.variable)) |var_payload|
try dg.renderFwdDecl(decl_index, var_payload.data);
if (ty.isSlice()) {
if (ty.isSlice(mod)) {
if (location == .StaticInitializer) {
try writer.writeByte('{');
} else {
@ -603,7 +603,7 @@ pub const DeclGen = struct {
fn renderParentPtr(dg: *DeclGen, writer: anytype, ptr_val: Value, ptr_ty: Type, location: ValueRenderLocation) error{ OutOfMemory, AnalysisFail }!void {
const mod = dg.module;
if (!ptr_ty.isSlice()) {
if (!ptr_ty.isSlice(mod)) {
try writer.writeByte('(');
try dg.renderType(writer, ptr_ty);
try writer.writeByte(')');
@ -776,7 +776,7 @@ pub const DeclGen = struct {
try dg.renderValue(writer, repr_ty, Value.undef, .FunctionArgument);
return writer.writeByte(')');
},
.Pointer => if (ty.isSlice()) {
.Pointer => if (ty.isSlice(mod)) {
if (!location.isInitializer()) {
try writer.writeByte('(');
try dg.renderType(writer, ty);
@ -1045,7 +1045,7 @@ pub const DeclGen = struct {
return;
},
.Pointer => switch (val.tag()) {
.null_value, .zero => if (ty.isSlice()) {
.null_value, .zero => if (ty.isSlice(mod)) {
var slice_pl = Value.Payload.Slice{
.base = .{ .tag = .slice },
.data = .{ .ptr = val, .len = Value.undef },
@ -5073,7 +5073,7 @@ fn airIsNull(
TypedValue{ .ty = optional_ty, .val = Value.null }
else if (payload_ty.zigTypeTag(mod) == .ErrorSet)
TypedValue{ .ty = payload_ty, .val = Value.zero }
else if (payload_ty.isSlice() and optional_ty.optionalReprIsPayload(mod)) rhs: {
else if (payload_ty.isSlice(mod) and optional_ty.optionalReprIsPayload(mod)) rhs: {
try writer.writeAll(".ptr");
const slice_ptr_ty = payload_ty.slicePtrFieldType(&slice_ptr_buf);
break :rhs TypedValue{ .ty = slice_ptr_ty, .val = Value.null };
@ -5864,6 +5864,7 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {
}
fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue {
const mod = f.object.dg.module;
const un_op = f.air.instructions.items(.data)[inst].un_op;
const operand = try f.resolveInst(un_op);
@ -5877,7 +5878,7 @@ fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue {
try writer.writeAll(" = (");
try f.renderType(writer, inst_ty);
try writer.writeByte(')');
if (operand_ty.isSlice()) {
if (operand_ty.isSlice(mod)) {
try f.writeCValueMember(writer, operand, .{ .identifier = "len" });
} else {
try f.writeCValue(writer, operand, .Other);
@ -6272,7 +6273,8 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa
}
fn writeSliceOrPtr(f: *Function, writer: anytype, ptr: CValue, ptr_ty: Type) !void {
if (ptr_ty.isSlice()) {
const mod = f.object.dg.module;
if (ptr_ty.isSlice(mod)) {
try f.writeCValueMember(writer, ptr, .{ .identifier = "ptr" });
} else {
try f.writeCValue(writer, ptr, .FunctionArgument);

View File

@ -1636,7 +1636,7 @@ pub const Object = struct {
return ptr_di_ty;
}
if (ty.isSlice()) {
if (ty.isSlice(mod)) {
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
const ptr_ty = ty.slicePtrFieldType(&buf);
const len_ty = Type.usize;
@ -2833,7 +2833,7 @@ pub const DeclGen = struct {
},
.Bool => return dg.context.intType(1),
.Pointer => {
if (t.isSlice()) {
if (t.isSlice(mod)) {
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
const ptr_type = t.slicePtrFieldType(&buf);
@ -4110,7 +4110,7 @@ pub const DeclGen = struct {
}
},
.Pointer => {
assert(parent_ty.isSlice());
assert(parent_ty.isSlice(mod));
const indices: [2]*llvm.Value = .{
llvm_u32.constInt(0, .False),
llvm_u32.constInt(field_index, .False),
@ -4184,7 +4184,7 @@ pub const DeclGen = struct {
decl_index: Module.Decl.Index,
) Error!*llvm.Value {
const mod = self.module;
if (tv.ty.isSlice()) {
if (tv.ty.isSlice(mod)) {
var buf: Type.SlicePtrFieldTypeBuffer = undefined;
const ptr_ty = tv.ty.slicePtrFieldType(&buf);
var slice_len: Value.Payload.U64 = .{
@ -5794,7 +5794,8 @@ pub const FuncGen = struct {
}
fn sliceOrArrayPtr(fg: *FuncGen, ptr: *llvm.Value, ty: Type) *llvm.Value {
if (ty.isSlice()) {
const mod = fg.dg.module;
if (ty.isSlice(mod)) {
return fg.builder.buildExtractValue(ptr, 0, "");
} else {
return ptr;
@ -6669,7 +6670,7 @@ pub const FuncGen = struct {
self.builder.buildLoad(optional_llvm_ty, operand, "")
else
operand;
if (payload_ty.isSlice()) {
if (payload_ty.isSlice(mod)) {
const slice_ptr = self.builder.buildExtractValue(loaded, 0, "");
var slice_buf: Type.SlicePtrFieldTypeBuffer = undefined;
const ptr_ty = try self.dg.lowerType(payload_ty.slicePtrFieldType(&slice_buf));
@ -10864,7 +10865,7 @@ const ParamTypeIterator = struct {
it.zig_index += 1;
it.llvm_index += 1;
var buf: Type.Payload.ElemType = undefined;
if (ty.isSlice() or (ty.zigTypeTag(mod) == .Optional and ty.optionalChild(&buf).isSlice())) {
if (ty.isSlice(mod) or (ty.zigTypeTag(mod) == .Optional and ty.optionalChild(&buf).isSlice(mod))) {
it.llvm_index += 1;
return .slice;
} else if (isByRef(ty, mod)) {

View File

@ -2980,12 +2980,12 @@ pub const DeclGen = struct {
// Pointer payload represents nullability: pointer or slice.
var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined;
const ptr_ty = if (payload_ty.isSlice())
const ptr_ty = if (payload_ty.isSlice(mod))
payload_ty.slicePtrFieldType(&ptr_buf)
else
payload_ty;
const ptr_id = if (payload_ty.isSlice())
const ptr_id = if (payload_ty.isSlice(mod))
try self.extractField(Type.bool, operand_id, 0)
else
operand_id;

View File

@ -258,7 +258,7 @@ pub const DeclState = struct {
}
},
.Pointer => {
if (ty.isSlice()) {
if (ty.isSlice(mod)) {
// Slices are structs: struct { .ptr = *, .len = N }
const ptr_bits = target.ptrBitWidth();
const ptr_bytes = @intCast(u8, @divExact(ptr_bits, 8));

View File

@ -229,7 +229,7 @@ pub const Type = struct {
.Frame,
=> false,
.Pointer => !ty.isSlice() and (is_equality_cmp or ty.isCPtr()),
.Pointer => !ty.isSlice(mod) and (is_equality_cmp or ty.isCPtr()),
.Optional => {
if (!is_equality_cmp) return false;
var buf: Payload.ElemType = undefined;
@ -369,209 +369,212 @@ pub const Type = struct {
}
pub fn ptrInfo(self: Type) Payload.Pointer {
switch (self.tag()) {
.single_const_pointer_to_comptime_int => return .{ .data = .{
.pointee_type = Type.comptime_int,
.sentinel = null,
.@"align" = 0,
.@"addrspace" = .generic,
.bit_offset = 0,
.host_size = 0,
.@"allowzero" = false,
.mutable = false,
.@"volatile" = false,
.size = .One,
} },
.const_slice_u8 => return .{ .data = .{
.pointee_type = Type.u8,
.sentinel = null,
.@"align" = 0,
.@"addrspace" = .generic,
.bit_offset = 0,
.host_size = 0,
.@"allowzero" = false,
.mutable = false,
.@"volatile" = false,
.size = .Slice,
} },
.const_slice_u8_sentinel_0 => return .{ .data = .{
.pointee_type = Type.u8,
.sentinel = Value.zero,
.@"align" = 0,
.@"addrspace" = .generic,
.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,
.@"addrspace" = .generic,
.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,
.@"addrspace" = .generic,
.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,
.@"addrspace" = .generic,
.bit_offset = 0,
.host_size = 0,
.@"allowzero" = false,
.mutable = false,
.@"volatile" = false,
.size = .Many,
} },
.manyptr_const_u8 => return .{ .data = .{
.pointee_type = Type.u8,
.sentinel = null,
.@"align" = 0,
.@"addrspace" = .generic,
.bit_offset = 0,
.host_size = 0,
.@"allowzero" = false,
.mutable = false,
.@"volatile" = false,
.size = .Many,
} },
.manyptr_const_u8_sentinel_0 => return .{ .data = .{
.pointee_type = Type.u8,
.sentinel = Value.zero,
.@"align" = 0,
.@"addrspace" = .generic,
.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,
.@"addrspace" = .generic,
.bit_offset = 0,
.host_size = 0,
.@"allowzero" = false,
.mutable = true,
.@"volatile" = false,
.size = .Many,
} },
.manyptr_u8 => return .{ .data = .{
.pointee_type = Type.u8,
.sentinel = null,
.@"align" = 0,
.@"addrspace" = .generic,
.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,
.@"addrspace" = .generic,
.bit_offset = 0,
.host_size = 0,
.@"allowzero" = true,
.mutable = false,
.@"volatile" = false,
.size = .C,
} },
.c_mut_pointer => return .{ .data = .{
.pointee_type = self.castPointer().?.data,
.sentinel = null,
.@"align" = 0,
.@"addrspace" = .generic,
.bit_offset = 0,
.host_size = 0,
.@"allowzero" = true,
.mutable = true,
.@"volatile" = false,
.size = .C,
} },
.const_slice => return .{ .data = .{
.pointee_type = self.castPointer().?.data,
.sentinel = null,
.@"align" = 0,
.@"addrspace" = .generic,
.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,
.@"addrspace" = .generic,
.bit_offset = 0,
.host_size = 0,
.@"allowzero" = false,
.mutable = true,
.@"volatile" = false,
.size = .Slice,
} },
switch (self.ip_index) {
.none => switch (self.tag()) {
.single_const_pointer_to_comptime_int => return .{ .data = .{
.pointee_type = Type.comptime_int,
.sentinel = null,
.@"align" = 0,
.@"addrspace" = .generic,
.bit_offset = 0,
.host_size = 0,
.@"allowzero" = false,
.mutable = false,
.@"volatile" = false,
.size = .One,
} },
.const_slice_u8 => return .{ .data = .{
.pointee_type = Type.u8,
.sentinel = null,
.@"align" = 0,
.@"addrspace" = .generic,
.bit_offset = 0,
.host_size = 0,
.@"allowzero" = false,
.mutable = false,
.@"volatile" = false,
.size = .Slice,
} },
.const_slice_u8_sentinel_0 => return .{ .data = .{
.pointee_type = Type.u8,
.sentinel = Value.zero,
.@"align" = 0,
.@"addrspace" = .generic,
.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,
.@"addrspace" = .generic,
.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,
.@"addrspace" = .generic,
.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,
.@"addrspace" = .generic,
.bit_offset = 0,
.host_size = 0,
.@"allowzero" = false,
.mutable = false,
.@"volatile" = false,
.size = .Many,
} },
.manyptr_const_u8 => return .{ .data = .{
.pointee_type = Type.u8,
.sentinel = null,
.@"align" = 0,
.@"addrspace" = .generic,
.bit_offset = 0,
.host_size = 0,
.@"allowzero" = false,
.mutable = false,
.@"volatile" = false,
.size = .Many,
} },
.manyptr_const_u8_sentinel_0 => return .{ .data = .{
.pointee_type = Type.u8,
.sentinel = Value.zero,
.@"align" = 0,
.@"addrspace" = .generic,
.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,
.@"addrspace" = .generic,
.bit_offset = 0,
.host_size = 0,
.@"allowzero" = false,
.mutable = true,
.@"volatile" = false,
.size = .Many,
} },
.manyptr_u8 => return .{ .data = .{
.pointee_type = Type.u8,
.sentinel = null,
.@"align" = 0,
.@"addrspace" = .generic,
.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,
.@"addrspace" = .generic,
.bit_offset = 0,
.host_size = 0,
.@"allowzero" = true,
.mutable = false,
.@"volatile" = false,
.size = .C,
} },
.c_mut_pointer => return .{ .data = .{
.pointee_type = self.castPointer().?.data,
.sentinel = null,
.@"align" = 0,
.@"addrspace" = .generic,
.bit_offset = 0,
.host_size = 0,
.@"allowzero" = true,
.mutable = true,
.@"volatile" = false,
.size = .C,
} },
.const_slice => return .{ .data = .{
.pointee_type = self.castPointer().?.data,
.sentinel = null,
.@"align" = 0,
.@"addrspace" = .generic,
.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,
.@"addrspace" = .generic,
.bit_offset = 0,
.host_size = 0,
.@"allowzero" = false,
.mutable = true,
.@"volatile" = false,
.size = .Slice,
} },
.pointer => return self.castTag(.pointer).?.*,
.pointer => return self.castTag(.pointer).?.*,
.optional_single_mut_pointer => return .{ .data = .{
.pointee_type = self.castPointer().?.data,
.sentinel = null,
.@"align" = 0,
.@"addrspace" = .generic,
.bit_offset = 0,
.host_size = 0,
.@"allowzero" = false,
.mutable = true,
.@"volatile" = false,
.size = .One,
} },
.optional_single_const_pointer => return .{ .data = .{
.pointee_type = self.castPointer().?.data,
.sentinel = null,
.@"align" = 0,
.@"addrspace" = .generic,
.bit_offset = 0,
.host_size = 0,
.@"allowzero" = false,
.mutable = false,
.@"volatile" = false,
.size = .One,
} },
.optional => {
var buf: Payload.ElemType = undefined;
const child_type = self.optionalChild(&buf);
return child_type.ptrInfo();
.optional_single_mut_pointer => return .{ .data = .{
.pointee_type = self.castPointer().?.data,
.sentinel = null,
.@"align" = 0,
.@"addrspace" = .generic,
.bit_offset = 0,
.host_size = 0,
.@"allowzero" = false,
.mutable = true,
.@"volatile" = false,
.size = .One,
} },
.optional_single_const_pointer => return .{ .data = .{
.pointee_type = self.castPointer().?.data,
.sentinel = null,
.@"align" = 0,
.@"addrspace" = .generic,
.bit_offset = 0,
.host_size = 0,
.@"allowzero" = false,
.mutable = false,
.@"volatile" = false,
.size = .One,
} },
.optional => {
var buf: Payload.ElemType = undefined;
const child_type = self.optionalChild(&buf);
return child_type.ptrInfo();
},
else => unreachable,
},
else => unreachable,
else => @panic("TODO"),
}
}
@ -3712,17 +3715,23 @@ pub const Type = struct {
};
}
pub fn isSlice(self: Type) bool {
return switch (self.tag()) {
.const_slice,
.mut_slice,
.const_slice_u8,
.const_slice_u8_sentinel_0,
=> true,
pub fn isSlice(ty: Type, mod: *const Module) bool {
return switch (ty.ip_index) {
.none => switch (ty.tag()) {
.const_slice,
.mut_slice,
.const_slice_u8,
.const_slice_u8_sentinel_0,
=> true,
.pointer => self.castTag(.pointer).?.data.size == .Slice,
.pointer => ty.castTag(.pointer).?.data.size == .Slice,
else => false,
else => false,
},
else => switch (mod.intern_pool.indexToKey(ty.ip_index)) {
.ptr_type => |ptr_type| ptr_type.size == .Slice,
else => false,
},
};
}

View File

@ -1144,7 +1144,7 @@ pub const Value = struct {
},
},
.Pointer => {
if (ty.isSlice()) return error.IllDefinedMemoryLayout;
if (ty.isSlice(mod)) return error.IllDefinedMemoryLayout;
if (val.isDeclRef()) return error.ReinterpretDeclRef;
return val.writeToMemory(Type.usize, mod, buffer);
},
@ -1261,7 +1261,7 @@ pub const Value = struct {
},
},
.Pointer => {
assert(!ty.isSlice()); // No well defined layout.
assert(!ty.isSlice(mod)); // No well defined layout.
if (val.isDeclRef()) return error.ReinterpretDeclRef;
return val.writeToPackedMemory(Type.usize, mod, buffer, bit_offset);
},
@ -1381,7 +1381,7 @@ pub const Value = struct {
return Value.initPayload(&payload.base);
},
.Pointer => {
assert(!ty.isSlice()); // No well defined layout.
assert(!ty.isSlice(mod)); // No well defined layout.
return readFromMemory(Type.usize, mod, buffer, arena);
},
.Optional => {
@ -1478,7 +1478,7 @@ pub const Value = struct {
},
},
.Pointer => {
assert(!ty.isSlice()); // No well defined layout.
assert(!ty.isSlice(mod)); // No well defined layout.
return readFromPackedMemory(Type.usize, mod, buffer, bit_offset, arena);
},
.Optional => {