diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2024-04-17 12:35:35 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-04-17 12:35:35 -0700 |
| commit | 1fb23813166e768a59bc7468d09bcb2e8e0f8f03 (patch) | |
| tree | ea6746763647264d62389f73768662184d32c82e /src/codegen/spirv.zig | |
| parent | 77abd3a96aa8c8c1277cdbb33d88149d4674d389 (diff) | |
| parent | 23062a5bed285f72e35651dd1e8b4a125b83dba0 (diff) | |
| download | zig-1fb23813166e768a59bc7468d09bcb2e8e0f8f03.tar.gz zig-1fb23813166e768a59bc7468d09bcb2e8e0f8f03.zip | |
Merge pull request #19630 from mlugg/comptime-ptr-access-5
compiler: rework comptime pointer representation and access
Diffstat (limited to 'src/codegen/spirv.zig')
| -rw-r--r-- | src/codegen/spirv.zig | 132 |
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}); |
