spirv: air aggregate_init for array

This commit is contained in:
Robin Voetter 2023-09-18 20:28:17 +02:00 committed by Andrew Kelley
parent 8d49b2ef4e
commit 26c279cca2

View File

@ -438,6 +438,8 @@ pub const DeclGen = struct {
/// Construct a struct at runtime.
/// result_ty_ref must be a struct type.
/// Constituents should be in `indirect` representation (as the elements of a struct should be).
/// Result is in `direct` representation.
fn constructStruct(self: *DeclGen, result_ty_ref: CacheRef, constituents: []const IdRef) !IdRef {
// The Khronos LLVM-SPIRV translator crashes because it cannot construct structs which'
// operands are not constant.
@ -474,6 +476,8 @@ pub const DeclGen = struct {
/// Construct a struct at runtime.
/// result_ty_ref must be an array type.
/// Constituents should be in `indirect` representation (as the elements of an array should be).
/// Result is in `direct` representation.
fn constructArray(self: *DeclGen, result_ty_ref: CacheRef, constituents: []const IdRef) !IdRef {
// The Khronos LLVM-SPIRV translator crashes because it cannot construct structs which'
// operands are not constant.
@ -1682,6 +1686,7 @@ pub const DeclGen = struct {
.not => try self.airNot(inst),
.array_to_slice => try self.airArrayToSlice(inst),
.aggregate_init => try self.airAggregateInit(inst),
.slice_ptr => try self.airSliceField(inst, 0),
.slice_len => try self.airSliceField(inst, 1),
@ -2430,6 +2435,8 @@ pub const DeclGen = struct {
}
fn airArrayToSlice(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
if (self.liveness.isUnused(inst)) return null;
const mod = self.module;
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const array_ptr_ty = self.typeOf(ty_op.operand);
@ -2453,6 +2460,40 @@ pub const DeclGen = struct {
return try self.constructStruct(slice_ty_ref, &.{ elem_ptr_id, len_id });
}
fn airAggregateInit(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
if (self.liveness.isUnused(inst)) return null;
const mod = self.module;
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const result_ty = self.typeOfIndex(inst);
const result_ty_ref = try self.resolveType(result_ty, .direct);
const len: usize = @intCast(result_ty.arrayLen(mod));
const elements: []const Air.Inst.Ref = @ptrCast(self.air.extra[ty_pl.payload..][0..len]);
switch (result_ty.zigTypeTag(mod)) {
.Vector => unreachable, // TODO
.Struct => unreachable, // TODO
.Array => {
const array_info = result_ty.arrayInfo(mod);
const n_elems: usize = @intCast(result_ty.arrayLenIncludingSentinel(mod));
const elem_ids = try self.gpa.alloc(IdRef, n_elems);
defer self.gpa.free(elem_ids);
for (elements, 0..) |elem_inst, i| {
const id = try self.resolve(elem_inst);
elem_ids[i] = try self.convertToIndirect(array_info.elem_type, id);
}
if (array_info.sentinel) |sentinel_val| {
elem_ids[n_elems - 1] = try self.constant(array_info.elem_type, sentinel_val, .indirect);
}
return try self.constructArray(result_ty_ref, elem_ids);
},
else => unreachable,
}
}
fn airSliceField(self: *DeclGen, inst: Air.Inst.Index, field: u32) !?IdRef {
if (self.liveness.isUnused(inst)) return null;
const ty_op = self.air.instructions.items(.data)[inst].ty_op;