aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/spirv.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen/spirv.zig')
-rw-r--r--src/codegen/spirv.zig132
1 files changed, 80 insertions, 52 deletions
diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig
index 53ec59d531..ed04ee475b 100644
--- a/src/codegen/spirv.zig
+++ b/src/codegen/spirv.zig
@@ -863,7 +863,7 @@ const DeclGen = struct {
const result_ty_id = try self.resolveType(ty, repr);
const ip = &mod.intern_pool;
- log.debug("lowering constant: ty = {}, val = {}", .{ ty.fmt(mod), val.fmtValue(mod) });
+ log.debug("lowering constant: ty = {}, val = {}", .{ ty.fmt(mod), val.fmtValue(mod, null) });
if (val.isUndefDeep(mod)) {
return self.spv.constUndef(result_ty_id);
}
@@ -983,10 +983,10 @@ const DeclGen = struct {
const int_ty = ty.intTagType(mod);
break :cache try self.constant(int_ty, int_val, repr);
},
- .ptr => return self.constantPtr(ty, val),
+ .ptr => return self.constantPtr(val),
.slice => |slice| {
const ptr_ty = ty.slicePtrFieldType(mod);
- const ptr_id = try self.constantPtr(ptr_ty, Value.fromInterned(slice.ptr));
+ const ptr_id = try self.constantPtr(Value.fromInterned(slice.ptr));
const len_id = try self.constant(Type.usize, Value.fromInterned(slice.len), .indirect);
return self.constructStruct(
ty,
@@ -1107,62 +1107,86 @@ const DeclGen = struct {
return cacheable_id;
}
- fn constantPtr(self: *DeclGen, ptr_ty: Type, ptr_val: Value) Error!IdRef {
+ fn constantPtr(self: *DeclGen, ptr_val: Value) Error!IdRef {
// TODO: Caching??
- const result_ty_id = try self.resolveType(ptr_ty, .direct);
- const mod = self.module;
+ const zcu = self.module;
+
+ if (ptr_val.isUndef(zcu)) {
+ const result_ty = ptr_val.typeOf(zcu);
+ const result_ty_id = try self.resolveType(result_ty, .direct);
+ return self.spv.constUndef(result_ty_id);
+ }
- if (ptr_val.isUndef(mod)) return self.spv.constUndef(result_ty_id);
+ var arena = std.heap.ArenaAllocator.init(self.gpa);
+ defer arena.deinit();
- switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) {
- .decl => |decl| return try self.constantDeclRef(ptr_ty, decl),
- .anon_decl => |anon_decl| return try self.constantAnonDeclRef(ptr_ty, anon_decl),
+ const derivation = try ptr_val.pointerDerivation(arena.allocator(), zcu);
+ return self.derivePtr(derivation);
+ }
+
+ fn derivePtr(self: *DeclGen, derivation: Value.PointerDeriveStep) Error!IdRef {
+ const zcu = self.module;
+ switch (derivation) {
+ .comptime_alloc_ptr, .comptime_field_ptr => unreachable,
.int => |int| {
- const ptr_id = self.spv.allocId();
+ const result_ty_id = try self.resolveType(int.ptr_ty, .direct);
// TODO: This can probably be an OpSpecConstantOp Bitcast, but
// that is not implemented by Mesa yet. Therefore, just generate it
// as a runtime operation.
+ const result_ptr_id = self.spv.allocId();
try self.func.body.emit(self.spv.gpa, .OpConvertUToPtr, .{
.id_result_type = result_ty_id,
- .id_result = ptr_id,
- .integer_value = try self.constant(Type.usize, Value.fromInterned(int), .direct),
+ .id_result = result_ptr_id,
+ .integer_value = try self.constant(Type.usize, try zcu.intValue(Type.usize, int.addr), .direct),
});
- return ptr_id;
+ return result_ptr_id;
+ },
+ .decl_ptr => |decl| {
+ const result_ptr_ty = try zcu.declPtr(decl).declPtrType(zcu);
+ return self.constantDeclRef(result_ptr_ty, decl);
},
- .eu_payload => unreachable, // TODO
- .opt_payload => unreachable, // TODO
- .comptime_field, .comptime_alloc => unreachable,
- .elem => |elem_ptr| {
- const parent_ptr_ty = Type.fromInterned(mod.intern_pool.typeOf(elem_ptr.base));
- const parent_ptr_id = try self.constantPtr(parent_ptr_ty, Value.fromInterned(elem_ptr.base));
- const index_id = try self.constInt(Type.usize, elem_ptr.index, .direct);
-
- const elem_ptr_id = try self.ptrElemPtr(parent_ptr_ty, parent_ptr_id, index_id);
-
- // TODO: Can we consolidate this in ptrElemPtr?
- const elem_ty = parent_ptr_ty.elemType2(mod); // use elemType() so that we get T for *[N]T.
- const elem_ptr_ty_id = try self.ptrType(elem_ty, self.spvStorageClass(parent_ptr_ty.ptrAddressSpace(mod)));
-
- // TODO: Can we remove this ID comparison?
- if (elem_ptr_ty_id == result_ty_id) {
- return elem_ptr_id;
+ .anon_decl_ptr => |ad| {
+ const result_ptr_ty = Type.fromInterned(ad.orig_ty);
+ return self.constantAnonDeclRef(result_ptr_ty, ad);
+ },
+ .eu_payload_ptr => @panic("TODO"),
+ .opt_payload_ptr => @panic("TODO"),
+ .field_ptr => |field| {
+ const parent_ptr_id = try self.derivePtr(field.parent.*);
+ const parent_ptr_ty = try field.parent.ptrType(zcu);
+ return self.structFieldPtr(field.result_ptr_ty, parent_ptr_ty, parent_ptr_id, field.field_idx);
+ },
+ .elem_ptr => |elem| {
+ const parent_ptr_id = try self.derivePtr(elem.parent.*);
+ const parent_ptr_ty = try elem.parent.ptrType(zcu);
+ const index_id = try self.constInt(Type.usize, elem.elem_idx, .direct);
+ return self.ptrElemPtr(parent_ptr_ty, parent_ptr_id, index_id);
+ },
+ .offset_and_cast => |oac| {
+ const parent_ptr_id = try self.derivePtr(oac.parent.*);
+ const parent_ptr_ty = try oac.parent.ptrType(zcu);
+ disallow: {
+ if (oac.byte_offset != 0) break :disallow;
+ // Allow changing the pointer type child only to restructure arrays.
+ // e.g. [3][2]T to T is fine, as is [2]T -> [2][1]T.
+ const src_base_ty = parent_ptr_ty.arrayBase(zcu)[0];
+ const dest_base_ty = oac.new_ptr_ty.arrayBase(zcu)[0];
+ if (self.getTarget().os.tag == .vulkan and src_base_ty.toIntern() != dest_base_ty.toIntern()) break :disallow;
+
+ const result_ty_id = try self.resolveType(oac.new_ptr_ty, .direct);
+ const result_ptr_id = self.spv.allocId();
+ try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
+ .id_result_type = result_ty_id,
+ .id_result = result_ptr_id,
+ .operand = parent_ptr_id,
+ });
+ return result_ptr_id;
}
- // This may happen when we have pointer-to-array and the result is
- // another pointer-to-array instead of a pointer-to-element.
- const result_id = self.spv.allocId();
- try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
- .id_result_type = result_ty_id,
- .id_result = result_id,
- .operand = elem_ptr_id,
+ return self.fail("Cannot perform pointer cast: '{}' to '{}'", .{
+ parent_ptr_ty.fmt(zcu),
+ oac.new_ptr_ty.fmt(zcu),
});
- return result_id;
- },
- .field => |field| {
- const base_ptr_ty = Type.fromInterned(mod.intern_pool.typeOf(field.base));
- const base_ptr = try self.constantPtr(base_ptr_ty, Value.fromInterned(field.base));
- const field_index: u32 = @intCast(field.index);
- return try self.structFieldPtr(ptr_ty, base_ptr_ty, base_ptr, field_index);
},
}
}
@@ -1170,7 +1194,7 @@ const DeclGen = struct {
fn constantAnonDeclRef(
self: *DeclGen,
ty: Type,
- anon_decl: InternPool.Key.Ptr.Addr.AnonDecl,
+ anon_decl: InternPool.Key.Ptr.BaseAddr.AnonDecl,
) !IdRef {
// TODO: Merge this function with constantDeclRef.
@@ -4456,16 +4480,20 @@ const DeclGen = struct {
) !IdRef {
const result_ty_id = try self.resolveType(result_ptr_ty, .direct);
- const mod = self.module;
- const object_ty = object_ptr_ty.childType(mod);
- switch (object_ty.zigTypeTag(mod)) {
- .Struct => switch (object_ty.containerLayout(mod)) {
+ const zcu = self.module;
+ const object_ty = object_ptr_ty.childType(zcu);
+ switch (object_ty.zigTypeTag(zcu)) {
+ .Pointer => {
+ assert(object_ty.isSlice(zcu));
+ return self.accessChain(result_ty_id, object_ptr, &.{field_index});
+ },
+ .Struct => switch (object_ty.containerLayout(zcu)) {
.@"packed" => unreachable, // TODO
else => {
return try self.accessChain(result_ty_id, object_ptr, &.{field_index});
},
},
- .Union => switch (object_ty.containerLayout(mod)) {
+ .Union => switch (object_ty.containerLayout(zcu)) {
.@"packed" => unreachable, // TODO
else => {
const layout = self.unionLayout(object_ty);
@@ -4475,7 +4503,7 @@ const DeclGen = struct {
return try self.spv.constUndef(result_ty_id);
}
- const storage_class = self.spvStorageClass(object_ptr_ty.ptrAddressSpace(mod));
+ const storage_class = self.spvStorageClass(object_ptr_ty.ptrAddressSpace(zcu));
const pl_ptr_ty_id = try self.ptrType(layout.payload_ty, storage_class);
const pl_ptr_id = try self.accessChain(pl_ptr_ty_id, object_ptr, &.{layout.payload_index});