spirv: make locals generic pointers

Taking the address of a local variable should result in a generic
pointer - too much code breaks if we do not do this. We cannot
lower locals into the generic storage class directly though, so
instead, lower the variables into the Function storage class
implicitly, and convert the pointer to a generic pointer.

Also Correct OpInboundsAccessChain generation (we only need
the one index).
This commit is contained in:
Robin Voetter 2022-11-30 23:28:07 +01:00
parent 2a8e784989
commit caf8461af8
No known key found for this signature in database
GPG Key ID: E755662F227CB468

View File

@ -1306,12 +1306,11 @@ pub const DeclGen = struct {
};
const result_id = self.spv.allocId();
const indexes = [_]IdRef{index};
try self.func.body.emit(self.spv.gpa, .OpInBoundsAccessChain, .{
try self.func.body.emit(self.spv.gpa, .OpInBoundsPtrAccessChain, .{
.id_result_type = spv_ptr_ty,
.id_result = result_id,
.base = slice_ptr,
.indexes = &indexes,
.element = index,
});
return result_id;
}
@ -1340,12 +1339,11 @@ pub const DeclGen = struct {
const elem_ptr = blk: {
const result_id = self.spv.allocId();
const indexes = [_]IdRef{index};
try self.func.body.emit(self.spv.gpa, .OpInBoundsAccessChain, .{
try self.func.body.emit(self.spv.gpa, .OpInBoundsPtrAccessChain, .{
.id_result_type = ptr_ty_id,
.id_result = result_id,
.base = slice_ptr,
.indexes = &indexes,
.element = index,
});
break :blk result_id;
};
@ -1448,22 +1446,45 @@ pub const DeclGen = struct {
fn airAlloc(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
if (self.liveness.isUnused(inst)) return null;
const ty = self.air.typeOfIndex(inst);
const result_type_id = try self.resolveTypeId(ty);
const result_ty_ref = try self.resolveType(ty, .direct);
const result_ty_id = self.typeId(result_ty_ref);
const result_id = self.spv.allocId();
// Rather than generating into code here, we're just going to generate directly into the functions section so that
// variable declarations appear in the first block of the function.
const storage_class = spirvStorageClass(ty.ptrAddressSpace());
const section = if (storage_class == .Function or storage_class == .Generic)
&self.func.prologue
else
&self.spv.sections.types_globals_constants;
const ptr_ty_id = switch (storage_class) {
.Generic => blk: {
const payload = try self.spv.arena.create(SpvType.Payload.Pointer);
payload.* = self.spv.typeRefType(result_ty_ref).payload(.pointer).*;
payload.storage_class = .Function;
break :blk try self.spv.resolveTypeId(SpvType.initPayload(&payload.base));
},
else => result_ty_id,
};
const actual_storage_class = switch (storage_class) {
.Generic, .Function => .Function,
else => storage_class,
};
const section = switch (storage_class) {
// SPIR-V requires that OpVariable declarations for locals go into the first block, so we are just going to
// directly generate them into func.prologue instead of the body.
.Generic, .Function => &self.func.prologue,
else => &self.spv.sections.types_globals_constants,
};
try section.emit(self.spv.gpa, .OpVariable, .{
.id_result_type = result_type_id,
.id_result_type = ptr_ty_id,
.id_result = result_id,
.storage_class = storage_class,
.storage_class = actual_storage_class,
});
if (storage_class == .Generic) {
const casted_result_id = self.spv.allocId();
try self.func.body.emit(self.spv.gpa, .OpPtrCastToGeneric, .{
.id_result_type = result_ty_id,
.id_result = casted_result_id,
.pointer = result_id,
});
return casted_result_id;
}
return result_id;
}