mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 20:37:54 +00:00
Merge pull request #9993 from Snektron/more-field-elem
stage2: More elemVal and elemPtr stuff
This commit is contained in:
commit
d49c601d62
19
src/Air.zig
19
src/Air.zig
@ -384,10 +384,10 @@ pub const Inst = struct {
|
||||
/// Result type is the element type of the slice operand.
|
||||
/// Uses the `bin_op` field.
|
||||
slice_elem_val,
|
||||
/// Given a pointer to a slice, and element index, return the element value at that index.
|
||||
/// Result type is the element type of the slice operand (2 element type operations).
|
||||
/// Uses the `bin_op` field.
|
||||
ptr_slice_elem_val,
|
||||
/// Given a slice value and element index, return a pointer to the element value at that index.
|
||||
/// Result type is a pointer to the element type of the slice operand.
|
||||
/// Uses the `ty_pl` field with payload `Bin`.
|
||||
slice_elem_ptr,
|
||||
/// Given a pointer value, and element index, return the element value at that index.
|
||||
/// Result type is the element type of the pointer operand.
|
||||
/// Uses the `bin_op` field.
|
||||
@ -396,11 +396,6 @@ pub const Inst = struct {
|
||||
/// Result type is pointer to the element type of the pointer operand.
|
||||
/// Uses the `ty_pl` field with payload `Bin`.
|
||||
ptr_elem_ptr,
|
||||
/// Given a pointer to a pointer, and element index, return the element value of the inner
|
||||
/// pointer at that index.
|
||||
/// Result type is the element type of the inner pointer operand.
|
||||
/// Uses the `bin_op` field.
|
||||
ptr_ptr_elem_val,
|
||||
/// Given a pointer to an array, return a slice.
|
||||
/// Uses the `ty_op` field.
|
||||
array_to_slice,
|
||||
@ -694,6 +689,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
|
||||
.constant,
|
||||
.struct_field_ptr,
|
||||
.struct_field_val,
|
||||
.slice_elem_ptr,
|
||||
.ptr_elem_ptr,
|
||||
.cmpxchg_weak,
|
||||
.cmpxchg_strong,
|
||||
@ -772,11 +768,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
|
||||
const ptr_ty = air.typeOf(datas[inst].bin_op.lhs);
|
||||
return ptr_ty.elemType();
|
||||
},
|
||||
.ptr_slice_elem_val, .ptr_ptr_elem_val => {
|
||||
const outer_ptr_ty = air.typeOf(datas[inst].bin_op.lhs);
|
||||
const inner_ptr_ty = outer_ptr_ty.elemType();
|
||||
return inner_ptr_ty.elemType();
|
||||
},
|
||||
.atomic_load => {
|
||||
const ptr_ty = air.typeOf(datas[inst].atomic_load.ptr);
|
||||
return ptr_ty.elemType();
|
||||
|
||||
@ -252,9 +252,7 @@ fn analyzeInst(
|
||||
.store,
|
||||
.array_elem_val,
|
||||
.slice_elem_val,
|
||||
.ptr_slice_elem_val,
|
||||
.ptr_elem_val,
|
||||
.ptr_ptr_elem_val,
|
||||
.shl,
|
||||
.shl_exact,
|
||||
.shl_sat,
|
||||
@ -362,7 +360,7 @@ fn analyzeInst(
|
||||
const extra = a.air.extraData(Air.StructField, inst_datas[inst].ty_pl.payload).data;
|
||||
return trackOperands(a, new_set, inst, main_tomb, .{ extra.struct_operand, .none, .none });
|
||||
},
|
||||
.ptr_elem_ptr => {
|
||||
.ptr_elem_ptr, .slice_elem_ptr => {
|
||||
const extra = a.air.extraData(Air.Bin, inst_datas[inst].ty_pl.payload).data;
|
||||
return trackOperands(a, new_set, inst, main_tomb, .{ extra.lhs, extra.rhs, .none });
|
||||
},
|
||||
|
||||
235
src/Sema.zig
235
src/Sema.zig
@ -333,6 +333,42 @@ pub const Block = struct {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn addSliceElemPtr(
|
||||
block: *Block,
|
||||
slice: Air.Inst.Ref,
|
||||
elem_index: Air.Inst.Ref,
|
||||
elem_ptr_ty: Type,
|
||||
) !Air.Inst.Ref {
|
||||
return block.addInst(.{
|
||||
.tag = .slice_elem_ptr,
|
||||
.data = .{ .ty_pl = .{
|
||||
.ty = try block.sema.addType(elem_ptr_ty),
|
||||
.payload = try block.sema.addExtra(Air.Bin{
|
||||
.lhs = slice,
|
||||
.rhs = elem_index,
|
||||
}),
|
||||
} },
|
||||
});
|
||||
}
|
||||
|
||||
pub fn addPtrElemPtr(
|
||||
block: *Block,
|
||||
array_ptr: Air.Inst.Ref,
|
||||
elem_index: Air.Inst.Ref,
|
||||
elem_ptr_ty: Type,
|
||||
) !Air.Inst.Ref {
|
||||
return block.addInst(.{
|
||||
.tag = .ptr_elem_ptr,
|
||||
.data = .{ .ty_pl = .{
|
||||
.ty = try block.sema.addType(elem_ptr_ty),
|
||||
.payload = try block.sema.addExtra(Air.Bin{
|
||||
.lhs = array_ptr,
|
||||
.rhs = elem_index,
|
||||
}),
|
||||
} },
|
||||
});
|
||||
}
|
||||
|
||||
pub fn addInst(block: *Block, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Ref {
|
||||
return Air.indexToRef(try block.addInstAsIndex(inst));
|
||||
}
|
||||
@ -11476,135 +11512,124 @@ fn elemPtr(
|
||||
else => return sema.fail(block, array_ptr_src, "expected pointer, found '{}'", .{array_ptr_ty}),
|
||||
};
|
||||
if (!array_ty.isIndexable()) {
|
||||
return sema.fail(block, src, "array access of non-array type '{}'", .{array_ty});
|
||||
}
|
||||
if (array_ty.isSinglePointer() and array_ty.elemType().zigTypeTag() == .Array) {
|
||||
// we have to deref the ptr operand to get the actual array pointer
|
||||
const array_ptr_deref = try sema.analyzeLoad(block, src, array_ptr, array_ptr_src);
|
||||
return sema.elemPtrArray(block, src, array_ptr_deref, elem_index, elem_index_src);
|
||||
}
|
||||
if (array_ty.zigTypeTag() == .Array) {
|
||||
return sema.elemPtrArray(block, src, array_ptr, elem_index, elem_index_src);
|
||||
return sema.fail(block, src, "array access of non-indexable type '{}'", .{array_ty});
|
||||
}
|
||||
|
||||
return sema.fail(block, src, "TODO implement more analyze elemptr", .{});
|
||||
switch (array_ty.zigTypeTag()) {
|
||||
.Pointer => {
|
||||
// In all below cases, we have to deref the ptr operand to get the actual array pointer.
|
||||
const array = try sema.analyzeLoad(block, array_ptr_src, array_ptr, array_ptr_src);
|
||||
const result_ty = try array_ty.elemPtrType(sema.arena);
|
||||
switch (array_ty.ptrSize()) {
|
||||
.Slice => {
|
||||
const maybe_slice_val = try sema.resolveDefinedValue(block, array_ptr_src, array);
|
||||
const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
|
||||
const runtime_src = if (maybe_slice_val) |slice_val| rs: {
|
||||
const index_val = maybe_index_val orelse break :rs elem_index_src;
|
||||
const index = @intCast(usize, index_val.toUnsignedInt());
|
||||
const elem_ptr = try slice_val.elemPtr(sema.arena, index);
|
||||
return sema.addConstant(result_ty, elem_ptr);
|
||||
} else array_ptr_src;
|
||||
|
||||
try sema.requireRuntimeBlock(block, runtime_src);
|
||||
return block.addSliceElemPtr(array, elem_index, result_ty);
|
||||
},
|
||||
.Many, .C => {
|
||||
const maybe_ptr_val = try sema.resolveDefinedValue(block, array_ptr_src, array);
|
||||
const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
|
||||
|
||||
const runtime_src = rs: {
|
||||
const ptr_val = maybe_ptr_val orelse break :rs array_ptr_src;
|
||||
const index_val = maybe_index_val orelse break :rs elem_index_src;
|
||||
const index = @intCast(usize, index_val.toUnsignedInt());
|
||||
const elem_ptr = try ptr_val.elemPtr(sema.arena, index);
|
||||
return sema.addConstant(result_ty, elem_ptr);
|
||||
};
|
||||
|
||||
try sema.requireRuntimeBlock(block, runtime_src);
|
||||
return block.addPtrElemPtr(array, elem_index, result_ty);
|
||||
},
|
||||
.One => {
|
||||
assert(array_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable
|
||||
return sema.elemPtrArray(block, array_ptr_src, array, elem_index, elem_index_src);
|
||||
},
|
||||
}
|
||||
},
|
||||
.Array => return sema.elemPtrArray(block, array_ptr_src, array_ptr, elem_index, elem_index_src),
|
||||
.Vector => return sema.fail(block, src, "TODO implement Sema for elemPtr for vector", .{}),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
fn elemVal(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
src: LazySrcLoc,
|
||||
array_maybe_ptr: Air.Inst.Ref,
|
||||
array: Air.Inst.Ref,
|
||||
elem_index: Air.Inst.Ref,
|
||||
elem_index_src: LazySrcLoc,
|
||||
) CompileError!Air.Inst.Ref {
|
||||
const array_ptr_src = src; // TODO better source location
|
||||
const maybe_ptr_ty = sema.typeOf(array_maybe_ptr);
|
||||
switch (maybe_ptr_ty.zigTypeTag()) {
|
||||
.Pointer => switch (maybe_ptr_ty.ptrSize()) {
|
||||
const array_src = src; // TODO better source location
|
||||
const array_ty = sema.typeOf(array);
|
||||
|
||||
if (!array_ty.isIndexable()) {
|
||||
return sema.fail(block, src, "array access of non-indexable type '{}'", .{array_ty});
|
||||
}
|
||||
|
||||
switch (array_ty.zigTypeTag()) {
|
||||
.Pointer => switch (array_ty.ptrSize()) {
|
||||
.Slice => {
|
||||
const maybe_slice_val = try sema.resolveDefinedValue(block, array_ptr_src, array_maybe_ptr);
|
||||
const maybe_slice_val = try sema.resolveDefinedValue(block, array_src, array);
|
||||
const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
|
||||
const runtime_src = if (maybe_slice_val) |slice_val| rs: {
|
||||
const index_val = maybe_index_val orelse break :rs elem_index_src;
|
||||
const index = @intCast(usize, index_val.toUnsignedInt());
|
||||
const elem_val = try slice_val.elemValue(sema.arena, index);
|
||||
return sema.addConstant(maybe_ptr_ty.elemType2(), elem_val);
|
||||
} else array_ptr_src;
|
||||
return sema.addConstant(array_ty.elemType2(), elem_val);
|
||||
} else array_src;
|
||||
|
||||
try sema.requireRuntimeBlock(block, runtime_src);
|
||||
return block.addBinOp(.slice_elem_val, array_maybe_ptr, elem_index);
|
||||
return block.addBinOp(.slice_elem_val, array, elem_index);
|
||||
},
|
||||
.Many, .C => {
|
||||
if (try sema.resolveDefinedValue(block, src, array_maybe_ptr)) |ptr_val| {
|
||||
_ = ptr_val;
|
||||
return sema.fail(block, src, "TODO implement Sema for elemVal for comptime known pointer", .{});
|
||||
}
|
||||
try sema.requireRuntimeBlock(block, src);
|
||||
return block.addBinOp(.ptr_elem_val, array_maybe_ptr, elem_index);
|
||||
const maybe_ptr_val = try sema.resolveDefinedValue(block, array_src, array);
|
||||
const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
|
||||
|
||||
const runtime_src = rs: {
|
||||
const ptr_val = maybe_ptr_val orelse break :rs array_src;
|
||||
const index_val = maybe_index_val orelse break :rs elem_index_src;
|
||||
const index = @intCast(usize, index_val.toUnsignedInt());
|
||||
const maybe_array_val = try ptr_val.pointerDeref(sema.arena);
|
||||
const array_val = maybe_array_val orelse break :rs array_src;
|
||||
const elem_val = try array_val.elemValue(sema.arena, index);
|
||||
return sema.addConstant(array_ty.elemType2(), elem_val);
|
||||
};
|
||||
|
||||
try sema.requireRuntimeBlock(block, runtime_src);
|
||||
return block.addBinOp(.ptr_elem_val, array, elem_index);
|
||||
},
|
||||
.One => {
|
||||
const indexable_ty = maybe_ptr_ty.childType();
|
||||
switch (indexable_ty.zigTypeTag()) {
|
||||
.Pointer => switch (indexable_ty.ptrSize()) {
|
||||
.Slice => {
|
||||
// We have a pointer to a slice and we want an element value.
|
||||
if (try sema.isComptimeKnown(block, src, array_maybe_ptr)) {
|
||||
const slice = try sema.analyzeLoad(block, src, array_maybe_ptr, array_ptr_src);
|
||||
if (try sema.resolveDefinedValue(block, src, slice)) |slice_val| {
|
||||
_ = slice_val;
|
||||
return sema.fail(block, src, "TODO implement Sema for elemVal for comptime known slice", .{});
|
||||
}
|
||||
try sema.requireRuntimeBlock(block, src);
|
||||
return block.addBinOp(.slice_elem_val, slice, elem_index);
|
||||
}
|
||||
try sema.requireRuntimeBlock(block, src);
|
||||
return block.addBinOp(.ptr_slice_elem_val, array_maybe_ptr, elem_index);
|
||||
},
|
||||
.Many, .C => {
|
||||
// We have a pointer to a pointer and we want an element value.
|
||||
if (try sema.isComptimeKnown(block, src, array_maybe_ptr)) {
|
||||
const ptr = try sema.analyzeLoad(block, src, array_maybe_ptr, array_ptr_src);
|
||||
if (try sema.resolveDefinedValue(block, src, ptr)) |ptr_val| {
|
||||
_ = ptr_val;
|
||||
return sema.fail(block, src, "TODO implement Sema for elemVal for comptime known pointer", .{});
|
||||
}
|
||||
try sema.requireRuntimeBlock(block, src);
|
||||
return block.addBinOp(.ptr_elem_val, ptr, elem_index);
|
||||
}
|
||||
try sema.requireRuntimeBlock(block, src);
|
||||
return block.addBinOp(.ptr_ptr_elem_val, array_maybe_ptr, elem_index);
|
||||
},
|
||||
.One => {
|
||||
const array_ty = indexable_ty.childType();
|
||||
if (array_ty.zigTypeTag() == .Array) {
|
||||
// We have a double pointer to an array, and we want an element
|
||||
// value. This can happen with this code for example:
|
||||
// var a: *[1]u8 = undefined; _ = a[0];
|
||||
const array_ptr = try sema.analyzeLoad(block, src, array_maybe_ptr, array_ptr_src);
|
||||
const ptr = try sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src);
|
||||
return sema.analyzeLoad(block, src, ptr, elem_index_src);
|
||||
} else return sema.fail(
|
||||
block,
|
||||
array_ptr_src,
|
||||
"expected pointer, found '{}'",
|
||||
.{array_ty},
|
||||
);
|
||||
},
|
||||
},
|
||||
.Array => {
|
||||
const ptr = try sema.elemPtr(block, src, array_maybe_ptr, elem_index, elem_index_src);
|
||||
return sema.analyzeLoad(block, src, ptr, elem_index_src);
|
||||
},
|
||||
else => return sema.fail(
|
||||
block,
|
||||
array_ptr_src,
|
||||
"expected pointer, found '{}'",
|
||||
.{indexable_ty},
|
||||
),
|
||||
}
|
||||
assert(array_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable
|
||||
const elem_ptr = try sema.elemPtr(block, array_src, array, elem_index, elem_index_src);
|
||||
return sema.analyzeLoad(block, array_src, elem_ptr, elem_index_src);
|
||||
},
|
||||
},
|
||||
.Array => {
|
||||
if (try sema.resolveMaybeUndefVal(block, src, array_maybe_ptr)) |array_val| {
|
||||
const elem_ty = maybe_ptr_ty.childType();
|
||||
const opt_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
|
||||
if (try sema.resolveMaybeUndefVal(block, array_src, array)) |array_val| {
|
||||
const elem_ty = array_ty.childType();
|
||||
if (array_val.isUndef()) return sema.addConstUndef(elem_ty);
|
||||
if (opt_index_val) |index_val| {
|
||||
const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
|
||||
if (maybe_index_val) |index_val| {
|
||||
const index = @intCast(usize, index_val.toUnsignedInt());
|
||||
const elem_val = try array_val.elemValue(sema.arena, index);
|
||||
return sema.addConstant(elem_ty, elem_val);
|
||||
}
|
||||
}
|
||||
try sema.requireRuntimeBlock(block, src);
|
||||
return block.addBinOp(.array_elem_val, array_maybe_ptr, elem_index);
|
||||
try sema.requireRuntimeBlock(block, array_src);
|
||||
return block.addBinOp(.array_elem_val, array, elem_index);
|
||||
},
|
||||
else => return sema.fail(
|
||||
block,
|
||||
array_ptr_src,
|
||||
"expected pointer or array; found '{}'",
|
||||
.{maybe_ptr_ty},
|
||||
),
|
||||
.Vector => return sema.fail(block, array_src, "TODO implement Sema for elemVal for vector", .{}),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
@ -11617,12 +11642,7 @@ fn elemPtrArray(
|
||||
elem_index_src: LazySrcLoc,
|
||||
) CompileError!Air.Inst.Ref {
|
||||
const array_ptr_ty = sema.typeOf(array_ptr);
|
||||
const pointee_type = array_ptr_ty.elemType().elemType();
|
||||
const result_ty = try Type.ptr(sema.arena, .{
|
||||
.pointee_type = pointee_type,
|
||||
.mutable = array_ptr_ty.ptrIsMutable(),
|
||||
.@"addrspace" = array_ptr_ty.ptrAddressSpace(),
|
||||
});
|
||||
const result_ty = try array_ptr_ty.elemPtrType(sema.arena);
|
||||
|
||||
if (try sema.resolveDefinedValue(block, src, array_ptr)) |array_ptr_val| {
|
||||
if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| {
|
||||
@ -11636,16 +11656,7 @@ fn elemPtrArray(
|
||||
}
|
||||
// TODO safety check for array bounds
|
||||
try sema.requireRuntimeBlock(block, src);
|
||||
return block.addInst(.{
|
||||
.tag = .ptr_elem_ptr,
|
||||
.data = .{ .ty_pl = .{
|
||||
.ty = try sema.addType(result_ty),
|
||||
.payload = try sema.addExtra(Air.Bin{
|
||||
.lhs = array_ptr,
|
||||
.rhs = elem_index,
|
||||
}),
|
||||
} },
|
||||
});
|
||||
return block.addPtrElemPtr(array_ptr, elem_index, result_ty);
|
||||
}
|
||||
|
||||
fn coerce(
|
||||
|
||||
@ -500,10 +500,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
||||
|
||||
.array_elem_val => try self.airArrayElemVal(inst),
|
||||
.slice_elem_val => try self.airSliceElemVal(inst),
|
||||
.ptr_slice_elem_val => try self.airPtrSliceElemVal(inst),
|
||||
.slice_elem_ptr => try self.airSliceElemPtr(inst),
|
||||
.ptr_elem_val => try self.airPtrElemVal(inst),
|
||||
.ptr_elem_ptr => try self.airPtrElemPtr(inst),
|
||||
.ptr_ptr_elem_val => try self.airPtrPtrElemVal(inst),
|
||||
|
||||
.constant => unreachable, // excluded from function bodies
|
||||
.const_ty => unreachable, // excluded from function bodies
|
||||
@ -1086,19 +1085,19 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
|
||||
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
|
||||
}
|
||||
|
||||
fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
|
||||
const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
|
||||
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement slice_elem_ptr for {}", .{self.target.cpu.arch});
|
||||
return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
|
||||
}
|
||||
|
||||
fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement array_elem_val for {}", .{self.target.cpu.arch});
|
||||
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
|
||||
}
|
||||
|
||||
fn airPtrSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const is_volatile = false; // TODO
|
||||
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||
const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement ptr_slice_elem_val for {}", .{self.target.cpu.arch});
|
||||
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
|
||||
}
|
||||
|
||||
fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const is_volatile = false; // TODO
|
||||
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||
@ -1113,13 +1112,6 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
|
||||
return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
|
||||
}
|
||||
|
||||
fn airPtrPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const is_volatile = false; // TODO
|
||||
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||
const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement ptr_ptr_elem_val for {}", .{self.target.cpu.arch});
|
||||
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
|
||||
}
|
||||
|
||||
fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||
_ = bin_op;
|
||||
|
||||
@ -848,10 +848,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
|
||||
.array_elem_val => try self.airArrayElemVal(inst),
|
||||
.slice_elem_val => try self.airSliceElemVal(inst),
|
||||
.ptr_slice_elem_val => try self.airPtrSliceElemVal(inst),
|
||||
.slice_elem_ptr => try self.airSliceElemPtr(inst),
|
||||
.ptr_elem_val => try self.airPtrElemVal(inst),
|
||||
.ptr_elem_ptr => try self.airPtrElemPtr(inst),
|
||||
.ptr_ptr_elem_val => try self.airPtrPtrElemVal(inst),
|
||||
|
||||
.constant => unreachable, // excluded from function bodies
|
||||
.const_ty => unreachable, // excluded from function bodies
|
||||
@ -1535,6 +1534,15 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
|
||||
}
|
||||
|
||||
fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
|
||||
const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
|
||||
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
|
||||
else => return self.fail("TODO implement slice_elem_ptr for {}", .{self.target.cpu.arch}),
|
||||
};
|
||||
return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
|
||||
}
|
||||
|
||||
fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
|
||||
@ -1543,15 +1551,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
|
||||
}
|
||||
|
||||
fn airPtrSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const is_volatile = false; // TODO
|
||||
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||
const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else switch (arch) {
|
||||
else => return self.fail("TODO implement ptr_slice_elem_val for {}", .{self.target.cpu.arch}),
|
||||
};
|
||||
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
|
||||
}
|
||||
|
||||
fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const is_volatile = false; // TODO
|
||||
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||
@ -1570,15 +1569,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
|
||||
}
|
||||
|
||||
fn airPtrPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const is_volatile = false; // TODO
|
||||
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||
const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else switch (arch) {
|
||||
else => return self.fail("TODO implement ptr_ptr_elem_val for {}", .{self.target.cpu.arch}),
|
||||
};
|
||||
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
|
||||
}
|
||||
|
||||
fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||
const result: MCValue = switch (arch) {
|
||||
|
||||
@ -1081,10 +1081,9 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
|
||||
.ptr_slice_ptr_ptr => try airPtrSliceFieldPtr(f, inst, ".ptr;\n"),
|
||||
|
||||
.ptr_elem_val => try airPtrElemVal(f, inst, "["),
|
||||
.ptr_ptr_elem_val => try airPtrElemVal(f, inst, "[0]["),
|
||||
.ptr_elem_ptr => try airPtrElemPtr(f, inst),
|
||||
.slice_elem_val => try airSliceElemVal(f, inst, "["),
|
||||
.ptr_slice_elem_val => try airSliceElemVal(f, inst, "[0]["),
|
||||
.slice_elem_ptr => try airSliceElemPtr(f, inst),
|
||||
.array_elem_val => try airArrayElemVal(f, inst),
|
||||
|
||||
.unwrap_errunion_payload => try airUnwrapErrUnionPay(f, inst),
|
||||
@ -1167,6 +1166,24 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index, prefix: []const u8) !CVal
|
||||
return local;
|
||||
}
|
||||
|
||||
fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||
if (f.liveness.isUnused(inst))
|
||||
return CValue.none;
|
||||
const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
|
||||
const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
|
||||
|
||||
const slice = try f.resolveInst(bin_op.lhs);
|
||||
const index = try f.resolveInst(bin_op.rhs);
|
||||
const writer = f.object.writer();
|
||||
const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const);
|
||||
try writer.writeAll(" = &");
|
||||
try f.writeCValue(writer, slice);
|
||||
try writer.writeByte('[');
|
||||
try f.writeCValue(writer, index);
|
||||
try writer.writeAll("];\n");
|
||||
return local;
|
||||
}
|
||||
|
||||
fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||
if (f.liveness.isUnused(inst)) return CValue.none;
|
||||
|
||||
|
||||
@ -1760,10 +1760,9 @@ pub const FuncGen = struct {
|
||||
|
||||
.array_elem_val => try self.airArrayElemVal(inst),
|
||||
.slice_elem_val => try self.airSliceElemVal(inst),
|
||||
.ptr_slice_elem_val => try self.airPtrSliceElemVal(inst),
|
||||
.slice_elem_ptr => try self.airSliceElemPtr(inst),
|
||||
.ptr_elem_val => try self.airPtrElemVal(inst),
|
||||
.ptr_elem_ptr => try self.airPtrElemPtr(inst),
|
||||
.ptr_ptr_elem_val => try self.airPtrPtrElemVal(inst),
|
||||
|
||||
.optional_payload => try self.airOptionalPayload(inst, false),
|
||||
.optional_payload_ptr => try self.airOptionalPayload(inst, true),
|
||||
@ -2159,28 +2158,18 @@ pub const FuncGen = struct {
|
||||
|
||||
const slice = try self.resolveInst(bin_op.lhs);
|
||||
const index = try self.resolveInst(bin_op.rhs);
|
||||
const base_ptr = self.builder.buildExtractValue(slice, 0, "");
|
||||
const indices: [1]*const llvm.Value = .{index};
|
||||
const ptr = self.builder.buildInBoundsGEP(base_ptr, &indices, indices.len, "");
|
||||
const ptr = self.sliceElemPtr(slice, index);
|
||||
return self.load(ptr, slice_ty);
|
||||
}
|
||||
|
||||
fn airPtrSliceElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
|
||||
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||
const slice_ty = self.air.typeOf(bin_op.lhs).childType();
|
||||
if (!slice_ty.isVolatilePtr() and self.liveness.isUnused(inst)) return null;
|
||||
fn airSliceElemPtr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
|
||||
if (self.liveness.isUnused(inst)) return null;
|
||||
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
|
||||
const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
|
||||
|
||||
const lhs = try self.resolveInst(bin_op.lhs);
|
||||
const rhs = try self.resolveInst(bin_op.rhs);
|
||||
|
||||
const base_ptr = ptr: {
|
||||
const ptr_field_ptr = self.builder.buildStructGEP(lhs, 0, "");
|
||||
break :ptr self.builder.buildLoad(ptr_field_ptr, "");
|
||||
};
|
||||
|
||||
const indices: [1]*const llvm.Value = .{rhs};
|
||||
const ptr = self.builder.buildInBoundsGEP(base_ptr, &indices, indices.len, "");
|
||||
return self.load(ptr, slice_ty);
|
||||
const slice = try self.resolveInst(bin_op.lhs);
|
||||
const index = try self.resolveInst(bin_op.rhs);
|
||||
return self.sliceElemPtr(slice, index);
|
||||
}
|
||||
|
||||
fn airArrayElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
|
||||
@ -2240,19 +2229,6 @@ pub const FuncGen = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn airPtrPtrElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
|
||||
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||
const ptr_ty = self.air.typeOf(bin_op.lhs).childType();
|
||||
if (!ptr_ty.isVolatilePtr() and self.liveness.isUnused(inst)) return null;
|
||||
|
||||
const lhs = try self.resolveInst(bin_op.lhs);
|
||||
const rhs = try self.resolveInst(bin_op.rhs);
|
||||
const base_ptr = self.builder.buildLoad(lhs, "");
|
||||
const indices: [1]*const llvm.Value = .{rhs};
|
||||
const ptr = self.builder.buildInBoundsGEP(base_ptr, &indices, indices.len, "");
|
||||
return self.load(ptr, ptr_ty);
|
||||
}
|
||||
|
||||
fn airStructFieldPtr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
|
||||
if (self.liveness.isUnused(inst))
|
||||
return null;
|
||||
@ -3608,6 +3584,16 @@ pub const FuncGen = struct {
|
||||
return self.builder.buildBitCast(union_field_ptr, result_llvm_ty, "");
|
||||
}
|
||||
|
||||
fn sliceElemPtr(
|
||||
self: *FuncGen,
|
||||
slice: *const llvm.Value,
|
||||
index: *const llvm.Value,
|
||||
) *const llvm.Value {
|
||||
const base_ptr = self.builder.buildExtractValue(slice, 0, "");
|
||||
const indices: [1]*const llvm.Value = .{index};
|
||||
return self.builder.buildInBoundsGEP(base_ptr, &indices, indices.len, "");
|
||||
}
|
||||
|
||||
fn getIntrinsic(self: *FuncGen, name: []const u8) *const llvm.Value {
|
||||
const id = llvm.lookupIntrinsicID(name.ptr, name.len);
|
||||
assert(id != 0);
|
||||
|
||||
@ -130,9 +130,7 @@ const Writer = struct {
|
||||
.store,
|
||||
.array_elem_val,
|
||||
.slice_elem_val,
|
||||
.ptr_slice_elem_val,
|
||||
.ptr_elem_val,
|
||||
.ptr_ptr_elem_val,
|
||||
.shl,
|
||||
.shl_exact,
|
||||
.shl_sat,
|
||||
@ -202,6 +200,7 @@ const Writer = struct {
|
||||
.loop,
|
||||
=> try w.writeBlock(s, inst),
|
||||
|
||||
.slice_elem_ptr => try w.writeSliceElemPtr(s, inst),
|
||||
.ptr_elem_ptr => try w.writePtrElemPtr(s, inst),
|
||||
.struct_field_ptr => try w.writeStructField(s, inst),
|
||||
.struct_field_val => try w.writeStructField(s, inst),
|
||||
@ -283,6 +282,15 @@ const Writer = struct {
|
||||
try s.print(", {d}", .{extra.field_index});
|
||||
}
|
||||
|
||||
fn writeSliceElemPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
|
||||
const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
|
||||
const extra = w.air.extraData(Air.Bin, ty_pl.payload).data;
|
||||
|
||||
try w.writeOperand(s, inst, 0, extra.lhs);
|
||||
try s.writeAll(", ");
|
||||
try w.writeOperand(s, inst, 1, extra.rhs);
|
||||
}
|
||||
|
||||
fn writePtrElemPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
|
||||
const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
|
||||
const extra = w.air.extraData(Air.Bin, ty_pl.payload).data;
|
||||
|
||||
14
src/type.zig
14
src/type.zig
@ -2520,6 +2520,20 @@ pub const Type = extern union {
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns the type of a pointer to an element.
|
||||
/// Asserts that the type is a pointer, and that the element type is indexable.
|
||||
/// For *[N]T, return *T
|
||||
/// For [*]T, returns *T
|
||||
/// For []T, returns *T
|
||||
/// Handles const-ness and address spaces in particular.
|
||||
pub fn elemPtrType(ptr_ty: Type, arena: *Allocator) !Type {
|
||||
return try Type.ptr(arena, .{
|
||||
.pointee_type = ptr_ty.elemType2(),
|
||||
.mutable = ptr_ty.ptrIsMutable(),
|
||||
.@"addrspace" = ptr_ty.ptrAddressSpace(),
|
||||
});
|
||||
}
|
||||
|
||||
fn shallowElemType(child_ty: Type) Type {
|
||||
return switch (child_ty.zigTypeTag()) {
|
||||
.Array, .Vector => child_ty.childType(),
|
||||
|
||||
@ -114,7 +114,7 @@ pub const Value = extern union {
|
||||
/// This Tag will never be seen by machine codegen backends. It is changed into a
|
||||
/// `decl_ref` when a comptime variable goes out of scope.
|
||||
decl_ref_mut,
|
||||
/// Pointer to a specific element of an array.
|
||||
/// Pointer to a specific element of an array, vector or slice.
|
||||
elem_ptr,
|
||||
/// Pointer to a specific field of a struct or union.
|
||||
field_ptr,
|
||||
@ -1792,17 +1792,23 @@ pub const Value = extern union {
|
||||
|
||||
/// Returns a pointer to the element value at the index.
|
||||
pub fn elemPtr(self: Value, allocator: *Allocator, index: usize) !Value {
|
||||
if (self.castTag(.elem_ptr)) |elem_ptr| {
|
||||
return Tag.elem_ptr.create(allocator, .{
|
||||
.array_ptr = elem_ptr.data.array_ptr,
|
||||
.index = elem_ptr.data.index + index,
|
||||
});
|
||||
switch (self.tag()) {
|
||||
.elem_ptr => {
|
||||
const elem_ptr = self.castTag(.elem_ptr).?.data;
|
||||
return Tag.elem_ptr.create(allocator, .{
|
||||
.array_ptr = elem_ptr.array_ptr,
|
||||
.index = elem_ptr.index + index,
|
||||
});
|
||||
},
|
||||
.slice => return Tag.elem_ptr.create(allocator, .{
|
||||
.array_ptr = self.castTag(.slice).?.data.ptr,
|
||||
.index = index,
|
||||
}),
|
||||
else => return Tag.elem_ptr.create(allocator, .{
|
||||
.array_ptr = self,
|
||||
.index = index,
|
||||
}),
|
||||
}
|
||||
|
||||
return Tag.elem_ptr.create(allocator, .{
|
||||
.array_ptr = self,
|
||||
.index = index,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn isUndef(self: Value) bool {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user