From 79f7481575005f9f63b5b3be8dd89b92b11b9c77 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sat, 26 Aug 2023 11:32:37 +0200 Subject: spirv: disable failing tests --- src/codegen/spirv.zig | 1 + 1 file changed, 1 insertion(+) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 33a864ea0a..22d7560806 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -1242,6 +1242,7 @@ pub const DeclGen = struct { }, .Int => { const int_info = ty.intInfo(mod); + // TODO: Integers in OpenCL kernels are always unsigned. return try self.intType(int_info.signedness, int_info.bits); }, .Enum => { -- cgit v1.2.3 From ced8a2c3a650fdddc489f97a1d12dd029856fe9e Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sat, 26 Aug 2023 12:19:28 +0200 Subject: spirv: add type_map to map AIR types to SPIR-V types This will help us both to make the implementation a little more efficient by caching emission for certain types like structs, and also allow us to attach extra information about types that we can use while lowering without performing a search over the entire type tree for some property. --- src/codegen/spirv.zig | 92 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 83 insertions(+), 9 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 22d7560806..2761a967de 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -12,6 +12,7 @@ const LazySrcLoc = Module.LazySrcLoc; const Air = @import("../Air.zig"); const Zir = @import("../Zir.zig"); const Liveness = @import("../Liveness.zig"); +const InternPool = @import("../InternPool.zig"); const spec = @import("spirv/spec.zig"); const Opcode = spec.Opcode; @@ -30,6 +31,15 @@ const SpvAssembler = @import("spirv/Assembler.zig"); const InstMap = std.AutoHashMapUnmanaged(Air.Inst.Index, IdRef); +/// We want to store some extra facts about types as mapped from Zig to SPIR-V. +/// This structure is used to keep that extra information, as well as +/// the cached reference to the type. +const SpvTypeInfo = struct { + ty_ref: CacheRef, +}; + +const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, SpvTypeInfo); + const IncomingBlock = struct { src_label_id: IdRef, break_value_id: IdRef, @@ -78,6 +88,15 @@ pub const DeclGen = struct { /// A map keeping track of which instruction generated which result-id. inst_results: InstMap = .{}, + /// A map that maps AIR intern pool indices to SPIR-V cache references (which + /// is basically the same thing except for SPIR-V). + /// This map is typically only used for structures that are deemed heavy enough + /// that it is worth to store them here. The SPIR-V module also interns types, + /// and so the main purpose of this map is to avoid recomputation and to + /// cache extra information about the type rather than to aid in validity + /// of the SPIR-V module. + type_map: TypeMap = .{}, + /// We need to keep track of result ids for block labels, as well as the 'incoming' /// blocks for a block. blocks: BlockMap = .{}, @@ -207,6 +226,7 @@ pub const DeclGen = struct { pub fn deinit(self: *DeclGen) void { self.args.deinit(self.gpa); self.inst_results.deinit(self.gpa); + self.type_map.deinit(self.gpa); self.blocks.deinit(self.gpa); self.func.deinit(self.gpa); } @@ -1180,6 +1200,9 @@ pub const DeclGen = struct { return try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect); } + const entry = try self.type_map.getOrPut(self.gpa, ty.toIntern()); + if (entry.found_existing) return entry.value_ptr.ty_ref; + var member_types = std.BoundedArray(CacheRef, 4){}; var member_names = std.BoundedArray(CacheString, 4){}; @@ -1222,10 +1245,16 @@ pub const DeclGen = struct { member_names.appendAssumeCapacity(try self.spv.resolveString("padding")); } - return try self.spv.resolve(.{ .struct_type = .{ + const ty_ref = try self.spv.resolve(.{ .struct_type = .{ .member_types = member_types.slice(), .member_names = member_names.slice(), } }); + + entry.value_ptr.* = .{ + .ty_ref = ty_ref, + }; + + return ty_ref; } /// Turn a Zig type into a SPIR-V Type, and return a reference to it. @@ -1268,15 +1297,26 @@ pub const DeclGen = struct { return try self.spv.resolve(.{ .float_type = .{ .bits = bits } }); }, .Array => { + const entry = try self.type_map.getOrPut(self.gpa, ty.toIntern()); + if (entry.found_existing) return entry.value_ptr.ty_ref; + const elem_ty = ty.childType(mod); - const elem_ty_ref = try self.resolveType(elem_ty, .direct); + const elem_ty_ref = try self.resolveType(elem_ty, .indirect); const total_len = std.math.cast(u32, ty.arrayLenIncludingSentinel(mod)) orelse { return self.fail("array type of {} elements is too large", .{ty.arrayLenIncludingSentinel(mod)}); }; - return self.spv.arrayType(total_len, elem_ty_ref); + const ty_ref = try self.spv.arrayType(total_len, elem_ty_ref); + entry.value_ptr.* = .{ + .ty_ref = ty_ref, + }; + return ty_ref; }, .Fn => switch (repr) { .direct => { + const entry = try self.type_map.getOrPut(self.gpa, ty.toIntern()); + if (entry.found_existing) return entry.value_ptr.ty_ref; + + const ip = &mod.intern_pool; const fn_info = mod.typeToFunc(ty).?; // TODO: Put this somewhere in Sema.zig if (fn_info.is_var_args) @@ -1289,10 +1329,16 @@ pub const DeclGen = struct { } const return_ty_ref = try self.resolveType(fn_info.return_type.toType(), .direct); - return try self.spv.resolve(.{ .function_type = .{ + const ty_ref = try self.spv.resolve(.{ .function_type = .{ .return_type = return_ty_ref, .parameters = param_ty_refs, } }); + + entry.value_ptr.* = .{ + .ty_ref = ty_ref, + }; + + return ty_ref; }, .indirect => { // TODO: Represent function pointers properly. @@ -1338,6 +1384,9 @@ pub const DeclGen = struct { } }); }, .Struct => { + const entry = try self.type_map.getOrPut(self.gpa, ty.toIntern()); + if (entry.found_existing) return entry.value_ptr.ty_ref; + const struct_type = switch (ip.indexToKey(ty.toIntern())) { .anon_struct_type => |tuple| { const member_types = try self.gpa.alloc(CacheRef, tuple.values.len); @@ -1351,9 +1400,14 @@ pub const DeclGen = struct { member_index += 1; } - return try self.spv.resolve(.{ .struct_type = .{ + const ty_ref = try self.spv.resolve(.{ .struct_type = .{ .member_types = member_types[0..member_index], } }); + + entry.value_ptr.* = .{ + .ty_ref = ty_ref, + }; + return ty_ref; }, .struct_type => |struct_type| struct_type, else => unreachable, @@ -1361,7 +1415,6 @@ pub const DeclGen = struct { if (struct_type.layout == .Packed) { return try self.resolveType(struct_type.backingIntType(ip).toType(), .direct); - } var member_types = std.ArrayList(CacheRef).init(self.gpa); defer member_types.deinit(); @@ -1379,11 +1432,16 @@ pub const DeclGen = struct { const name = ip.stringToSlice(try mod.declPtr(struct_type.decl.unwrap().?).getFullyQualifiedName(mod)); - return try self.spv.resolve(.{ .struct_type = .{ + const ty_ref = try self.spv.resolve(.{ .struct_type = .{ .name = try self.spv.resolveString(name), .member_types = member_types.items, .member_names = member_names.items, } }); + + entry.value_ptr.* = .{ + .ty_ref = ty_ref, + }; + return ty_ref; }, .Optional => { const payload_ty = ty.optionalChild(mod); @@ -1400,15 +1458,23 @@ pub const DeclGen = struct { return payload_ty_ref; } + const entry = try self.type_map.getOrPut(self.gpa, ty.toIntern()); + if (entry.found_existing) return entry.value_ptr.ty_ref; + const bool_ty_ref = try self.resolveType(Type.bool, .indirect); - return try self.spv.resolve(.{ .struct_type = .{ + const ty_ref = try self.spv.resolve(.{ .struct_type = .{ .member_types = &.{ payload_ty_ref, bool_ty_ref }, .member_names = &.{ try self.spv.resolveString("payload"), try self.spv.resolveString("valid"), }, } }); + + entry.value_ptr.* = .{ + .ty_ref = ty_ref, + }; + return ty_ref; }, .Union => return try self.resolveUnionType(ty, null), .ErrorSet => return try self.intType(.unsigned, 16), @@ -1421,6 +1487,9 @@ pub const DeclGen = struct { return error_ty_ref; } + const entry = try self.type_map.getOrPut(self.gpa, ty.toIntern()); + if (entry.found_existing) return entry.value_ptr.ty_ref; + const payload_ty_ref = try self.resolveType(payload_ty, .indirect); var member_types: [2]CacheRef = undefined; @@ -1443,10 +1512,15 @@ pub const DeclGen = struct { // TODO: ABI padding? } - return try self.spv.resolve(.{ .struct_type = .{ + const ty_ref = try self.spv.resolve(.{ .struct_type = .{ .member_types = &member_types, .member_names = &member_names, } }); + + entry.value_ptr.* = .{ + .ty_ref = ty_ref, + }; + return ty_ref; }, .Null, -- cgit v1.2.3 From ece52640ebeac867e0f69116f99bc14f5590bb9a Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sat, 16 Sep 2023 00:53:39 +0200 Subject: spirv: construct error union at runtime --- src/codegen/spirv.zig | 56 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 7 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 2761a967de..67707925fc 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -1021,9 +1021,10 @@ pub const DeclGen = struct { } /// This function generates a load for a constant in direct (ie, non-memory) representation. - /// When the constant is simple, it can be generated directly using OpConstant instructions. When - /// the constant is more complicated however, it needs to be lowered to an indirect constant, which - /// is then loaded using OpLoad. Such values are loaded into the UniformConstant storage class by default. + /// When the constant is simple, it can be generated directly using OpConstant instructions. + /// When the constant is more complicated however, it needs to be constructed using multiple values. This + /// is done by emitting a sequence of instructions that initialize the value. + // /// This function should only be called during function code generation. fn constant(self: *DeclGen, ty: Type, arg_val: Value, repr: Repr) !IdRef { const mod = self.module; @@ -1037,7 +1038,7 @@ pub const DeclGen = struct { } log.debug("constant: ty = {}, val = {}", .{ ty.fmt(self.module), val.fmtValue(ty, self.module) }); - if (val.isUndef(mod)) { + if (val.isUndefDeep(mod)) { return self.spv.constUndef(result_ty_ref); } @@ -1060,8 +1061,7 @@ pub const DeclGen = struct { .inferred_error_set_type, => unreachable, // types, not values - .undef => unreachable, // handled above - .runtime_value => unreachable, // ??? + .undef, .runtime_value => unreachable, // handled above .variable, .extern_func, @@ -1103,6 +1103,49 @@ pub const DeclGen = struct { const value = try mod.getErrorValue(err.name); return try self.spv.constInt(result_ty_ref, value); }, + .error_union => |error_union| { + // TODO: Error unions may be constructed with constant instructions if the payload type + // allows it. For now, just generate it here regardless. + const err_ty = switch (error_union.val) { + .err_name => ty.errorUnionSet(mod), + .payload => Type.err_int, + }; + const err_val = switch (error_union.val) { + .err_name => |err_name| (try mod.intern(.{ .err = .{ + .ty = ty.errorUnionSet(mod).toIntern(), + .name = err_name, + } })).toValue(), + .payload => try mod.intValue(Type.err_int, 0), + }; + const payload_ty = ty.errorUnionPayload(mod); + const eu_layout = self.errorUnionLayout(payload_ty); + if (!eu_layout.payload_has_bits) { + // We use the error type directly as the type. + return try self.constant(err_ty, err_val, .indirect); + } + + const payload_val = switch (error_union.val) { + .err_name => try mod.intern(.{ .undef = payload_ty.toIntern() }), + .payload => |payload| payload, + }.toValue(); + + var constituents: [2]IdRef = undefined; + if (eu_layout.error_first) { + constituents[0] = try self.constant(err_ty, err_val, .indirect); + constituents[1] = try self.constant(payload_ty, payload_val, .indirect); + } else { + constituents[0] = try self.constant(payload_ty, payload_val, .indirect); + constituents[1] = try self.constant(err_ty, err_val, .indirect); + } + + const result_id = self.spv.allocId(); + try self.func.body.emit(self.spv.gpa, .OpCompositeConstruct, .{ + .id_result_type = self.typeId(result_ty_ref), + .id_result = result_id, + .constituents = &constituents, + }); + return result_id; + }, // TODO: We can handle most pointers here (decl refs etc), because now they emit an extra // OpVariable that is not really required. else => { @@ -1316,7 +1359,6 @@ pub const DeclGen = struct { const entry = try self.type_map.getOrPut(self.gpa, ty.toIntern()); if (entry.found_existing) return entry.value_ptr.ty_ref; - const ip = &mod.intern_pool; const fn_info = mod.typeToFunc(ty).?; // TODO: Put this somewhere in Sema.zig if (fn_info.is_var_args) -- cgit v1.2.3 From aeaaa953a04c42fb2068be559155e237f7e931d2 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sat, 16 Sep 2023 00:58:22 +0200 Subject: spirv: assign type names to (error) unions --- src/codegen/spirv.zig | 15 ++++++++++++--- src/link/SpirV.zig | 4 ++-- 2 files changed, 14 insertions(+), 5 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 67707925fc..1ebc09d315 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -1178,6 +1178,14 @@ pub const DeclGen = struct { } } + // Turn a Zig type's name into a cache reference. + fn resolveTypeName(self: *DeclGen, ty: Type) !CacheString { + var name = std.ArrayList(u8).init(self.gpa); + defer name.deinit(); + try ty.print(name.writer(), self.module); + return try self.spv.resolveString(name.items); + } + /// Turn a Zig type into a SPIR-V Type, and return its type result-id. fn resolveTypeId(self: *DeclGen, ty: Type) !IdResultType { const type_ref = try self.resolveType(ty, .direct); @@ -1289,6 +1297,7 @@ pub const DeclGen = struct { } const ty_ref = try self.spv.resolve(.{ .struct_type = .{ + .name = try self.resolveTypeName(ty), .member_types = member_types.slice(), .member_names = member_names.slice(), } }); @@ -1443,6 +1452,7 @@ pub const DeclGen = struct { } const ty_ref = try self.spv.resolve(.{ .struct_type = .{ + .name = try self.resolveTypeName(ty), .member_types = member_types[0..member_index], } }); @@ -1472,10 +1482,8 @@ pub const DeclGen = struct { try member_names.append(try self.spv.resolveString(field_name)); } - const name = ip.stringToSlice(try mod.declPtr(struct_type.decl.unwrap().?).getFullyQualifiedName(mod)); - const ty_ref = try self.spv.resolve(.{ .struct_type = .{ - .name = try self.spv.resolveString(name), + .name = try self.resolveTypeName(ty), .member_types = member_types.items, .member_names = member_names.items, } }); @@ -1555,6 +1563,7 @@ pub const DeclGen = struct { } const ty_ref = try self.spv.resolve(.{ .struct_type = .{ + .name = try self.resolveTypeName(ty), .member_types = &member_types, .member_names = &member_names, } }); diff --git a/src/link/SpirV.zig b/src/link/SpirV.zig index bf133bbb16..7ad4c846d4 100644 --- a/src/link/SpirV.zig +++ b/src/link/SpirV.zig @@ -111,7 +111,7 @@ pub fn updateFunc(self: *SpirV, module: *Module, func_index: InternPool.Index, a const func = module.funcInfo(func_index); const decl = module.declPtr(func.owner_decl); - log.debug("lowering function {s}", .{ module.intern_pool.stringToSlice(decl.name) }); + log.debug("lowering function {s}", .{module.intern_pool.stringToSlice(decl.name)}); var decl_gen = codegen.DeclGen.init(self.base.allocator, module, &self.spv, &self.decl_link); defer decl_gen.deinit(); @@ -127,7 +127,7 @@ pub fn updateDecl(self: *SpirV, module: *Module, decl_index: Module.Decl.Index) } const decl = module.declPtr(decl_index); - log.debug("lowering declaration {s}", .{ module.intern_pool.stringToSlice(decl.name) }); + log.debug("lowering declaration {s}", .{module.intern_pool.stringToSlice(decl.name)}); var decl_gen = codegen.DeclGen.init(self.base.allocator, module, &self.spv, &self.decl_link); defer decl_gen.deinit(); -- cgit v1.2.3 From cc13864dfbeeebab7dff6ef0d38195c44005caba Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sat, 16 Sep 2023 01:02:31 +0200 Subject: spirv: lower enum_tag constants --- src/codegen/spirv.zig | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 1ebc09d315..e193a355d0 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -1146,6 +1146,11 @@ pub const DeclGen = struct { }); return result_id; }, + .enum_tag => { + const int_val = try val.intFromEnum(ty, mod); + const int_ty = ty.intTagType(mod); + return try self.constant(int_ty, int_val, repr); + }, // TODO: We can handle most pointers here (decl refs etc), because now they emit an extra // OpVariable that is not really required. else => { -- cgit v1.2.3 From 3e2553c7123e914f34bdd0c29dcb2683ad3a6726 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sat, 16 Sep 2023 01:31:21 +0200 Subject: spirv: lower ptr constants --- src/codegen/spirv.zig | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index e193a355d0..484f9b0896 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -450,6 +450,42 @@ pub const DeclGen = struct { return result_id; } + fn constructDeclRef(self: *DeclGen, ty: Type, decl_index: Decl.Index) !IdRef { + const mod = self.module; + const ty_ref = try self.resolveType(ty, .direct); + const ty_id = self.typeId(ty_ref); + const decl = mod.declPtr(decl_index); + const spv_decl_index = try self.resolveDecl(decl_index); + switch (mod.intern_pool.indexToKey(decl.val.ip_index)) { + .func => { + // TODO: Properly lower function pointers. For now we are going to hack around it and + // just generate an empty pointer. Function pointers are represented by usize for now, + // though. + // TODO: Add dependency + return try self.spv.constInt(ty_ref, 0); + }, + .extern_func => unreachable, // TODO + else => { + const decl_id = self.spv.declPtr(spv_decl_index).result_id; + try self.func.decl_deps.put(self.spv.gpa, spv_decl_index, {}); + + switch (decl.@"addrspace") { + .generic => { + // Pointer should be generic, but is actually placed in CrossWorkgroup. + const result_id = self.spv.allocId(); + try self.func.body.emit(self.spv.gpa, .OpPtrCastToGeneric, .{ + .id_result_type = ty_id, + .id_result = result_id, + .pointer = decl_id, + }); + return result_id; + }, + else => return decl_id, // Variable is already correct, probably. Maybe needs a bitcast? + } + }, + } + } + const IndirectConstantLowering = struct { const undef = 0xAA; @@ -1151,6 +1187,42 @@ pub const DeclGen = struct { const int_ty = ty.intTagType(mod); return try self.constant(int_ty, int_val, repr); }, + .ptr => |ptr| { + const ptr_ty = switch (ptr.len) { + .none => ty, + else => ty.slicePtrFieldType(mod), + }; + const ptr_id = switch (ptr.addr) { + .decl => |decl| try self.constructDeclRef(ptr_ty, decl), + .mut_decl => |mut_decl| try self.constructDeclRef(ptr_ty, mut_decl.decl), // TODO + .int => |int| blk: { + const ptr_id = self.spv.allocId(); + // TODO: This can probably be an OpSpecConstantOp Bitcast, but + // that is not implemented by Mesa yet. Therefore, just generate it + // as a runtime operation. + try self.func.body.emit(self.spv.gpa, .OpConvertUToPtr, .{ + .id_result_type = try self.resolveTypeId(ptr_ty), + .id_result = ptr_id, + .integer_value = try self.constant(Type.usize, int.toValue(), .direct), + }); + break :blk ptr_id; + }, + .comptime_field => unreachable, + else => |tag| return self.todo("pointer value of type {s}", .{@tagName(tag)}), + }; + if (ptr.len == .none) { + return ptr_id; + } + + const len_id = try self.constant(Type.usize, ptr.len.toValue(), .indirect); + const result_id = self.spv.allocId(); + try self.func.body.emit(self.spv.gpa, .OpCompositeConstruct, .{ + .id_result_type = self.typeId(result_ty_ref), + .id_result = result_id, + .constituents = &.{ ptr_id, len_id }, + }); + return result_id; + }, // TODO: We can handle most pointers here (decl refs etc), because now they emit an extra // OpVariable that is not really required. else => { -- cgit v1.2.3 From ae17831cc060840c881c9514ef98c0637c446760 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sat, 16 Sep 2023 01:44:25 +0200 Subject: spirv: lower opt constants --- src/codegen/spirv.zig | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 484f9b0896..fa4ea4ec1b 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -1223,6 +1223,40 @@ pub const DeclGen = struct { }); return result_id; }, + .opt => { + const payload_ty = ty.optionalChild(mod); + const maybe_payload_val = val.optionalValue(mod); + + if (!payload_ty.hasRuntimeBits(mod)) { + return try self.constBool(maybe_payload_val != null, .indirect); + } else if (ty.optionalReprIsPayload(mod)) { + // Optional representation is a nullable pointer or slice. + if (maybe_payload_val) |payload_val| { + return try self.constant(payload_ty, payload_val, .indirect); + } else { + const ptr_ty_ref = try self.resolveType(ty, .indirect); + return self.spv.constNull(ptr_ty_ref); + } + } + + // Optional representation is a structure. + // { Payload, Bool } + + const payload_id = if (maybe_payload_val) |payload_val| + try self.constant(payload_ty, payload_val, .indirect) + else + try self.spv.constUndef(try self.resolveType(payload_ty, .indirect)); + + const has_pl_id = try self.constBool(maybe_payload_val != null, .indirect); + + const result_id = self.spv.allocId(); + try self.func.body.emit(self.spv.gpa, .OpCompositeConstruct, .{ + .id_result_type = self.typeId(result_ty_ref), + .id_result = result_id, + .constituents = &.{ payload_id, has_pl_id }, + }); + return result_id; + }, // TODO: We can handle most pointers here (decl refs etc), because now they emit an extra // OpVariable that is not really required. else => { -- cgit v1.2.3 From 001d76a4129da9998ebe25edc2583c8f3c75798a Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sat, 16 Sep 2023 02:06:42 +0200 Subject: spirv: lower array aggregate at runtime --- src/codegen/spirv.zig | 71 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 27 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index fa4ea4ec1b..9c65ddc505 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -1066,9 +1066,10 @@ pub const DeclGen = struct { const mod = self.module; const target = self.getTarget(); const result_ty_ref = try self.resolveType(ty, repr); + const ip = &mod.intern_pool; var val = arg_val; - switch (mod.intern_pool.indexToKey(val.toIntern())) { + switch (ip.indexToKey(val.toIntern())) { .runtime_value => |rt| val = rt.val.toValue(), else => {}, } @@ -1078,7 +1079,7 @@ pub const DeclGen = struct { return self.spv.constUndef(result_ty_ref); } - switch (mod.intern_pool.indexToKey(val.toIntern())) { + switch (ip.indexToKey(val.toIntern())) { .int_type, .ptr_type, .array_type, @@ -1174,13 +1175,7 @@ pub const DeclGen = struct { constituents[1] = try self.constant(err_ty, err_val, .indirect); } - const result_id = self.spv.allocId(); - try self.func.body.emit(self.spv.gpa, .OpCompositeConstruct, .{ - .id_result_type = self.typeId(result_ty_ref), - .id_result = result_id, - .constituents = &constituents, - }); - return result_id; + return try self.constructStruct(result_ty_ref, &constituents); }, .enum_tag => { const int_val = try val.intFromEnum(ty, mod); @@ -1215,13 +1210,7 @@ pub const DeclGen = struct { } const len_id = try self.constant(Type.usize, ptr.len.toValue(), .indirect); - const result_id = self.spv.allocId(); - try self.func.body.emit(self.spv.gpa, .OpCompositeConstruct, .{ - .id_result_type = self.typeId(result_ty_ref), - .id_result = result_id, - .constituents = &.{ ptr_id, len_id }, - }); - return result_id; + return try self.constructStruct(result_ty_ref, &.{ ptr_id, len_id }); }, .opt => { const payload_ty = ty.optionalChild(mod); @@ -1242,23 +1231,51 @@ pub const DeclGen = struct { // Optional representation is a structure. // { Payload, Bool } + const has_pl_id = try self.constBool(maybe_payload_val != null, .indirect); const payload_id = if (maybe_payload_val) |payload_val| try self.constant(payload_ty, payload_val, .indirect) else try self.spv.constUndef(try self.resolveType(payload_ty, .indirect)); - const has_pl_id = try self.constBool(maybe_payload_val != null, .indirect); - - const result_id = self.spv.allocId(); - try self.func.body.emit(self.spv.gpa, .OpCompositeConstruct, .{ - .id_result_type = self.typeId(result_ty_ref), - .id_result = result_id, - .constituents = &.{ payload_id, has_pl_id }, - }); - return result_id; + return try self.constructStruct(result_ty_ref, &.{ payload_id, has_pl_id }); + }, + .aggregate => |aggregate| switch (ip.indexToKey(ty.ip_index)) { + .array_type => |array_type| { + const elem_ty = array_type.child.toType(); + const elem_ty_ref = try self.resolveType(elem_ty, .indirect); + + var constituents = try self.gpa.alloc(IdRef, ty.arrayLenIncludingSentinel(mod)); + defer self.gpa.free(constituents); + + switch (aggregate.storage) { + .bytes => |bytes| { + // TODO: This is really space inefficient, perhaps there is a better + // way to do it? + for (bytes, 0..) |byte, i| { + constituents[i] = try self.spv.constInt(elem_ty_ref, byte); + } + }, + .elems => |elems| { + for (0..@as(usize, @intCast(array_type.len))) |i| { + constituents[i] = try self.constant(elem_ty, elems[i].toValue(), .indirect); + } + }, + .repeated_elem => |elem| { + const val_id = try self.constant(elem_ty, elem.toValue(), .indirect); + for (0..@as(usize, @intCast(array_type.len))) |i| { + constituents[i] = val_id; + } + }, + } + if (array_type.sentinel != .none) { + constituents[constituents.len - 1] = try self.constant(elem_ty, array_type.sentinel.toValue(), .indirect); + } + return try self.constructStruct(result_ty_ref, constituents); + }, + .vector_type => return self.todo("constant aggregate of type {}", .{ty.fmt(mod)}), + .anon_struct_type => unreachable, // TODO + else => unreachable, }, - // TODO: We can handle most pointers here (decl refs etc), because now they emit an extra - // OpVariable that is not really required. else => { // The value cannot be generated directly, so generate it as an indirect constant, // and then perform an OpLoad. -- cgit v1.2.3 From d06862b759ce59d97049043057f95911e7557077 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sat, 16 Sep 2023 02:15:02 +0200 Subject: spirv: lower struct aggregate initialization at runtime --- src/codegen/spirv.zig | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 9c65ddc505..ff499aded3 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -1244,7 +1244,7 @@ pub const DeclGen = struct { const elem_ty = array_type.child.toType(); const elem_ty_ref = try self.resolveType(elem_ty, .indirect); - var constituents = try self.gpa.alloc(IdRef, ty.arrayLenIncludingSentinel(mod)); + const constituents = try self.gpa.alloc(IdRef, ty.arrayLenIncludingSentinel(mod)); defer self.gpa.free(constituents); switch (aggregate.storage) { @@ -1272,8 +1272,33 @@ pub const DeclGen = struct { } return try self.constructStruct(result_ty_ref, constituents); }, - .vector_type => return self.todo("constant aggregate of type {}", .{ty.fmt(mod)}), - .anon_struct_type => unreachable, // TODO + .struct_type => { + const struct_ty = mod.typeToStruct(ty).?; + if (struct_ty.layout == .Packed) { + return self.todo("packed struct constants", .{}); + } + + var constituents = std.ArrayList(IdRef).init(self.gpa); + defer constituents.deinit(); + + for (struct_ty.fields.values(), 0..) |field, i| { + if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue; + + const field_val = switch (aggregate.storage) { + .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ + .ty = field.ty.toIntern(), + .storage = .{ .u64 = bytes[i] }, + } }), + .elems => |elems| elems[i], + .repeated_elem => |elem| elem, + }; + const field_id = try self.constant(field.ty, field_val.toValue(), .indirect); + try constituents.append(field_id); + } + + return try self.constructStruct(result_ty_ref, constituents.items); + }, + .vector_type, .anon_struct_type => unreachable, // TODO else => unreachable, }, else => { -- cgit v1.2.3 From 240f9d740d4d04619de6c6c7dbad46c78e38c831 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sat, 16 Sep 2023 02:53:14 +0200 Subject: spirv: lower union initialization at runtime --- src/codegen/spirv.zig | 76 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 5 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index ff499aded3..dcf717950b 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -1301,6 +1301,72 @@ pub const DeclGen = struct { .vector_type, .anon_struct_type => unreachable, // TODO else => unreachable, }, + .un => |un| { + // To initialize a union, generate a temporary variable with the + // type that has the right field active, then pointer-cast and store + // the active field, and finally load and return the entire union. + + const layout = ty.unionGetLayout(mod); + const union_ty = mod.typeToUnion(ty).?; + + if (union_ty.getLayout(ip) == .Packed) { + return self.todo("packed union types", .{}); + } else if (layout.payload_size == 0) { + // No payload, so represent this as just the tag type. + return try self.constant(ty.unionTagTypeSafety(mod).?, un.tag.toValue(), .indirect); + } + + const has_tag = layout.tag_size != 0; + const tag_first = layout.tag_align >= layout.payload_align; + + const un_ptr_ty_ref = try self.spv.ptrType(result_ty_ref, .Function); + + const var_id = self.spv.allocId(); + try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{ + .id_result_type = self.typeId(un_ptr_ty_ref), + .id_result = var_id, + .storage_class = .Function, + }); + + const index_ty_ref = try self.intType(.unsigned, 32); + + if (has_tag) { + const tag_index: u32 = if (tag_first) 0 else 1; + const index_id = try self.spv.constInt(index_ty_ref, tag_index); + const tag_ty = ty.unionTagTypeSafety(mod).?; + const tag_ty_ref = try self.resolveType(tag_ty, .indirect); + const tag_ptr_ty_ref = try self.spv.ptrType(tag_ty_ref, .Function); + const ptr_id = try self.accessChain(tag_ptr_ty_ref, var_id, &.{index_id}); + const tag_id = try self.constant(tag_ty, un.tag.toValue(), .indirect); + try self.func.body.emit(self.spv.gpa, .OpStore, .{ + .pointer = ptr_id, + .object = tag_id, + }); + } + + const pl_index: u32 = if (tag_first) 1 else 0; + const index_id = try self.spv.constInt(index_ty_ref, pl_index); + const active_field = ty.unionTagFieldIndex(un.tag.toValue(), mod).?; + const active_field_ty = union_ty.field_types.get(ip)[active_field].toType(); + const active_field_ty_ref = try self.resolveType(active_field_ty, .indirect); + const active_field_ptr_ty_ref = try self.spv.ptrType(active_field_ty_ref, .Function); + const ptr_id = try self.accessChain(active_field_ptr_ty_ref, var_id, &.{index_id}); + const value_id = try self.constant(active_field_ty, un.val.toValue(), .indirect); + try self.func.body.emit(self.spv.gpa, .OpStore, .{ + .pointer = ptr_id, + .object = value_id, + }); + + // Just leave the padding fields uninitialized... + + const result_id = self.spv.allocId(); + try self.func.body.emit(self.spv.gpa, .OpLoad, .{ + .id_result_type = self.typeId(result_ty_ref), + .id_result = result_id, + .pointer = var_id, + }); + return result_id; + }, else => { // The value cannot be generated directly, so generate it as an indirect constant, // and then perform an OpLoad. @@ -1417,7 +1483,7 @@ pub const DeclGen = struct { if (has_tag and tag_first) { const tag_ty_ref = try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect); member_types.appendAssumeCapacity(tag_ty_ref); - member_names.appendAssumeCapacity(try self.spv.resolveString("tag")); + member_names.appendAssumeCapacity(try self.spv.resolveString("(tag)")); } const active_field = maybe_active_field orelse layout.most_aligned_field; @@ -1426,7 +1492,7 @@ pub const DeclGen = struct { const active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime(mod)) blk: { const active_payload_ty_ref = try self.resolveType(active_field_ty, .indirect); member_types.appendAssumeCapacity(active_payload_ty_ref); - member_names.appendAssumeCapacity(try self.spv.resolveString("payload")); + member_names.appendAssumeCapacity(try self.spv.resolveString("(payload)")); break :blk active_field_ty.abiSize(mod); } else 0; @@ -1434,19 +1500,19 @@ pub const DeclGen = struct { if (payload_padding_len != 0) { const payload_padding_ty_ref = try self.spv.arrayType(@as(u32, @intCast(payload_padding_len)), u8_ty_ref); member_types.appendAssumeCapacity(payload_padding_ty_ref); - member_names.appendAssumeCapacity(try self.spv.resolveString("payload_padding")); + member_names.appendAssumeCapacity(try self.spv.resolveString("(payload padding)")); } if (has_tag and !tag_first) { const tag_ty_ref = try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect); member_types.appendAssumeCapacity(tag_ty_ref); - member_names.appendAssumeCapacity(try self.spv.resolveString("tag")); + member_names.appendAssumeCapacity(try self.spv.resolveString("(tag)")); } if (layout.padding != 0) { const padding_ty_ref = try self.spv.arrayType(layout.padding, u8_ty_ref); member_types.appendAssumeCapacity(padding_ty_ref); - member_names.appendAssumeCapacity(try self.spv.resolveString("padding")); + member_names.appendAssumeCapacity(try self.spv.resolveString("(padding)")); } const ty_ref = try self.spv.resolve(.{ .struct_type = .{ -- cgit v1.2.3 From b30cd679878ab0fab7f1e1589c348a2477d542aa Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sat, 16 Sep 2023 13:14:38 +0200 Subject: spirv: put global var initializers in functions --- src/codegen/spirv.zig | 347 +++++++++++++++++++++++++++++-------------- src/codegen/spirv/Module.zig | 5 + 2 files changed, 239 insertions(+), 113 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index dcf717950b..4ab89a1c97 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -425,6 +425,7 @@ pub const DeclGen = struct { // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349 // For now, just initialize the struct by setting the fields manually... // TODO: Make this OpCompositeConstruct when we can + // TODO: Make this Function storage type const ptr_composite_id = try self.alloc(result_ty_ref, null); // Note: using 32-bit ints here because usize crashes the translator as well const index_ty_ref = try self.intType(.unsigned, 32); @@ -450,6 +451,40 @@ pub const DeclGen = struct { return result_id; } + /// Construct a struct at runtime. + /// result_ty_ref must be an array type. + 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. + // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349 + // For now, just initialize the struct by setting the fields manually... + // TODO: Make this OpCompositeConstruct when we can + // TODO: Make this Function storage type + const ptr_composite_id = try self.alloc(result_ty_ref, null); + // Note: using 32-bit ints here because usize crashes the translator as well + const index_ty_ref = try self.intType(.unsigned, 32); + + const spv_composite_ty = self.spv.cache.lookup(result_ty_ref).array_type; + const elem_ty_ref = spv_composite_ty.element_type; + const ptr_elem_ty_ref = try self.spv.ptrType(elem_ty_ref, .Generic); + + for (constituents, 0..) |constitent_id, index| { + const index_id = try self.spv.constInt(index_ty_ref, index); + const ptr_id = try self.accessChain(ptr_elem_ty_ref, ptr_composite_id, &.{index_id}); + try self.func.body.emit(self.spv.gpa, .OpStore, .{ + .pointer = ptr_id, + .object = constitent_id, + }); + } + const result_id = self.spv.allocId(); + try self.func.body.emit(self.spv.gpa, .OpLoad, .{ + .id_result_type = self.typeId(result_ty_ref), + .id_result = result_id, + .pointer = ptr_composite_id, + }); + return result_id; + } + fn constructDeclRef(self: *DeclGen, ty: Type, decl_index: Decl.Index) !IdRef { const mod = self.module; const ty_ref = try self.resolveType(ty, .direct); @@ -459,10 +494,9 @@ pub const DeclGen = struct { switch (mod.intern_pool.indexToKey(decl.val.ip_index)) { .func => { // TODO: Properly lower function pointers. For now we are going to hack around it and - // just generate an empty pointer. Function pointers are represented by usize for now, - // though. + // just generate an empty pointer. Function pointers are represented by a pointer to usize. // TODO: Add dependency - return try self.spv.constInt(ty_ref, 0); + return try self.spv.constNull(ty_ref); }, .extern_func => unreachable, // TODO else => { @@ -1074,7 +1108,7 @@ pub const DeclGen = struct { else => {}, } - log.debug("constant: ty = {}, val = {}", .{ ty.fmt(self.module), val.fmtValue(ty, self.module) }); + log.debug("constant: ty = {}, val = {}", .{ ty.fmt(mod), val.fmtValue(ty, mod) }); if (val.isUndefDeep(mod)) { return self.spv.constUndef(result_ty_ref); } @@ -1270,7 +1304,7 @@ pub const DeclGen = struct { if (array_type.sentinel != .none) { constituents[constituents.len - 1] = try self.constant(elem_ty, array_type.sentinel.toValue(), .indirect); } - return try self.constructStruct(result_ty_ref, constituents); + return try self.constructArray(result_ty_ref, constituents); }, .struct_type => { const struct_ty = mod.typeToStruct(ty).?; @@ -1281,18 +1315,14 @@ pub const DeclGen = struct { var constituents = std.ArrayList(IdRef).init(self.gpa); defer constituents.deinit(); - for (struct_ty.fields.values(), 0..) |field, i| { - if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue; + var field_it = struct_ty.runtimeFieldIterator(mod); + while (field_it.next()) |field_and_index| { + const field = field_and_index.field; + const index = field_and_index.index; + // TODO: Padding? + const field_val = try val.fieldValue(mod, index); + const field_id = try self.constant(field.ty, field_val, .indirect); - const field_val = switch (aggregate.storage) { - .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ - .ty = field.ty.toIntern(), - .storage = .{ .u64 = bytes[i] }, - } }), - .elems => |elems| elems[i], - .repeated_elem => |elem| elem, - }; - const field_id = try self.constant(field.ty, field_val.toValue(), .indirect); try constituents.append(field_id); } @@ -1306,33 +1336,35 @@ pub const DeclGen = struct { // type that has the right field active, then pointer-cast and store // the active field, and finally load and return the entire union. - const layout = ty.unionGetLayout(mod); const union_ty = mod.typeToUnion(ty).?; if (union_ty.getLayout(ip) == .Packed) { return self.todo("packed union types", .{}); - } else if (layout.payload_size == 0) { + } + + const active_field = ty.unionTagFieldIndex(un.tag.toValue(), mod).?; + const layout = self.unionLayout(ty, active_field); + + if (layout.payload_size == 0) { // No payload, so represent this as just the tag type. return try self.constant(ty.unionTagTypeSafety(mod).?, un.tag.toValue(), .indirect); } - const has_tag = layout.tag_size != 0; - const tag_first = layout.tag_align >= layout.payload_align; - - const un_ptr_ty_ref = try self.spv.ptrType(result_ty_ref, .Function); + const un_active_ty_ref = try self.resolveUnionType(ty, active_field); + const un_active_ptr_ty_ref = try self.spv.ptrType(un_active_ty_ref, .Function); + const un_general_ptr_ty_ref = try self.spv.ptrType(result_ty_ref, .Function); const var_id = self.spv.allocId(); try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{ - .id_result_type = self.typeId(un_ptr_ty_ref), + .id_result_type = self.typeId(un_active_ptr_ty_ref), .id_result = var_id, .storage_class = .Function, }); const index_ty_ref = try self.intType(.unsigned, 32); - if (has_tag) { - const tag_index: u32 = if (tag_first) 0 else 1; - const index_id = try self.spv.constInt(index_ty_ref, tag_index); + if (layout.tag_size != 0) { + const index_id = try self.spv.constInt(index_ty_ref, @as(u32, @intCast(layout.tag_index))); const tag_ty = ty.unionTagTypeSafety(mod).?; const tag_ty_ref = try self.resolveType(tag_ty, .indirect); const tag_ptr_ty_ref = try self.spv.ptrType(tag_ty_ref, .Function); @@ -1344,56 +1376,39 @@ pub const DeclGen = struct { }); } - const pl_index: u32 = if (tag_first) 1 else 0; - const index_id = try self.spv.constInt(index_ty_ref, pl_index); - const active_field = ty.unionTagFieldIndex(un.tag.toValue(), mod).?; - const active_field_ty = union_ty.field_types.get(ip)[active_field].toType(); - const active_field_ty_ref = try self.resolveType(active_field_ty, .indirect); - const active_field_ptr_ty_ref = try self.spv.ptrType(active_field_ty_ref, .Function); - const ptr_id = try self.accessChain(active_field_ptr_ty_ref, var_id, &.{index_id}); - const value_id = try self.constant(active_field_ty, un.val.toValue(), .indirect); - try self.func.body.emit(self.spv.gpa, .OpStore, .{ - .pointer = ptr_id, - .object = value_id, - }); + if (layout.active_field_size != 0) { + const index_id = try self.spv.constInt(index_ty_ref, @as(u32, @intCast(layout.active_field_index))); + const active_field_ty_ref = try self.resolveType(layout.active_field_ty, .indirect); + const active_field_ptr_ty_ref = try self.spv.ptrType(active_field_ty_ref, .Function); + const ptr_id = try self.accessChain(active_field_ptr_ty_ref, var_id, &.{index_id}); + const value_id = try self.constant(layout.active_field_ty, un.val.toValue(), .indirect); + try self.func.body.emit(self.spv.gpa, .OpStore, .{ + .pointer = ptr_id, + .object = value_id, + }); + } // Just leave the padding fields uninitialized... + // TODO: Or should we initialize them with undef explicitly? - const result_id = self.spv.allocId(); - try self.func.body.emit(self.spv.gpa, .OpLoad, .{ - .id_result_type = self.typeId(result_ty_ref), - .id_result = result_id, - .pointer = var_id, + // Now cast the pointer and load it as the 'generic' union type. + + const casted_var_id = self.spv.allocId(); + try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ + .id_result_type = self.typeId(un_general_ptr_ty_ref), + .id_result = casted_var_id, + .operand = var_id, }); - return result_id; - }, - else => { - // The value cannot be generated directly, so generate it as an indirect constant, - // and then perform an OpLoad. - const result_id = self.spv.allocId(); - const alignment = ty.abiAlignment(mod); - const spv_decl_index = try self.spv.allocDecl(.global); - - try self.lowerIndirectConstant( - spv_decl_index, - ty, - val, - .UniformConstant, - false, - @intCast(alignment.toByteUnits(0)), - ); - log.debug("indirect constant: index = {}", .{@intFromEnum(spv_decl_index)}); - try self.func.decl_deps.put(self.spv.gpa, spv_decl_index, {}); + const result_id = self.spv.allocId(); try self.func.body.emit(self.spv.gpa, .OpLoad, .{ .id_result_type = self.typeId(result_ty_ref), .id_result = result_id, - .pointer = self.spv.declPtr(spv_decl_index).result_id, + .pointer = casted_var_id, }); - // TODO: Convert bools? This logic should hook into `load`. It should be a dead - // path though considering .Bool is handled above. return result_id; }, + .memoized_call => unreachable, } } @@ -1458,72 +1473,61 @@ pub const DeclGen = struct { fn resolveUnionType(self: *DeclGen, ty: Type, maybe_active_field: ?usize) !CacheRef { const mod = self.module; const ip = &mod.intern_pool; - const layout = ty.unionGetLayout(mod); const union_obj = mod.typeToUnion(ty).?; if (union_obj.getLayout(ip) == .Packed) { return self.todo("packed union types", .{}); } + const layout = self.unionLayout(ty, maybe_active_field); + if (layout.payload_size == 0) { // No payload, so represent this as just the tag type. return try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect); } - const entry = try self.type_map.getOrPut(self.gpa, ty.toIntern()); - if (entry.found_existing) return entry.value_ptr.ty_ref; + // TODO: We need to add the active field to the key. + // const entry = try self.type_map.getOrPut(self.gpa, ty.toIntern()); + // if (entry.found_existing) return entry.value_ptr.ty_ref; - var member_types = std.BoundedArray(CacheRef, 4){}; - var member_names = std.BoundedArray(CacheString, 4){}; + var member_types: [4]CacheRef = undefined; + var member_names: [4]CacheString = undefined; - const has_tag = layout.tag_size != 0; - const tag_first = layout.tag_align.compare(.gte, layout.payload_align); const u8_ty_ref = try self.intType(.unsigned, 8); // TODO: What if Int8Type is not enabled? - if (has_tag and tag_first) { + if (layout.tag_size != 0) { const tag_ty_ref = try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect); - member_types.appendAssumeCapacity(tag_ty_ref); - member_names.appendAssumeCapacity(try self.spv.resolveString("(tag)")); + member_types[layout.tag_index] = tag_ty_ref; + member_names[layout.tag_index] = try self.spv.resolveString("(tag)"); } - const active_field = maybe_active_field orelse layout.most_aligned_field; - const active_field_ty = union_obj.field_types.get(ip)[active_field].toType(); - - const active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime(mod)) blk: { - const active_payload_ty_ref = try self.resolveType(active_field_ty, .indirect); - member_types.appendAssumeCapacity(active_payload_ty_ref); - member_names.appendAssumeCapacity(try self.spv.resolveString("(payload)")); - break :blk active_field_ty.abiSize(mod); - } else 0; - - const payload_padding_len = layout.payload_size - active_field_size; - if (payload_padding_len != 0) { - const payload_padding_ty_ref = try self.spv.arrayType(@as(u32, @intCast(payload_padding_len)), u8_ty_ref); - member_types.appendAssumeCapacity(payload_padding_ty_ref); - member_names.appendAssumeCapacity(try self.spv.resolveString("(payload padding)")); + if (layout.active_field_size != 0) { + const active_payload_ty_ref = try self.resolveType(layout.active_field_ty, .indirect); + member_types[layout.active_field_index] = active_payload_ty_ref; + member_names[layout.active_field_index] = try self.spv.resolveString("(payload)"); } - if (has_tag and !tag_first) { - const tag_ty_ref = try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect); - member_types.appendAssumeCapacity(tag_ty_ref); - member_names.appendAssumeCapacity(try self.spv.resolveString("(tag)")); + if (layout.payload_padding_size != 0) { + const payload_padding_ty_ref = try self.spv.arrayType(@intCast(layout.payload_padding_size), u8_ty_ref); + member_types[layout.payload_padding_index] = payload_padding_ty_ref; + member_names[layout.payload_padding_index] = try self.spv.resolveString("(payload padding)"); } - if (layout.padding != 0) { - const padding_ty_ref = try self.spv.arrayType(layout.padding, u8_ty_ref); - member_types.appendAssumeCapacity(padding_ty_ref); - member_names.appendAssumeCapacity(try self.spv.resolveString("(padding)")); + if (layout.padding_size != 0) { + const padding_ty_ref = try self.spv.arrayType(@intCast(layout.padding_size), u8_ty_ref); + member_types[layout.padding_index] = padding_ty_ref; + member_names[layout.padding_index] = try self.spv.resolveString("(padding)"); } const ty_ref = try self.spv.resolve(.{ .struct_type = .{ .name = try self.resolveTypeName(ty), - .member_types = member_types.slice(), - .member_names = member_names.slice(), + .member_types = member_types[0..layout.total_fields], + .member_names = member_names[0..layout.total_fields], } }); - entry.value_ptr.* = .{ - .ty_ref = ty_ref, - }; + // entry.value_ptr.* = .{ + // .ty_ref = ty_ref, + // }; return ty_ref; } @@ -1532,7 +1536,7 @@ pub const DeclGen = struct { fn resolveType(self: *DeclGen, ty: Type, repr: Repr) Error!CacheRef { const mod = self.module; const ip = &mod.intern_pool; - log.debug("resolveType: ty = {}", .{ty.fmt(self.module)}); + log.debug("resolveType: ty = {}", .{ty.fmt(mod)}); const target = self.getTarget(); switch (ty.zigTypeTag(mod)) { .Void, .NoReturn => return try self.spv.resolve(.void_type), @@ -1854,6 +1858,85 @@ pub const DeclGen = struct { }; } + const UnionLayout = struct { + active_field: usize, + active_field_ty: Type, + payload_size: usize, + + tag_size: usize, + tag_index: usize, + active_field_size: usize, + active_field_index: usize, + payload_padding_size: usize, + payload_padding_index: usize, + padding_size: usize, + padding_index: usize, + total_fields: usize, + }; + + fn unionLayout(self: *DeclGen, ty: Type, maybe_active_field: ?usize) UnionLayout { + const mod = self.module; + const ip = &mod.intern_pool; + const layout = ty.unionGetLayout(self.module); + const union_obj = mod.typeToUnion(ty).?; + + const active_field = maybe_active_field orelse layout.most_aligned_field; + const active_field_ty = union_obj.field_types.get(ip)[active_field].toType(); + + var union_layout = UnionLayout{ + .active_field = active_field, + .active_field_ty = active_field_ty, + .payload_size = layout.payload_size, + .tag_size = layout.tag_size, + .tag_index = undefined, + .active_field_size = undefined, + .active_field_index = undefined, + .payload_padding_size = undefined, + .payload_padding_index = undefined, + .padding_size = layout.padding, + .padding_index = undefined, + .total_fields = undefined, + }; + + union_layout.active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime(mod)) + active_field_ty.abiSize(mod) + else + 0; + union_layout.payload_padding_size = layout.payload_size - union_layout.active_field_size; + + const tag_first = layout.tag_align.compare(.gte, layout.payload_align); + var field_index: usize = 0; + + if (union_layout.tag_size != 0 and tag_first) { + union_layout.tag_index = field_index; + field_index += 1; + } + + if (union_layout.active_field_size != 0) { + union_layout.active_field_index = field_index; + field_index += 1; + } + + if (union_layout.payload_padding_size != 0) { + union_layout.payload_padding_index = field_index; + field_index += 1; + } + + if (union_layout.tag_size != 0 and !tag_first) { + union_layout.tag_index = field_index; + field_index += 1; + } + + if (union_layout.padding_size != 0) { + union_layout.padding_index = field_index; + field_index += 1; + } + + union_layout.total_fields = field_index; + + return union_layout; + } + /// The SPIR-V backend is not yet advanced enough to support the std testing infrastructure. /// In order to be able to run tests, we "temporarily" lower test kernels into separate entry- /// points. The test executor will then be able to invoke these to run the tests. @@ -1995,22 +2078,60 @@ pub const DeclGen = struct { return self.todo("importing extern variables", .{}); } - // TODO: integrate with variable(). + // Currently, initializers for CrossWorkgroup variables is not implemented + // in Mesa. Therefore we generate an initialization kernel instead. + + const void_ty_ref = try self.resolveType(Type.void, .direct); + + const initializer_proto_ty_ref = try self.spv.resolve(.{ .function_type = .{ + .return_type = void_ty_ref, + .parameters = &.{}, + } }); + // Generate the actual variable for the global... const final_storage_class = spvStorageClass(decl.@"addrspace"); const actual_storage_class = switch (final_storage_class) { .Generic => .CrossWorkgroup, else => final_storage_class, }; - try self.lowerIndirectConstant( - spv_decl_index, - decl.ty, - init_val, - actual_storage_class, - final_storage_class == .Generic, - @intCast(decl.alignment.toByteUnits(0)), - ); + const ty_ref = try self.resolveType(decl.ty, .indirect); + const ptr_ty_ref = try self.spv.ptrType(ty_ref, actual_storage_class); + + const begin = self.spv.beginGlobal(); + try self.spv.globals.section.emit(self.spv.gpa, .OpVariable, .{ + .id_result_type = self.typeId(ptr_ty_ref), + .id_result = decl_id, + .storage_class = actual_storage_class, + }); + // TODO: We should be able to get rid of this by now... + self.spv.endGlobal(spv_decl_index, begin); + + // Now emit the instructions that initialize the variable. + const initializer_id = self.spv.allocId(); + try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{ + .id_result_type = self.typeId(void_ty_ref), + .id_result = initializer_id, + .function_control = .{}, + .function_type = self.typeId(initializer_proto_ty_ref), + }); + const root_block_id = self.spv.allocId(); + try self.func.prologue.emit(self.spv.gpa, .OpLabel, .{ + .id_result = root_block_id, + }); + self.current_block_label_id = root_block_id; + + const val_id = try self.constant(decl.ty, init_val, .indirect); + try self.func.body.emit(self.spv.gpa, .OpStore, .{ + .pointer = decl_id, + .object = val_id, + }); + + try self.func.body.emit(self.spv.gpa, .OpReturn, {}); + try self.func.body.emit(self.spv.gpa, .OpFunctionEnd, {}); + try self.spv.addFunction(spv_decl_index, self.func); + + try self.spv.initializers.append(self.spv.gpa, initializer_id); } } diff --git a/src/codegen/spirv/Module.zig b/src/codegen/spirv/Module.zig index e61ac754ee..cafc2f0662 100644 --- a/src/codegen/spirv/Module.zig +++ b/src/codegen/spirv/Module.zig @@ -174,6 +174,9 @@ globals: struct { section: Section = .{}, } = .{}, +/// The function IDs of global variable initializers +initializers: std.ArrayListUnmanaged(IdRef) = .{}, + pub fn init(gpa: Allocator, arena: Allocator) Module { return .{ .gpa = gpa, @@ -202,6 +205,8 @@ pub fn deinit(self: *Module) void { self.globals.globals.deinit(self.gpa); self.globals.section.deinit(self.gpa); + self.initializers.deinit(self.gpa); + self.* = undefined; } -- cgit v1.2.3 From 66036e600058081ce2f9248fd221900dce793cdd Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sat, 16 Sep 2023 13:16:02 +0200 Subject: spirv: remove indirect constant lowering It is stupid and I hate it. --- src/codegen/spirv.zig | 575 +------------------------------------------------- 1 file changed, 3 insertions(+), 572 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 4ab89a1c97..c906e5ad96 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -520,576 +520,6 @@ pub const DeclGen = struct { } } - const IndirectConstantLowering = struct { - const undef = 0xAA; - - dg: *DeclGen, - /// Cached reference of the u32 type. - u32_ty_ref: CacheRef, - /// The members of the resulting structure type - members: std.ArrayList(CacheRef), - /// The initializers of each of the members. - initializers: std.ArrayList(IdRef), - /// The current size of the structure. Includes - /// the bytes in partial_word. - size: u32 = 0, - /// The partially filled last constant. - /// If full, its flushed. - partial_word: std.BoundedArray(u8, @sizeOf(Word)) = .{}, - /// The declaration dependencies of the constant we are lowering. - decl_deps: std.AutoArrayHashMap(SpvModule.Decl.Index, void), - - /// Utility function to get the section that instructions should be lowered to. - fn section(self: *@This()) *SpvSection { - return &self.dg.spv.globals.section; - } - - /// Flush the partial_word to the members. If the partial_word is not - /// filled, this adds padding bytes (which are undefined). - fn flush(self: *@This()) !void { - if (self.partial_word.len == 0) { - // No need to add it there. - return; - } - - for (self.partial_word.unusedCapacitySlice()) |*unused| { - // TODO: Perhaps we should generate OpUndef for these bytes? - unused.* = undef; - } - - const word = @as(Word, @bitCast(self.partial_word.buffer)); - const result_id = try self.dg.spv.constInt(self.u32_ty_ref, word); - try self.members.append(self.u32_ty_ref); - try self.initializers.append(result_id); - - self.partial_word.len = 0; - self.size = std.mem.alignForward(u32, self.size, @sizeOf(Word)); - } - - /// Fill the buffer with undefined values until the size is aligned to `align`. - fn fillToAlign(self: *@This(), alignment: u32) !void { - const target_size = std.mem.alignForward(u32, self.size, alignment); - try self.addUndef(target_size - self.size); - } - - fn addUndef(self: *@This(), amt: u64) !void { - for (0..@as(usize, @intCast(amt))) |_| { - try self.addByte(undef); - } - } - - /// Add a single byte of data to the constant. - fn addByte(self: *@This(), data: u8) !void { - self.partial_word.append(data) catch { - try self.flush(); - self.partial_word.append(data) catch unreachable; - }; - self.size += 1; - } - - /// Add many bytes of data to the constnat. - fn addBytes(self: *@This(), data: []const u8) !void { - // TODO: Improve performance by adding in bulk, or something? - for (data) |byte| { - try self.addByte(byte); - } - } - - fn addPtr(self: *@This(), ptr_ty_ref: CacheRef, ptr_id: IdRef) !void { - // TODO: Double check pointer sizes here. - // shared pointers might be u32... - const target = self.dg.getTarget(); - const width = @divExact(target.ptrBitWidth(), 8); - if (self.size % width != 0) { - return self.dg.todo("misaligned pointer constants", .{}); - } - try self.members.append(ptr_ty_ref); - try self.initializers.append(ptr_id); - self.size += width; - } - - fn addNullPtr(self: *@This(), ptr_ty_ref: CacheRef) !void { - const result_id = try self.dg.spv.constNull(ptr_ty_ref); - try self.addPtr(ptr_ty_ref, result_id); - } - - fn addConstInt(self: *@This(), comptime T: type, value: T) !void { - if (@bitSizeOf(T) % 8 != 0) { - @compileError("todo: non byte aligned int constants"); - } - - // TODO: Swap endianness if the compiler is big endian. - try self.addBytes(std.mem.asBytes(&value)); - } - - fn addConstBool(self: *@This(), value: bool) !void { - try self.addByte(@intFromBool(value)); // TODO: Keep in sync with something? - } - - fn addInt(self: *@This(), ty: Type, val: Value) !void { - const mod = self.dg.module; - const len = ty.abiSize(mod); - if (val.isUndef(mod)) { - try self.addUndef(len); - return; - } - - const int_info = ty.intInfo(mod); - const int_bits = switch (int_info.signedness) { - .signed => @as(u64, @bitCast(val.toSignedInt(mod))), - .unsigned => val.toUnsignedInt(mod), - }; - - // TODO: Swap endianess if the compiler is big endian. - try self.addBytes(std.mem.asBytes(&int_bits)[0..@as(usize, @intCast(len))]); - } - - fn addFloat(self: *@This(), ty: Type, val: Value) !void { - const mod = self.dg.module; - const target = self.dg.getTarget(); - const len = ty.abiSize(mod); - - // TODO: Swap endianess if the compiler is big endian. - switch (ty.floatBits(target)) { - 16 => { - const float_bits = val.toFloat(f16, mod); - try self.addBytes(std.mem.asBytes(&float_bits)[0..@as(usize, @intCast(len))]); - }, - 32 => { - const float_bits = val.toFloat(f32, mod); - try self.addBytes(std.mem.asBytes(&float_bits)[0..@as(usize, @intCast(len))]); - }, - 64 => { - const float_bits = val.toFloat(f64, mod); - try self.addBytes(std.mem.asBytes(&float_bits)[0..@as(usize, @intCast(len))]); - }, - else => unreachable, - } - } - - fn addDeclRef(self: *@This(), ty: Type, decl_index: Decl.Index) !void { - const dg = self.dg; - const mod = dg.module; - - const ty_ref = try self.dg.resolveType(ty, .indirect); - const ty_id = dg.typeId(ty_ref); - - const decl = dg.module.declPtr(decl_index); - const spv_decl_index = try dg.resolveDecl(decl_index); - - switch (mod.intern_pool.indexToKey(decl.val.ip_index)) { - .func => { - // TODO: Properly lower function pointers. For now we are going to hack around it and - // just generate an empty pointer. Function pointers are represented by usize for now, - // though. - try self.addInt(Type.usize, Value.zero_usize); - // TODO: Add dependency - return; - }, - .extern_func => unreachable, // TODO - else => { - const result_id = dg.spv.allocId(); - - try self.decl_deps.put(spv_decl_index, {}); - - const decl_id = dg.spv.declPtr(spv_decl_index).result_id; - // TODO: Do we need a storage class cast here? - // TODO: We can probably eliminate these casts - try dg.spv.globals.section.emitSpecConstantOp(dg.spv.gpa, .OpBitcast, .{ - .id_result_type = ty_id, - .id_result = result_id, - .operand = decl_id, - }); - - try self.addPtr(ty_ref, result_id); - }, - } - } - - fn lower(self: *@This(), ty: Type, arg_val: Value) !void { - const dg = self.dg; - const mod = dg.module; - const ip = &mod.intern_pool; - - var val = arg_val; - switch (ip.indexToKey(val.toIntern())) { - .runtime_value => |rt| val = rt.val.toValue(), - else => {}, - } - - if (val.isUndefDeep(mod)) { - const size = ty.abiSize(mod); - return try self.addUndef(size); - } - - switch (ip.indexToKey(val.toIntern())) { - .int_type, - .ptr_type, - .array_type, - .vector_type, - .opt_type, - .anyframe_type, - .error_union_type, - .simple_type, - .struct_type, - .anon_struct_type, - .union_type, - .opaque_type, - .enum_type, - .func_type, - .error_set_type, - .inferred_error_set_type, - => unreachable, // types, not values - - .undef, .runtime_value => unreachable, // handled above - .simple_value => |simple_value| switch (simple_value) { - .undefined, - .void, - .null, - .empty_struct, - .@"unreachable", - .generic_poison, - => unreachable, // non-runtime values - .false, .true => try self.addConstBool(val.toBool()), - }, - .variable, - .extern_func, - .func, - .enum_literal, - .empty_enum_value, - => unreachable, // non-runtime values - .int => try self.addInt(ty, val), - .err => |err| { - const int = try mod.getErrorValue(err.name); - try self.addConstInt(u16, @as(u16, @intCast(int))); - }, - .error_union => |error_union| { - const err_ty = switch (error_union.val) { - .err_name => ty.errorUnionSet(mod), - .payload => Type.err_int, - }; - const err_val = switch (error_union.val) { - .err_name => |err_name| (try mod.intern(.{ .err = .{ - .ty = ty.errorUnionSet(mod).toIntern(), - .name = err_name, - } })).toValue(), - .payload => try mod.intValue(Type.err_int, 0), - }; - const payload_ty = ty.errorUnionPayload(mod); - const eu_layout = dg.errorUnionLayout(payload_ty); - if (!eu_layout.payload_has_bits) { - // We use the error type directly as the type. - try self.lower(err_ty, err_val); - return; - } - - const payload_size = payload_ty.abiSize(mod); - const error_size = err_ty.abiSize(mod); - const ty_size = ty.abiSize(mod); - const padding = ty_size - payload_size - error_size; - - const payload_val = switch (error_union.val) { - .err_name => try mod.intern(.{ .undef = payload_ty.toIntern() }), - .payload => |payload| payload, - }.toValue(); - - if (eu_layout.error_first) { - try self.lower(err_ty, err_val); - try self.lower(payload_ty, payload_val); - } else { - try self.lower(payload_ty, payload_val); - try self.lower(err_ty, err_val); - } - - try self.addUndef(padding); - }, - .enum_tag => { - const int_val = try val.intFromEnum(ty, mod); - - const int_ty = ty.intTagType(mod); - - try self.lower(int_ty, int_val); - }, - .float => try self.addFloat(ty, val), - .ptr => |ptr| { - const ptr_ty = switch (ptr.len) { - .none => ty, - else => ty.slicePtrFieldType(mod), - }; - switch (ptr.addr) { - .decl => |decl| try self.addDeclRef(ptr_ty, decl), - .mut_decl => |mut_decl| try self.addDeclRef(ptr_ty, mut_decl.decl), - .int => |int| try self.addInt(Type.usize, int.toValue()), - else => |tag| return dg.todo("pointer value of type {s}", .{@tagName(tag)}), - } - if (ptr.len != .none) { - try self.addInt(Type.usize, ptr.len.toValue()); - } - }, - .opt => { - const payload_ty = ty.optionalChild(mod); - const payload_val = val.optionalValue(mod); - const abi_size = ty.abiSize(mod); - - if (!payload_ty.hasRuntimeBits(mod)) { - try self.addConstBool(payload_val != null); - return; - } else if (ty.optionalReprIsPayload(mod)) { - // Optional representation is a nullable pointer or slice. - if (payload_val) |pl_val| { - try self.lower(payload_ty, pl_val); - } else { - const ptr_ty_ref = try dg.resolveType(ty, .indirect); - try self.addNullPtr(ptr_ty_ref); - } - return; - } - - // Optional representation is a structure. - // { Payload, Bool } - - // Subtract 1 for @sizeOf(bool). - // TODO: Make this not hardcoded. - const payload_size = payload_ty.abiSize(mod); - const padding = abi_size - payload_size - 1; - - if (payload_val) |pl_val| { - try self.lower(payload_ty, pl_val); - } else { - try self.addUndef(payload_size); - } - try self.addConstBool(payload_val != null); - try self.addUndef(padding); - }, - .aggregate => |aggregate| switch (ip.indexToKey(ty.ip_index)) { - .array_type => |array_type| { - const elem_ty = array_type.child.toType(); - switch (aggregate.storage) { - .bytes => |bytes| try self.addBytes(bytes), - .elems, .repeated_elem => { - for (0..@as(usize, @intCast(array_type.len))) |i| { - try self.lower(elem_ty, switch (aggregate.storage) { - .bytes => unreachable, - .elems => |elem_vals| elem_vals[@as(usize, @intCast(i))].toValue(), - .repeated_elem => |elem_val| elem_val.toValue(), - }); - } - }, - } - if (array_type.sentinel != .none) { - try self.lower(elem_ty, array_type.sentinel.toValue()); - } - }, - .vector_type => return dg.todo("indirect constant of type {}", .{ty.fmt(mod)}), - .struct_type => { - const struct_type = mod.typeToStruct(ty).?; - if (struct_type.layout == .Packed) { - return dg.todo("packed struct constants", .{}); - } - - // TODO iterate with runtime order instead so that struct field - // reordering can be enabled for this backend. - const struct_begin = self.size; - for (struct_type.field_types.get(ip), 0..) |field_ty, i_usize| { - const i: u32 = @intCast(i_usize); - if (struct_type.fieldIsComptime(ip, i)) continue; - if (!field_ty.toType().hasRuntimeBits(mod)) continue; - - const field_val = switch (aggregate.storage) { - .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ - .ty = field_ty, - .storage = .{ .u64 = bytes[i] }, - } }), - .elems => |elems| elems[i], - .repeated_elem => |elem| elem, - }; - try self.lower(field_ty.toType(), field_val.toValue()); - - // Add padding if required. - // TODO: Add to type generation as well? - const unpadded_field_end = self.size - struct_begin; - const padded_field_end = ty.structFieldOffset(i + 1, mod); - const padding = padded_field_end - unpadded_field_end; - try self.addUndef(padding); - } - }, - .anon_struct_type => unreachable, // TODO - else => unreachable, - }, - .un => |un| { - const layout = ty.unionGetLayout(mod); - - if (layout.payload_size == 0) { - return try self.lower(ty.unionTagTypeSafety(mod).?, un.tag.toValue()); - } - - const union_obj = mod.typeToUnion(ty).?; - if (union_obj.getLayout(ip) == .Packed) { - return dg.todo("packed union constants", .{}); - } - - const active_field = ty.unionTagFieldIndex(un.tag.toValue(), dg.module).?; - const active_field_ty = union_obj.field_types.get(ip)[active_field].toType(); - - const has_tag = layout.tag_size != 0; - const tag_first = layout.tag_align.compare(.gte, layout.payload_align); - - if (has_tag and tag_first) { - try self.lower(ty.unionTagTypeSafety(mod).?, un.tag.toValue()); - } - - const active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime(mod)) blk: { - try self.lower(active_field_ty, un.val.toValue()); - break :blk active_field_ty.abiSize(mod); - } else 0; - - const payload_padding_len = layout.payload_size - active_field_size; - try self.addUndef(payload_padding_len); - - if (has_tag and !tag_first) { - try self.lower(ty.unionTagTypeSafety(mod).?, un.tag.toValue()); - } - - try self.addUndef(layout.padding); - }, - .memoized_call => unreachable, - } - } - }; - - /// Returns a pointer to `val`. The value is placed directly - /// into the storage class `storage_class`, and this is also where the resulting - /// pointer points to. Note: result is not necessarily an OpVariable instruction! - fn lowerIndirectConstant( - self: *DeclGen, - spv_decl_index: SpvModule.Decl.Index, - ty: Type, - val: Value, - storage_class: StorageClass, - cast_to_generic: bool, - alignment: u32, - ) Error!void { - // To simplify constant generation, we're going to generate constants as a word-array, and - // pointer cast the result to the right type. - // This means that the final constant will be generated as follows: - // %T = OpTypeStruct %members... - // %P = OpTypePointer %T - // %U = OpTypePointer %ty - // %1 = OpConstantComposite %T %initializers... - // %2 = OpVariable %P %1 - // %result_id = OpSpecConstantOp OpBitcast %U %2 - // - // The members consist of two options: - // - Literal values: ints, strings, etc. These are generated as u32 words. - // - Relocations, such as pointers: These are generated by embedding the pointer into the - // to-be-generated structure. There are two options here, depending on the alignment of the - // pointer value itself (not the alignment of the pointee). - // - Natively or over-aligned values. These can just be generated directly. - // - Underaligned pointers. These need to be packed into the word array by using a mixture of - // OpSpecConstantOp instructions such as OpConvertPtrToU, OpBitcast, OpShift, etc. - - // TODO: Implement alignment here. - // This is hoing to require some hacks because there is no real way to - // set an OpVariable's alignment. - _ = alignment; - - assert(storage_class != .Generic and storage_class != .Function); - - const var_id = self.spv.allocId(); - log.debug("lowerIndirectConstant: id = {}, index = {}, ty = {}, val = {}", .{ var_id.id, @intFromEnum(spv_decl_index), ty.fmt(self.module), val.fmtDebug() }); - - const section = &self.spv.globals.section; - - const ty_ref = try self.resolveType(ty, .indirect); - const ptr_ty_ref = try self.spv.ptrType(ty_ref, storage_class); - - // const target = self.getTarget(); - - // TODO: Fix the resulting global linking for these paths. - // if (val.isUndef(mod)) { - // // Special case: the entire value is undefined. In this case, we can just - // // generate an OpVariable with no initializer. - // return try section.emit(self.spv.gpa, .OpVariable, .{ - // .id_result_type = self.typeId(ptr_ty_ref), - // .id_result = result_id, - // .storage_class = storage_class, - // }); - // } else if (ty.abiSize(mod) == 0) { - // // Special case: if the type has no size, then return an undefined pointer. - // return try section.emit(self.spv.gpa, .OpUndef, .{ - // .id_result_type = self.typeId(ptr_ty_ref), - // .id_result = result_id, - // }); - // } - - // TODO: Capture the above stuff in here as well... - const begin_inst = self.spv.beginGlobal(); - - const u32_ty_ref = try self.intType(.unsigned, 32); - var icl = IndirectConstantLowering{ - .dg = self, - .u32_ty_ref = u32_ty_ref, - .members = std.ArrayList(CacheRef).init(self.gpa), - .initializers = std.ArrayList(IdRef).init(self.gpa), - .decl_deps = std.AutoArrayHashMap(SpvModule.Decl.Index, void).init(self.gpa), - }; - - defer icl.members.deinit(); - defer icl.initializers.deinit(); - defer icl.decl_deps.deinit(); - - try icl.lower(ty, val); - try icl.flush(); - - const constant_struct_ty_ref = try self.spv.resolve(.{ .struct_type = .{ - .member_types = icl.members.items, - } }); - const ptr_constant_struct_ty_ref = try self.spv.ptrType(constant_struct_ty_ref, storage_class); - - const constant_struct_id = self.spv.allocId(); - try section.emit(self.spv.gpa, .OpSpecConstantComposite, .{ - .id_result_type = self.typeId(constant_struct_ty_ref), - .id_result = constant_struct_id, - .constituents = icl.initializers.items, - }); - - self.spv.globalPtr(spv_decl_index).?.result_id = var_id; - try section.emit(self.spv.gpa, .OpVariable, .{ - .id_result_type = self.typeId(ptr_constant_struct_ty_ref), - .id_result = var_id, - .storage_class = storage_class, - .initializer = constant_struct_id, - }); - // TODO: Set alignment of OpVariable. - // TODO: We may be able to eliminate these casts. - - const const_ptr_id = try self.makePointerConstant(section, ptr_constant_struct_ty_ref, var_id); - const result_id = self.spv.declPtr(spv_decl_index).result_id; - - const bitcast_result_id = if (cast_to_generic) - self.spv.allocId() - else - result_id; - - try section.emitSpecConstantOp(self.spv.gpa, .OpBitcast, .{ - .id_result_type = self.typeId(ptr_ty_ref), - .id_result = bitcast_result_id, - .operand = const_ptr_id, - }); - - if (cast_to_generic) { - const generic_ptr_ty_ref = try self.spv.ptrType(ty_ref, .Generic); - try section.emitSpecConstantOp(self.spv.gpa, .OpPtrCastToGeneric, .{ - .id_result_type = self.typeId(generic_ptr_ty_ref), - .id_result = result_id, - .pointer = bitcast_result_id, - }); - } - - try self.spv.declareDeclDeps(spv_decl_index, icl.decl_deps.keys()); - self.spv.endGlobal(spv_decl_index, begin_inst); - } - /// This function generates a load for a constant in direct (ie, non-memory) representation. /// When the constant is simple, it can be generated directly using OpConstant instructions. /// When the constant is more complicated however, it needs to be constructed using multiple values. This @@ -2104,8 +1534,6 @@ pub const DeclGen = struct { .id_result = decl_id, .storage_class = actual_storage_class, }); - // TODO: We should be able to get rid of this by now... - self.spv.endGlobal(spv_decl_index, begin); // Now emit the instructions that initialize the variable. const initializer_id = self.spv.allocId(); @@ -2127,6 +1555,9 @@ pub const DeclGen = struct { .object = val_id, }); + // TODO: We should be able to get rid of this by now... + self.spv.endGlobal(spv_decl_index, begin); + try self.func.body.emit(self.spv.gpa, .OpReturn, {}); try self.func.body.emit(self.spv.gpa, .OpFunctionEnd, {}); try self.spv.addFunction(spv_decl_index, self.func); -- cgit v1.2.3 From 18d0909adaac1ba67a06d92632423a435e4458f4 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 17 Sep 2023 01:51:47 +0200 Subject: spirv: fixes --- src/codegen/spirv.zig | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index c906e5ad96..372a11c912 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -708,7 +708,7 @@ pub const DeclGen = struct { const elem_ty = array_type.child.toType(); const elem_ty_ref = try self.resolveType(elem_ty, .indirect); - const constituents = try self.gpa.alloc(IdRef, ty.arrayLenIncludingSentinel(mod)); + const constituents = try self.gpa.alloc(IdRef, @as(u32, @intCast(ty.arrayLenIncludingSentinel(mod)))); defer self.gpa.free(constituents); switch (aggregate.storage) { @@ -1289,19 +1289,19 @@ pub const DeclGen = struct { } const UnionLayout = struct { - active_field: usize, + active_field: u32, active_field_ty: Type, - payload_size: usize, - - tag_size: usize, - tag_index: usize, - active_field_size: usize, - active_field_index: usize, - payload_padding_size: usize, - payload_padding_index: usize, - padding_size: usize, - padding_index: usize, - total_fields: usize, + payload_size: u32, + + tag_size: u32, + tag_index: u32, + active_field_size: u32, + active_field_index: u32, + payload_padding_size: u32, + payload_padding_index: u32, + padding_size: u32, + padding_index: u32, + total_fields: u32, }; fn unionLayout(self: *DeclGen, ty: Type, maybe_active_field: ?usize) UnionLayout { @@ -1314,28 +1314,28 @@ pub const DeclGen = struct { const active_field_ty = union_obj.field_types.get(ip)[active_field].toType(); var union_layout = UnionLayout{ - .active_field = active_field, + .active_field = @intCast(active_field), .active_field_ty = active_field_ty, - .payload_size = layout.payload_size, - .tag_size = layout.tag_size, + .payload_size = @intCast(layout.payload_size), + .tag_size = @intCast(layout.tag_size), .tag_index = undefined, .active_field_size = undefined, .active_field_index = undefined, .payload_padding_size = undefined, .payload_padding_index = undefined, - .padding_size = layout.padding, + .padding_size = @intCast(layout.padding), .padding_index = undefined, .total_fields = undefined, }; union_layout.active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime(mod)) - active_field_ty.abiSize(mod) + @intCast(active_field_ty.abiSize(mod)) else 0; - union_layout.payload_padding_size = layout.payload_size - union_layout.active_field_size; + union_layout.payload_padding_size = @intCast(layout.payload_size - union_layout.active_field_size); const tag_first = layout.tag_align.compare(.gte, layout.payload_align); - var field_index: usize = 0; + var field_index: u32 = 0; if (union_layout.tag_size != 0 and tag_first) { union_layout.tag_index = field_index; @@ -1534,6 +1534,7 @@ pub const DeclGen = struct { .id_result = decl_id, .storage_class = actual_storage_class, }); + self.spv.globalPtr(spv_decl_index).?.result_id = decl_id; // Now emit the instructions that initialize the variable. const initializer_id = self.spv.allocId(); -- cgit v1.2.3 From 06d9e3b2eb7a5c44edfce672b61feb2efc7234a6 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 17 Sep 2023 02:54:53 +0200 Subject: spirv: always emit unsigned integers This is required for SPIR-V in Kernel mode. The Intel implementation just didn't care about this fact. --- src/codegen/spirv.zig | 60 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 21 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 372a11c912..a119d93901 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -408,7 +408,7 @@ pub const DeclGen = struct { switch (repr) { .indirect => { const int_ty_ref = try self.intType(.unsigned, 1); - return self.spv.constInt(int_ty_ref, @intFromBool(value)); + return self.constInt(int_ty_ref, @intFromBool(value)); }, .direct => { const bool_ty_ref = try self.resolveType(Type.bool, .direct); @@ -417,6 +417,25 @@ pub const DeclGen = struct { } } + /// Emits an integer constant. + /// This function, unlike SpvModule.constInt, takes care to bitcast + /// the value to an unsigned int first for Kernels. + fn constInt(self: *DeclGen, ty_ref: CacheRef, value: anytype) !IdRef { + if (value < 0) { + const ty = self.spv.cache.lookup(ty_ref).int_type; + // Manually truncate the value so that the resulting value + // fits within the unsigned type. + const bits: u64 = @bitCast(@as(i64, @intCast(value))); + const truncated_bits = if (ty.bits == 64) + bits + else + bits & (@as(u64, 1) << @intCast(ty.bits)) - 1; + return try self.spv.constInt(ty_ref, truncated_bits); + } else { + return try self.spv.constInt(ty_ref, value); + } + } + /// Construct a struct at runtime. /// result_ty_ref must be a struct type. fn constructStruct(self: *DeclGen, result_ty_ref: CacheRef, constituents: []const IdRef) !IdRef { @@ -434,7 +453,7 @@ pub const DeclGen = struct { const member_types = spv_composite_ty.member_types; for (constituents, member_types, 0..) |constitent_id, member_ty_ref, index| { - const index_id = try self.spv.constInt(index_ty_ref, index); + const index_id = try self.constInt(index_ty_ref, index); const ptr_member_ty_ref = try self.spv.ptrType(member_ty_ref, .Generic); const ptr_id = try self.accessChain(ptr_member_ty_ref, ptr_composite_id, &.{index_id}); try self.func.body.emit(self.spv.gpa, .OpStore, .{ @@ -469,7 +488,7 @@ pub const DeclGen = struct { const ptr_elem_ty_ref = try self.spv.ptrType(elem_ty_ref, .Generic); for (constituents, 0..) |constitent_id, index| { - const index_id = try self.spv.constInt(index_ty_ref, index); + const index_id = try self.constInt(index_ty_ref, index); const ptr_id = try self.accessChain(ptr_elem_ty_ref, ptr_composite_id, &.{index_id}); try self.func.body.emit(self.spv.gpa, .OpStore, .{ .pointer = ptr_id, @@ -580,17 +599,14 @@ pub const DeclGen = struct { .generic_poison, => unreachable, // non-runtime values - .false, .true => switch (repr) { - .direct => return try self.spv.constBool(result_ty_ref, val.toBool()), - .indirect => return try self.spv.constInt(result_ty_ref, @intFromBool(val.toBool())), - }, + .false, .true => return try self.constBool(val.toBool(), repr), }, .int => { if (ty.isSignedInt(mod)) { - return try self.spv.constInt(result_ty_ref, val.toSignedInt(mod)); + return try self.constInt(result_ty_ref, val.toSignedInt(mod)); } else { - return try self.spv.constInt(result_ty_ref, val.toUnsignedInt(mod)); + return try self.constInt(result_ty_ref, val.toUnsignedInt(mod)); } }, .float => return switch (ty.floatBits(target)) { @@ -602,7 +618,7 @@ pub const DeclGen = struct { }, .err => |err| { const value = try mod.getErrorValue(err.name); - return try self.spv.constInt(result_ty_ref, value); + return try self.constInt(result_ty_ref, value); }, .error_union => |error_union| { // TODO: Error unions may be constructed with constant instructions if the payload type @@ -716,7 +732,7 @@ pub const DeclGen = struct { // TODO: This is really space inefficient, perhaps there is a better // way to do it? for (bytes, 0..) |byte, i| { - constituents[i] = try self.spv.constInt(elem_ty_ref, byte); + constituents[i] = try self.constInt(elem_ty_ref, byte); } }, .elems => |elems| { @@ -794,7 +810,7 @@ pub const DeclGen = struct { const index_ty_ref = try self.intType(.unsigned, 32); if (layout.tag_size != 0) { - const index_id = try self.spv.constInt(index_ty_ref, @as(u32, @intCast(layout.tag_index))); + const index_id = try self.constInt(index_ty_ref, @as(u32, @intCast(layout.tag_index))); const tag_ty = ty.unionTagTypeSafety(mod).?; const tag_ty_ref = try self.resolveType(tag_ty, .indirect); const tag_ptr_ty_ref = try self.spv.ptrType(tag_ty_ref, .Function); @@ -807,7 +823,7 @@ pub const DeclGen = struct { } if (layout.active_field_size != 0) { - const index_id = try self.spv.constInt(index_ty_ref, @as(u32, @intCast(layout.active_field_index))); + const index_id = try self.constInt(index_ty_ref, @as(u32, @intCast(layout.active_field_index))); const active_field_ty_ref = try self.resolveType(layout.active_field_ty, .indirect); const active_field_ptr_ty_ref = try self.spv.ptrType(active_field_ty_ref, .Function); const ptr_id = try self.accessChain(active_field_ptr_ty_ref, var_id, &.{index_id}); @@ -870,7 +886,9 @@ pub const DeclGen = struct { // An array of largestSupportedIntBits. return self.todo("Implement {s} composite int type of {} bits", .{ @tagName(signedness), bits }); }; - return self.spv.intType(signedness, backing_bits); + // Kernel only supports unsigned ints. + // TODO: Only do this with Kernels + return self.spv.intType(.unsigned, backing_bits); } /// Create an integer type that represents 'usize'. @@ -1568,8 +1586,8 @@ pub const DeclGen = struct { } fn intFromBool(self: *DeclGen, result_ty_ref: CacheRef, condition_id: IdRef) !IdRef { - const zero_id = try self.spv.constInt(result_ty_ref, 0); - const one_id = try self.spv.constInt(result_ty_ref, 1); + const zero_id = try self.constInt(result_ty_ref, 0); + const one_id = try self.constInt(result_ty_ref, 1); const result_id = self.spv.allocId(); try self.func.body.emit(self.spv.gpa, .OpSelect, .{ .id_result_type = self.typeId(result_ty_ref), @@ -1589,7 +1607,7 @@ pub const DeclGen = struct { .Bool => blk: { const direct_bool_ty_ref = try self.resolveType(ty, .direct); const indirect_bool_ty_ref = try self.resolveType(ty, .indirect); - const zero_id = try self.spv.constInt(indirect_bool_ty_ref, 0); + const zero_id = try self.constInt(indirect_bool_ty_ref, 0); const result_id = self.spv.allocId(); try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{ .id_result_type = self.typeId(direct_bool_ty_ref), @@ -1832,7 +1850,7 @@ pub const DeclGen = struct { fn maskStrangeInt(self: *DeclGen, ty_ref: CacheRef, value_id: IdRef, bits: u16) !IdRef { const mask_value = if (bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(bits))) - 1; const result_id = self.spv.allocId(); - const mask_id = try self.spv.constInt(ty_ref, mask_value); + const mask_id = try self.constInt(ty_ref, mask_value); try self.func.body.emit(self.spv.gpa, .OpBitwiseAnd, .{ .id_result_type = self.typeId(ty_ref), .id_result = result_id, @@ -1971,7 +1989,7 @@ pub const DeclGen = struct { // Note that signed overflow is also wrapping in spir-v. const rhs_lt_zero_id = self.spv.allocId(); - const zero_id = try self.spv.constInt(operand_ty_ref, 0); + const zero_id = try self.constInt(operand_ty_ref, 0); try self.func.body.emit(self.spv.gpa, .OpSLessThan, .{ .id_result_type = self.typeId(bool_ty_ref), .id_result = rhs_lt_zero_id, @@ -2540,7 +2558,7 @@ pub const DeclGen = struct { .Packed => unreachable, // TODO else => { const field_index_ty_ref = try self.intType(.unsigned, 32); - const field_index_id = try self.spv.constInt(field_index_ty_ref, field_index); + const field_index_id = try self.constInt(field_index_ty_ref, field_index); const result_ty_ref = try self.resolveType(result_ptr_ty, .direct); return try self.accessChain(result_ty_ref, object_ptr, &.{field_index_id}); }, @@ -2822,7 +2840,7 @@ pub const DeclGen = struct { else err_union_id; - const zero_id = try self.spv.constInt(err_ty_ref, 0); + const zero_id = try self.constInt(err_ty_ref, 0); const is_err_id = self.spv.allocId(); try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{ .id_result_type = self.typeId(bool_ty_ref), -- cgit v1.2.3 From 42226fc1b77ba042e72fcdfb1f3c1973650a7cc3 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 17 Sep 2023 03:39:22 +0200 Subject: spirv: make construct(Struct|Array) use the Function storage class --- src/codegen/spirv.zig | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index a119d93901..768ebea623 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -444,8 +444,14 @@ pub const DeclGen = struct { // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349 // For now, just initialize the struct by setting the fields manually... // TODO: Make this OpCompositeConstruct when we can - // TODO: Make this Function storage type - const ptr_composite_id = try self.alloc(result_ty_ref, null); + const ptr_ty_ref = try self.spv.ptrType(result_ty_ref, .Function); + const ptr_composite_id = self.spv.allocId(); + try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{ + .id_result_type = self.typeId(ptr_ty_ref), + .id_result = ptr_composite_id, + .storage_class = .Function, + }); + // Note: using 32-bit ints here because usize crashes the translator as well const index_ty_ref = try self.intType(.unsigned, 32); @@ -454,7 +460,7 @@ pub const DeclGen = struct { for (constituents, member_types, 0..) |constitent_id, member_ty_ref, index| { const index_id = try self.constInt(index_ty_ref, index); - const ptr_member_ty_ref = try self.spv.ptrType(member_ty_ref, .Generic); + const ptr_member_ty_ref = try self.spv.ptrType(member_ty_ref, .Function); const ptr_id = try self.accessChain(ptr_member_ty_ref, ptr_composite_id, &.{index_id}); try self.func.body.emit(self.spv.gpa, .OpStore, .{ .pointer = ptr_id, @@ -479,13 +485,20 @@ pub const DeclGen = struct { // For now, just initialize the struct by setting the fields manually... // TODO: Make this OpCompositeConstruct when we can // TODO: Make this Function storage type - const ptr_composite_id = try self.alloc(result_ty_ref, null); + const ptr_ty_ref = try self.spv.ptrType(result_ty_ref, .Function); + const ptr_composite_id = self.spv.allocId(); + try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{ + .id_result_type = self.typeId(ptr_ty_ref), + .id_result = ptr_composite_id, + .storage_class = .Function, + }); + // Note: using 32-bit ints here because usize crashes the translator as well const index_ty_ref = try self.intType(.unsigned, 32); const spv_composite_ty = self.spv.cache.lookup(result_ty_ref).array_type; const elem_ty_ref = spv_composite_ty.element_type; - const ptr_elem_ty_ref = try self.spv.ptrType(elem_ty_ref, .Generic); + const ptr_elem_ty_ref = try self.spv.ptrType(elem_ty_ref, .Function); for (constituents, 0..) |constitent_id, index| { const index_id = try self.constInt(index_ty_ref, index); -- cgit v1.2.3 From f16d1603ab199b6e605c5e83f2edaebcf89d5512 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 17 Sep 2023 13:24:29 +0200 Subject: spirv: fix type_map use-after-realloc issues --- src/codegen/spirv.zig | 55 ++++++++++++++++++--------------------------------- 1 file changed, 19 insertions(+), 36 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 768ebea623..34ea55eaf3 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -947,9 +947,10 @@ pub const DeclGen = struct { return try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect); } - // TODO: We need to add the active field to the key. - // const entry = try self.type_map.getOrPut(self.gpa, ty.toIntern()); - // if (entry.found_existing) return entry.value_ptr.ty_ref; + // TODO: We need to add the active field to the key, somehow. + if (maybe_active_field == null) { + if (self.type_map.get(ty.toIntern())) |info| return info.ty_ref; + } var member_types: [4]CacheRef = undefined; var member_names: [4]CacheString = undefined; @@ -986,10 +987,9 @@ pub const DeclGen = struct { .member_names = member_names[0..layout.total_fields], } }); - // entry.value_ptr.* = .{ - // .ty_ref = ty_ref, - // }; - + if (maybe_active_field == null) { + try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref }); + } return ty_ref; } @@ -1033,8 +1033,7 @@ pub const DeclGen = struct { return try self.spv.resolve(.{ .float_type = .{ .bits = bits } }); }, .Array => { - const entry = try self.type_map.getOrPut(self.gpa, ty.toIntern()); - if (entry.found_existing) return entry.value_ptr.ty_ref; + if (self.type_map.get(ty.toIntern())) |info| return info.ty_ref; const elem_ty = ty.childType(mod); const elem_ty_ref = try self.resolveType(elem_ty, .indirect); @@ -1042,15 +1041,12 @@ pub const DeclGen = struct { return self.fail("array type of {} elements is too large", .{ty.arrayLenIncludingSentinel(mod)}); }; const ty_ref = try self.spv.arrayType(total_len, elem_ty_ref); - entry.value_ptr.* = .{ - .ty_ref = ty_ref, - }; + try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref }); return ty_ref; }, .Fn => switch (repr) { .direct => { - const entry = try self.type_map.getOrPut(self.gpa, ty.toIntern()); - if (entry.found_existing) return entry.value_ptr.ty_ref; + if (self.type_map.get(ty.toIntern())) |info| return info.ty_ref; const fn_info = mod.typeToFunc(ty).?; // TODO: Put this somewhere in Sema.zig @@ -1069,10 +1065,7 @@ pub const DeclGen = struct { .parameters = param_ty_refs, } }); - entry.value_ptr.* = .{ - .ty_ref = ty_ref, - }; - + try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref }); return ty_ref; }, .indirect => { @@ -1119,8 +1112,7 @@ pub const DeclGen = struct { } }); }, .Struct => { - const entry = try self.type_map.getOrPut(self.gpa, ty.toIntern()); - if (entry.found_existing) return entry.value_ptr.ty_ref; + if (self.type_map.get(ty.toIntern())) |info| return info.ty_ref; const struct_type = switch (ip.indexToKey(ty.toIntern())) { .anon_struct_type => |tuple| { @@ -1140,9 +1132,7 @@ pub const DeclGen = struct { .member_types = member_types[0..member_index], } }); - entry.value_ptr.* = .{ - .ty_ref = ty_ref, - }; + try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref }); return ty_ref; }, .struct_type => |struct_type| struct_type, @@ -1151,6 +1141,7 @@ pub const DeclGen = struct { if (struct_type.layout == .Packed) { return try self.resolveType(struct_type.backingIntType(ip).toType(), .direct); + } var member_types = std.ArrayList(CacheRef).init(self.gpa); defer member_types.deinit(); @@ -1172,9 +1163,7 @@ pub const DeclGen = struct { .member_names = member_names.items, } }); - entry.value_ptr.* = .{ - .ty_ref = ty_ref, - }; + try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref }); return ty_ref; }, .Optional => { @@ -1192,8 +1181,7 @@ pub const DeclGen = struct { return payload_ty_ref; } - const entry = try self.type_map.getOrPut(self.gpa, ty.toIntern()); - if (entry.found_existing) return entry.value_ptr.ty_ref; + if (self.type_map.get(ty.toIntern())) |info| return info.ty_ref; const bool_ty_ref = try self.resolveType(Type.bool, .indirect); @@ -1205,9 +1193,7 @@ pub const DeclGen = struct { }, } }); - entry.value_ptr.* = .{ - .ty_ref = ty_ref, - }; + try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref }); return ty_ref; }, .Union => return try self.resolveUnionType(ty, null), @@ -1221,8 +1207,7 @@ pub const DeclGen = struct { return error_ty_ref; } - const entry = try self.type_map.getOrPut(self.gpa, ty.toIntern()); - if (entry.found_existing) return entry.value_ptr.ty_ref; + if (self.type_map.get(ty.toIntern())) |info| return info.ty_ref; const payload_ty_ref = try self.resolveType(payload_ty, .indirect); @@ -1252,9 +1237,7 @@ pub const DeclGen = struct { .member_names = &member_names, } }); - entry.value_ptr.* = .{ - .ty_ref = ty_ref, - }; + try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref }); return ty_ref; }, -- cgit v1.2.3 From 5141b4e05c08f394c4c0e76ea73f0547c9854288 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 17 Sep 2023 14:01:11 +0200 Subject: spirv: fix store of undef --- src/codegen/spirv.zig | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 34ea55eaf3..572af60f3c 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -2753,20 +2753,12 @@ pub const DeclGen = struct { } fn airStore(self: *DeclGen, inst: Air.Inst.Index) !void { - const mod = self.module; const bin_op = self.air.instructions.items(.data)[inst].bin_op; const ptr_ty = self.typeOf(bin_op.lhs); const ptr = try self.resolve(bin_op.lhs); const value = try self.resolve(bin_op.rhs); - const ptr_ty_ref = try self.resolveType(ptr_ty, .direct); - const val_is_undef = if (try self.air.value(bin_op.rhs, mod)) |val| val.isUndefDeep(mod) else false; - if (val_is_undef) { - const undef = try self.spv.constUndef(ptr_ty_ref); - try self.store(ptr_ty, ptr, undef); - } else { - try self.store(ptr_ty, ptr, value); - } + try self.store(ptr_ty, ptr, value); } fn airLoop(self: *DeclGen, inst: Air.Inst.Index) !void { @@ -2790,6 +2782,7 @@ pub const DeclGen = struct { const operand_ty = self.typeOf(operand); const mod = self.module; if (operand_ty.hasRuntimeBits(mod)) { + // TODO: If we return an empty struct, this branch is also hit incorrectly. const operand_id = try self.resolve(operand); try self.func.body.emit(self.spv.gpa, .OpReturnValue, .{ .value = operand_id }); } else { -- cgit v1.2.3 From c7c0517ac0a7aa54ac4f020555f3c13e71a51c43 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 17 Sep 2023 14:19:18 +0200 Subject: spirv: emit OpNot for arithmetic not --- src/codegen/spirv.zig | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 572af60f3c..1e11970c51 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -2403,13 +2403,31 @@ pub const DeclGen = struct { if (self.liveness.isUnused(inst)) return null; const ty_op = self.air.instructions.items(.data)[inst].ty_op; const operand_id = try self.resolve(ty_op.operand); + const result_ty = self.typeOfIndex(inst); + const result_ty_id = try self.resolveTypeId(result_ty); + const info = try self.arithmeticTypeInfo(result_ty); + const result_id = self.spv.allocId(); - const result_type_id = try self.resolveTypeId(Type.bool); - try self.func.body.emit(self.spv.gpa, .OpLogicalNot, .{ - .id_result_type = result_type_id, - .id_result = result_id, - .operand = operand_id, - }); + switch (info.class) { + .bool => { + try self.func.body.emit(self.spv.gpa, .OpLogicalNot, .{ + .id_result_type = result_ty_id, + .id_result = result_id, + .operand = operand_id, + }); + }, + .float => unreachable, + .composite_integer => unreachable, // TODO + .strange_integer, .integer => { + // Note: strange integer bits will be masked before operations that do not hold under modulo. + try self.func.body.emit(self.spv.gpa, .OpNot, .{ + .id_result_type = result_ty_id, + .id_result = result_id, + .operand = operand_id, + }); + }, + } + return result_id; } -- cgit v1.2.3 From 924235a0239b84856ac500a9c61507e43303234b Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 17 Sep 2023 14:22:15 +0200 Subject: spirv: emit OpLogical(Not)Equal for comparing bools --- src/codegen/spirv.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 1e11970c51..559008f3cd 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -2206,8 +2206,8 @@ pub const DeclGen = struct { .gte => .OpFOrdGreaterThanEqual, }, .bool => break :opcode switch (op) { - .eq => .OpIEqual, - .neq => .OpINotEqual, + .eq => .OpLogicalEqual, + .neq => .OpLogicalNotEqual, else => unreachable, }, .strange_integer => sign: { -- cgit v1.2.3 From decdedf97d493b665866cfa8207a7fcb6a94c017 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 17 Sep 2023 14:51:58 +0200 Subject: spirv: add names to globals and initializers --- src/codegen/spirv.zig | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 559008f3cd..f8c552f91f 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -1502,7 +1502,6 @@ pub const DeclGen = struct { try self.spv.addFunction(spv_decl_index, self.func); const fqn = ip.stringToSlice(try decl.getFullyQualifiedName(self.module)); - try self.spv.sections.debug_names.emit(self.gpa, .OpName, .{ .target = decl_id, .name = fqn, @@ -1578,6 +1577,19 @@ pub const DeclGen = struct { try self.spv.addFunction(spv_decl_index, self.func); try self.spv.initializers.append(self.spv.gpa, initializer_id); + + const fqn = ip.stringToSlice(try decl.getFullyQualifiedName(self.module)); + try self.spv.sections.debug_names.emit(self.gpa, .OpName, .{ + .target = decl_id, + .name = fqn, + }); + + const init_name = try std.fmt.allocPrint(self.gpa, "initializer of {s}", .{fqn}); + defer self.gpa.free(init_name); + try self.spv.sections.debug_names.emit(self.gpa, .OpName, .{ + .target = initializer_id, + .name = init_name, + }); } } -- cgit v1.2.3 From 5dffbf32bfb0c88163d2a116b6b0f9d802dce8cc Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 17 Sep 2023 17:17:46 +0200 Subject: spirv: air struct_field_val for unions --- src/codegen/spirv.zig | 158 +++++++++++++++++++++++++++++++++++------------- test/behavior/union.zig | 4 -- 2 files changed, 115 insertions(+), 47 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index f8c552f91f..7ac7672cdd 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -452,16 +452,12 @@ pub const DeclGen = struct { .storage_class = .Function, }); - // Note: using 32-bit ints here because usize crashes the translator as well - const index_ty_ref = try self.intType(.unsigned, 32); - const spv_composite_ty = self.spv.cache.lookup(result_ty_ref).struct_type; const member_types = spv_composite_ty.member_types; for (constituents, member_types, 0..) |constitent_id, member_ty_ref, index| { - const index_id = try self.constInt(index_ty_ref, index); const ptr_member_ty_ref = try self.spv.ptrType(member_ty_ref, .Function); - const ptr_id = try self.accessChain(ptr_member_ty_ref, ptr_composite_id, &.{index_id}); + const ptr_id = try self.accessChain(ptr_member_ty_ref, ptr_composite_id, &.{@as(u32, @intCast(index))}); try self.func.body.emit(self.spv.gpa, .OpStore, .{ .pointer = ptr_id, .object = constitent_id, @@ -493,16 +489,12 @@ pub const DeclGen = struct { .storage_class = .Function, }); - // Note: using 32-bit ints here because usize crashes the translator as well - const index_ty_ref = try self.intType(.unsigned, 32); - const spv_composite_ty = self.spv.cache.lookup(result_ty_ref).array_type; const elem_ty_ref = spv_composite_ty.element_type; const ptr_elem_ty_ref = try self.spv.ptrType(elem_ty_ref, .Function); for (constituents, 0..) |constitent_id, index| { - const index_id = try self.constInt(index_ty_ref, index); - const ptr_id = try self.accessChain(ptr_elem_ty_ref, ptr_composite_id, &.{index_id}); + const ptr_id = try self.accessChain(ptr_elem_ty_ref, ptr_composite_id, &.{@as(u32, @intCast(index))}); try self.func.body.emit(self.spv.gpa, .OpStore, .{ .pointer = ptr_id, .object = constitent_id, @@ -535,18 +527,36 @@ pub const DeclGen = struct { const decl_id = self.spv.declPtr(spv_decl_index).result_id; try self.func.decl_deps.put(self.spv.gpa, spv_decl_index, {}); - switch (decl.@"addrspace") { - .generic => { - // Pointer should be generic, but is actually placed in CrossWorkgroup. + const final_storage_class = spvStorageClass(decl.@"addrspace"); + + const decl_ty_ref = try self.resolveType(decl.ty, .indirect); + const decl_ptr_ty_ref = try self.spv.ptrType(decl_ty_ref, final_storage_class); + + const ptr_id = switch (final_storage_class) { + .Generic => blk: { + // Pointer should be Generic, but is actually placed in CrossWorkgroup. const result_id = self.spv.allocId(); try self.func.body.emit(self.spv.gpa, .OpPtrCastToGeneric, .{ - .id_result_type = ty_id, + .id_result_type = self.typeId(decl_ptr_ty_ref), .id_result = result_id, .pointer = decl_id, }); - return result_id; + break :blk result_id; }, - else => return decl_id, // Variable is already correct, probably. Maybe needs a bitcast? + else => decl_id, + }; + + if (decl_ptr_ty_ref != ty_ref) { + // Differing pointer types, insert a cast. + const casted_ptr_id = self.spv.allocId(); + try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ + .id_result_type = ty_id, + .id_result = casted_ptr_id, + .operand = ptr_id, + }); + return casted_ptr_id; + } else { + return ptr_id; } }, } @@ -820,14 +830,11 @@ pub const DeclGen = struct { .storage_class = .Function, }); - const index_ty_ref = try self.intType(.unsigned, 32); - if (layout.tag_size != 0) { - const index_id = try self.constInt(index_ty_ref, @as(u32, @intCast(layout.tag_index))); const tag_ty = ty.unionTagTypeSafety(mod).?; const tag_ty_ref = try self.resolveType(tag_ty, .indirect); const tag_ptr_ty_ref = try self.spv.ptrType(tag_ty_ref, .Function); - const ptr_id = try self.accessChain(tag_ptr_ty_ref, var_id, &.{index_id}); + const ptr_id = try self.accessChain(tag_ptr_ty_ref, var_id, &.{@as(u32, @intCast(layout.tag_index))}); const tag_id = try self.constant(tag_ty, un.tag.toValue(), .indirect); try self.func.body.emit(self.spv.gpa, .OpStore, .{ .pointer = ptr_id, @@ -836,10 +843,9 @@ pub const DeclGen = struct { } if (layout.active_field_size != 0) { - const index_id = try self.constInt(index_ty_ref, @as(u32, @intCast(layout.active_field_index))); const active_field_ty_ref = try self.resolveType(layout.active_field_ty, .indirect); const active_field_ptr_ty_ref = try self.spv.ptrType(active_field_ty_ref, .Function); - const ptr_id = try self.accessChain(active_field_ptr_ty_ref, var_id, &.{index_id}); + const ptr_id = try self.accessChain(active_field_ptr_ty_ref, var_id, &.{@as(u32, @intCast(layout.active_field_index))}); const value_id = try self.constant(layout.active_field_ty, un.val.toValue(), .indirect); try self.func.body.emit(self.spv.gpa, .OpStore, .{ .pointer = ptr_id, @@ -2070,40 +2076,65 @@ pub const DeclGen = struct { return result_id; } - /// AccessChain is essentially PtrAccessChain with 0 as initial argument. The effective - /// difference lies in whether the resulting type of the first dereference will be the - /// same as that of the base pointer, or that of a dereferenced base pointer. AccessChain - /// is the latter and PtrAccessChain is the former. - fn accessChain( + fn indicesToIds(self: *DeclGen, indices: []const u32) ![]IdRef { + const index_ty_ref = try self.intType(.unsigned, 32); + const ids = try self.gpa.alloc(IdRef, indices.len); + errdefer self.gpa.free(ids); + for (indices, ids) |index, *id| { + id.* = try self.constInt(index_ty_ref, index); + } + + return ids; + } + + fn accessChainId( self: *DeclGen, result_ty_ref: CacheRef, base: IdRef, - indexes: []const IdRef, + indices: []const IdRef, ) !IdRef { const result_id = self.spv.allocId(); try self.func.body.emit(self.spv.gpa, .OpInBoundsAccessChain, .{ .id_result_type = self.typeId(result_ty_ref), .id_result = result_id, .base = base, - .indexes = indexes, + .indexes = indices, }); return result_id; } + /// AccessChain is essentially PtrAccessChain with 0 as initial argument. The effective + /// difference lies in whether the resulting type of the first dereference will be the + /// same as that of the base pointer, or that of a dereferenced base pointer. AccessChain + /// is the latter and PtrAccessChain is the former. + fn accessChain( + self: *DeclGen, + result_ty_ref: CacheRef, + base: IdRef, + indices: []const u32, + ) !IdRef { + const ids = try self.indicesToIds(indices); + defer self.gpa.free(ids); + return try self.accessChainId(result_ty_ref, base, ids); + } + fn ptrAccessChain( self: *DeclGen, result_ty_ref: CacheRef, base: IdRef, element: IdRef, - indexes: []const IdRef, + indices: []const u32, ) !IdRef { + const ids = try self.indicesToIds(indices); + defer self.gpa.free(ids); + const result_id = self.spv.allocId(); try self.func.body.emit(self.spv.gpa, .OpInBoundsPtrAccessChain, .{ .id_result_type = self.typeId(result_ty_ref), .id_result = result_id, .base = base, .element = element, - .indexes = indexes, + .indexes = ids, }); return result_id; } @@ -2116,7 +2147,7 @@ pub const DeclGen = struct { .One => { // Pointer to array // TODO: Is this correct? - return try self.accessChain(result_ty_ref, ptr_id, &.{offset_id}); + return try self.accessChainId(result_ty_ref, ptr_id, &.{offset_id}); }, .C, .Many => { return try self.ptrAccessChain(result_ty_ref, ptr_id, offset_id, &.{}); @@ -2493,7 +2524,7 @@ pub const DeclGen = struct { if (ptr_ty.isSinglePointer(mod)) { // Pointer-to-array. In this case, the resulting pointer is not of the same type // as the ptr_ty (we want a *T, not a *[N]T), and hence we need to use accessChain. - return try self.accessChain(elem_ptr_ty_ref, ptr_id, &.{index_id}); + return try self.accessChainId(elem_ptr_ty_ref, ptr_id, &.{index_id}); } else { // Resulting pointer type is the same as the ptr_ty, so use ptrAccessChain return try self.ptrAccessChain(elem_ptr_ty_ref, ptr_id, index_id, &.{}); @@ -2540,15 +2571,14 @@ pub const DeclGen = struct { const un_ty = self.typeOf(ty_op.operand); const mod = self.module; - const layout = un_ty.unionGetLayout(mod); + const layout = self.unionLayout(un_ty, null); if (layout.tag_size == 0) return null; const union_handle = try self.resolve(ty_op.operand); if (layout.payload_size == 0) return union_handle; const tag_ty = un_ty.unionTagTypeSafety(mod).?; - const tag_index = @intFromBool(layout.tag_align.compare(.lt, layout.payload_align)); - return try self.extractField(tag_ty, union_handle, tag_index); + return try self.extractField(tag_ty, union_handle, layout.tag_index); } fn airStructFieldVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { @@ -2558,16 +2588,60 @@ pub const DeclGen = struct { const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data; - const struct_ty = self.typeOf(struct_field.struct_operand); + const container_ty = self.typeOf(struct_field.struct_operand); const object_id = try self.resolve(struct_field.struct_operand); const field_index = struct_field.field_index; - const field_ty = struct_ty.structFieldType(field_index, mod); + const field_ty = container_ty.structFieldType(field_index, mod); if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) return null; - assert(struct_ty.zigTypeTag(mod) == .Struct); // Cannot do unions yet. + switch (container_ty.zigTypeTag(mod)) { + .Struct => switch (container_ty.containerLayout(mod)) { + .Packed => unreachable, // TODO + else => return try self.extractField(field_ty, object_id, field_index), + }, + .Union => switch (container_ty.containerLayout(mod)) { + .Packed => unreachable, // TODO + else => { + // Store, pointer-cast, load + const un_general_ty_ref = try self.resolveType(container_ty, .indirect); + const un_general_ptr_ty_ref = try self.spv.ptrType(un_general_ty_ref, .Function); + const un_active_ty_ref = try self.resolveUnionType(container_ty, field_index); + const un_active_ptr_ty_ref = try self.spv.ptrType(un_active_ty_ref, .Function); + const field_ty_ref = try self.resolveType(field_ty, .indirect); + const field_ptr_ty_ref = try self.spv.ptrType(field_ty_ref, .Function); + + const tmp_id = self.spv.allocId(); + try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{ + .id_result_type = self.typeId(un_general_ptr_ty_ref), + .id_result = tmp_id, + .storage_class = .Function, + }); + try self.func.body.emit(self.spv.gpa, .OpStore, .{ + .pointer = tmp_id, + .object = object_id, + }); + const casted_tmp_id = self.spv.allocId(); + try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ + .id_result_type = self.typeId(un_active_ptr_ty_ref), + .id_result = casted_tmp_id, + .operand = tmp_id, + }); + const layout = self.unionLayout(container_ty, field_index); + const field_ptr_id = try self.accessChain(field_ptr_ty_ref, casted_tmp_id, &.{layout.active_field_index}); + const result_id = self.spv.allocId(); + try self.func.body.emit(self.spv.gpa, .OpLoad, .{ + .id_result_type = self.typeId(field_ty_ref), + .id_result = result_id, + .pointer = field_ptr_id, + }); + return try self.convertToDirect(field_ty, result_id); + }, + }, + else => unreachable, + } - return try self.extractField(field_ty, object_id, field_index); + // return try self.extractField(field_ty, object_id, field_index); } fn structFieldPtr( @@ -2583,10 +2657,8 @@ pub const DeclGen = struct { .Struct => switch (object_ty.containerLayout(mod)) { .Packed => unreachable, // TODO else => { - const field_index_ty_ref = try self.intType(.unsigned, 32); - const field_index_id = try self.constInt(field_index_ty_ref, field_index); const result_ty_ref = try self.resolveType(result_ptr_ty, .direct); - return try self.accessChain(result_ty_ref, object_ptr, &.{field_index_id}); + return try self.accessChain(result_ty_ref, object_ptr, &.{field_index}); }, }, else => unreachable, // TODO diff --git a/test/behavior/union.zig b/test/behavior/union.zig index 408506d3aa..aa4ba3bc44 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -14,7 +14,6 @@ test "basic unions with floats" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var foo = FooWithFloats{ .int = 1 }; try expect(foo.int == 1); @@ -42,7 +41,6 @@ test "basic unions" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var foo = Foo{ .int = 1 }; try expect(foo.int == 1); @@ -342,7 +340,6 @@ test "constant packed union" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; try testConstPackedUnion(&[_]PackThis{PackThis{ .StringLiteral = 1 }}); } @@ -453,7 +450,6 @@ test "global union with single field is correctly initialized" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; glbl = Foo1{ .f = @typeInfo(Foo1).Union.fields[0].type{ .x = 123 }, -- cgit v1.2.3 From 6f55a689644fa85a6f650e6d33bcb882b1f507cd Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 17 Sep 2023 17:29:38 +0200 Subject: spirv: air struct_field_ptr for unions --- src/codegen/spirv.zig | 22 ++++++++++++++++++++-- test/behavior/union.zig | 1 - 2 files changed, 20 insertions(+), 3 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 7ac7672cdd..8a77899bc0 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -2651,17 +2651,35 @@ pub const DeclGen = struct { object_ptr: IdRef, field_index: u32, ) !?IdRef { + const result_ty_ref = 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)) { .Packed => unreachable, // TODO else => { - const result_ty_ref = try self.resolveType(result_ptr_ty, .direct); return try self.accessChain(result_ty_ref, object_ptr, &.{field_index}); }, }, - else => unreachable, // TODO + .Union => switch (object_ty.containerLayout(mod)) { + .Packed => unreachable, // TODO + else => { + const storage_class = spvStorageClass(object_ptr_ty.ptrAddressSpace(mod)); + const un_active_ty_ref = try self.resolveUnionType(object_ty, field_index); + const un_active_ptr_ty_ref = try self.spv.ptrType(un_active_ty_ref, storage_class); + + const casted_id = self.spv.allocId(); + try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ + .id_result_type = self.typeId(un_active_ptr_ty_ref), + .id_result = casted_id, + .operand = object_ptr, + }); + const layout = self.unionLayout(object_ty, field_index); + return try self.accessChain(result_ty_ref, casted_id, &.{layout.active_field_index}); + }, + }, + else => unreachable, } } diff --git a/test/behavior/union.zig b/test/behavior/union.zig index aa4ba3bc44..003b6d3f8f 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -496,7 +496,6 @@ test "union initializer generates padding only if needed" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const U = union(enum) { A: u24, -- cgit v1.2.3 From 98046b4c3c09d3d115b38a943fce328a2dc20dc4 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 17 Sep 2023 18:36:45 +0200 Subject: spirv: air set_union_tag + improve load()/store() --- src/codegen/spirv.zig | 86 ++++++++++++++++++++++++++----------------------- test/behavior/union.zig | 19 ----------- 2 files changed, 45 insertions(+), 60 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 8a77899bc0..b11a822390 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -1662,13 +1662,11 @@ pub const DeclGen = struct { return try self.convertToDirect(result_ty, result_id); } - fn load(self: *DeclGen, ptr_ty: Type, ptr_id: IdRef) !IdRef { - const mod = self.module; - const value_ty = ptr_ty.childType(mod); + fn load(self: *DeclGen, value_ty: Type, ptr_id: IdRef, is_volatile: bool) !IdRef { const indirect_value_ty_ref = try self.resolveType(value_ty, .indirect); const result_id = self.spv.allocId(); const access = spec.MemoryAccess.Extended{ - .Volatile = ptr_ty.isVolatilePtr(mod), + .Volatile = is_volatile, }; try self.func.body.emit(self.spv.gpa, .OpLoad, .{ .id_result_type = self.typeId(indirect_value_ty_ref), @@ -1679,12 +1677,10 @@ pub const DeclGen = struct { return try self.convertToDirect(value_ty, result_id); } - fn store(self: *DeclGen, ptr_ty: Type, ptr_id: IdRef, value_id: IdRef) !void { - const mod = self.module; - const value_ty = ptr_ty.childType(mod); + fn store(self: *DeclGen, value_ty: Type, ptr_id: IdRef, value_id: IdRef, is_volatile: bool) !void { const indirect_value_id = try self.convertToIndirect(value_ty, value_id); const access = spec.MemoryAccess.Extended{ - .Volatile = ptr_ty.isVolatilePtr(mod), + .Volatile = is_volatile, }; try self.func.body.emit(self.spv.gpa, .OpStore, .{ .pointer = ptr_id, @@ -1754,6 +1750,7 @@ pub const DeclGen = struct { .ptr_elem_ptr => try self.airPtrElemPtr(inst), .ptr_elem_val => try self.airPtrElemVal(inst), + .set_union_tag => return try self.airSetUnionTag(inst), .get_union_tag => try self.airGetUnionTag(inst), .struct_field_val => try self.airStructFieldVal(inst), @@ -2512,7 +2509,7 @@ pub const DeclGen = struct { const slice_ptr = try self.extractField(ptr_ty, slice_id, 0); const elem_ptr = try self.ptrAccessChain(ptr_ty_ref, slice_ptr, index_id, &.{}); - return try self.load(slice_ty, elem_ptr); + return try self.load(slice_ty.childType(mod), elem_ptr, slice_ty.isVolatilePtr(mod)); } fn ptrElemPtr(self: *DeclGen, ptr_ty: Type, ptr_id: IdRef, index_id: IdRef) !IdRef { @@ -2548,25 +2545,41 @@ pub const DeclGen = struct { } fn airPtrElemVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { + if (self.liveness.isUnused(inst)) return null; + const mod = self.module; const bin_op = self.air.instructions.items(.data)[inst].bin_op; const ptr_ty = self.typeOf(bin_op.lhs); + const elem_ty = self.typeOfIndex(inst); const ptr_id = try self.resolve(bin_op.lhs); const index_id = try self.resolve(bin_op.rhs); - const elem_ptr_id = try self.ptrElemPtr(ptr_ty, ptr_id, index_id); + return try self.load(elem_ty, elem_ptr_id, ptr_ty.isVolatilePtr(mod)); + } + + fn airSetUnionTag(self: *DeclGen, inst: Air.Inst.Index) !void { + const mod = self.module; + const bin_op = self.air.instructions.items(.data)[inst].bin_op; + const un_ptr_ty = self.typeOf(bin_op.lhs); + const un_ty = un_ptr_ty.childType(mod); + const layout = self.unionLayout(un_ty, null); + + if (layout.tag_size == 0) return; + + const tag_ty = un_ty.unionTagTypeSafety(mod).?; + const tag_ty_ref = try self.resolveType(tag_ty, .indirect); + const tag_ptr_ty_ref = try self.spv.ptrType(tag_ty_ref, spvStorageClass(un_ptr_ty.ptrAddressSpace(mod))); - // If we have a pointer-to-array, construct an element pointer to use with load() - // If we pass ptr_ty directly, it will attempt to load the entire array rather than - // just an element. - var elem_ptr_info = ptr_ty.ptrInfo(mod); - elem_ptr_info.flags.size = .One; - const elem_ptr_ty = try mod.intern_pool.get(mod.gpa, .{ .ptr_type = elem_ptr_info }); + const union_ptr_id = try self.resolve(bin_op.lhs); + const new_tag_id = try self.resolve(bin_op.rhs); - return try self.load(elem_ptr_ty.toType(), elem_ptr_id); + const ptr_id = try self.accessChain(tag_ptr_ty_ref, union_ptr_id, &.{layout.tag_index}); + try self.store(tag_ty, ptr_id, new_tag_id, un_ptr_ty.isVolatilePtr(mod)); } fn airGetUnionTag(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { + if (self.liveness.isUnused(inst)) return null; + const ty_op = self.air.instructions.items(.data)[inst].ty_op; const un_ty = self.typeOf(ty_op.operand); @@ -2588,25 +2601,25 @@ pub const DeclGen = struct { const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data; - const container_ty = self.typeOf(struct_field.struct_operand); + const object_ty = self.typeOf(struct_field.struct_operand); const object_id = try self.resolve(struct_field.struct_operand); const field_index = struct_field.field_index; - const field_ty = container_ty.structFieldType(field_index, mod); + const field_ty = object_ty.structFieldType(field_index, mod); if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) return null; - switch (container_ty.zigTypeTag(mod)) { - .Struct => switch (container_ty.containerLayout(mod)) { + switch (object_ty.zigTypeTag(mod)) { + .Struct => switch (object_ty.containerLayout(mod)) { .Packed => unreachable, // TODO else => return try self.extractField(field_ty, object_id, field_index), }, - .Union => switch (container_ty.containerLayout(mod)) { + .Union => switch (object_ty.containerLayout(mod)) { .Packed => unreachable, // TODO else => { // Store, pointer-cast, load - const un_general_ty_ref = try self.resolveType(container_ty, .indirect); + const un_general_ty_ref = try self.resolveType(object_ty, .indirect); const un_general_ptr_ty_ref = try self.spv.ptrType(un_general_ty_ref, .Function); - const un_active_ty_ref = try self.resolveUnionType(container_ty, field_index); + const un_active_ty_ref = try self.resolveUnionType(object_ty, field_index); const un_active_ptr_ty_ref = try self.spv.ptrType(un_active_ty_ref, .Function); const field_ty_ref = try self.resolveType(field_ty, .indirect); const field_ptr_ty_ref = try self.spv.ptrType(field_ty_ref, .Function); @@ -2617,31 +2630,20 @@ pub const DeclGen = struct { .id_result = tmp_id, .storage_class = .Function, }); - try self.func.body.emit(self.spv.gpa, .OpStore, .{ - .pointer = tmp_id, - .object = object_id, - }); + try self.store(object_ty, tmp_id, object_id, false); const casted_tmp_id = self.spv.allocId(); try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ .id_result_type = self.typeId(un_active_ptr_ty_ref), .id_result = casted_tmp_id, .operand = tmp_id, }); - const layout = self.unionLayout(container_ty, field_index); + const layout = self.unionLayout(object_ty, field_index); const field_ptr_id = try self.accessChain(field_ptr_ty_ref, casted_tmp_id, &.{layout.active_field_index}); - const result_id = self.spv.allocId(); - try self.func.body.emit(self.spv.gpa, .OpLoad, .{ - .id_result_type = self.typeId(field_ty_ref), - .id_result = result_id, - .pointer = field_ptr_id, - }); - return try self.convertToDirect(field_ty, result_id); + return try self.load(field_ty, field_ptr_id, false); }, }, else => unreachable, } - - // return try self.extractField(field_ty, object_id, field_index); } fn structFieldPtr( @@ -2866,19 +2868,21 @@ pub const DeclGen = struct { const mod = self.module; const ty_op = self.air.instructions.items(.data)[inst].ty_op; const ptr_ty = self.typeOf(ty_op.operand); + const elem_ty = self.typeOfIndex(inst); const operand = try self.resolve(ty_op.operand); if (!ptr_ty.isVolatilePtr(mod) and self.liveness.isUnused(inst)) return null; - return try self.load(ptr_ty, operand); + return try self.load(elem_ty, operand, ptr_ty.isVolatilePtr(mod)); } fn airStore(self: *DeclGen, inst: Air.Inst.Index) !void { const bin_op = self.air.instructions.items(.data)[inst].bin_op; const ptr_ty = self.typeOf(bin_op.lhs); + const elem_ty = ptr_ty.childType(self.module); const ptr = try self.resolve(bin_op.lhs); const value = try self.resolve(bin_op.rhs); - try self.store(ptr_ty, ptr, value); + try self.store(elem_ty, ptr, value, ptr_ty.isVolatilePtr(self.module)); } fn airLoop(self: *DeclGen, inst: Air.Inst.Index) !void { @@ -2922,7 +2926,7 @@ pub const DeclGen = struct { } const ptr = try self.resolve(un_op); - const value = try self.load(ptr_ty, ptr); + const value = try self.load(ret_ty, ptr, ptr_ty.isVolatilePtr(mod)); try self.func.body.emit(self.spv.gpa, .OpReturnValue, .{ .value = value, }); diff --git a/test/behavior/union.zig b/test/behavior/union.zig index 003b6d3f8f..d87b411e99 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -29,7 +29,6 @@ test "init union with runtime value - floats" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var foo: FooWithFloats = undefined; @@ -59,7 +58,6 @@ test "init union with runtime value" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var foo: Foo = undefined; @@ -170,7 +168,6 @@ test "constant tagged union with payload" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var empty = TaggedUnionWithPayload{ .Empty = {} }; var full = TaggedUnionWithPayload{ .Full = 13 }; @@ -508,7 +505,6 @@ test "union initializer generates padding only if needed" { test "runtime tag name with single field" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const U = union(enum) { A: i32, @@ -585,7 +581,6 @@ test "tagged union as return value" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; switch (returnAnInt(13)) { TaggedFoo.One => |value| try expect(value == 13), @@ -630,7 +625,6 @@ test "union(enum(u32)) with specified and unspecified tag values" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; try comptime expect(Tag(Tag(MultipleChoice2)) == u32); try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 }); @@ -668,7 +662,6 @@ test "switch on union with only 1 field" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var r: PartialInst = undefined; r = PartialInst.Compiled; @@ -697,7 +690,6 @@ const PartialInstWithPayload = union(enum) { test "union with only 1 field casted to its enum type which has enum value specified" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const Literal = union(enum) { Number: f64, @@ -782,7 +774,6 @@ test "return union init with void payload" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn entry() !void { @@ -836,7 +827,6 @@ test "@unionInit can modify a union type" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const UnionInitEnum = union(enum) { Boolean: bool, @@ -860,7 +850,6 @@ test "@unionInit can modify a pointer value" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const UnionInitEnum = union(enum) { Boolean: bool, @@ -917,7 +906,6 @@ test "anonymous union literal syntax" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { const Number = union { @@ -1041,7 +1029,6 @@ test "switching on non exhaustive union" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { const E = enum(u8) { @@ -1225,7 +1212,6 @@ test "union tag is set when initiated as a temporary value at runtime" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const U = union(enum) { a, @@ -1263,7 +1249,6 @@ test "return an extern union from C calling convention" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const namespace = struct { const S = extern struct { @@ -1294,7 +1279,6 @@ test "noreturn field in union" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const U = union(enum) { a: u32, @@ -1475,7 +1459,6 @@ test "no dependency loop when function pointer in union returns the union" { test "union reassignment can use previous value" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const U = union { a: u32, @@ -1527,7 +1510,6 @@ test "reinterpreting enum value inside packed union" { test "access the tag of a global tagged union" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const U = union(enum) { a, @@ -1539,7 +1521,6 @@ test "access the tag of a global tagged union" { test "coerce enum literal to union in result loc" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const U = union(enum) { a, -- cgit v1.2.3 From 749307dbb260886433f366b3fdf9baf8f5b2ae30 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 17 Sep 2023 20:25:32 +0200 Subject: spirv: air union_init --- src/codegen/spirv.zig | 190 ++++++++++++++++++++++++++++++------------------ test/behavior/union.zig | 1 - 2 files changed, 120 insertions(+), 71 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index b11a822390..2d54fee891 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -801,77 +801,14 @@ pub const DeclGen = struct { else => unreachable, }, .un => |un| { - // To initialize a union, generate a temporary variable with the - // type that has the right field active, then pointer-cast and store - // the active field, and finally load and return the entire union. - - const union_ty = mod.typeToUnion(ty).?; - - if (union_ty.getLayout(ip) == .Packed) { - return self.todo("packed union types", .{}); - } - const active_field = ty.unionTagFieldIndex(un.tag.toValue(), mod).?; const layout = self.unionLayout(ty, active_field); + const payload = if (layout.active_field_size != 0) + try self.constant(layout.active_field_ty, un.val.toValue(), .indirect) + else + null; - if (layout.payload_size == 0) { - // No payload, so represent this as just the tag type. - return try self.constant(ty.unionTagTypeSafety(mod).?, un.tag.toValue(), .indirect); - } - - const un_active_ty_ref = try self.resolveUnionType(ty, active_field); - const un_active_ptr_ty_ref = try self.spv.ptrType(un_active_ty_ref, .Function); - const un_general_ptr_ty_ref = try self.spv.ptrType(result_ty_ref, .Function); - - const var_id = self.spv.allocId(); - try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{ - .id_result_type = self.typeId(un_active_ptr_ty_ref), - .id_result = var_id, - .storage_class = .Function, - }); - - if (layout.tag_size != 0) { - const tag_ty = ty.unionTagTypeSafety(mod).?; - const tag_ty_ref = try self.resolveType(tag_ty, .indirect); - const tag_ptr_ty_ref = try self.spv.ptrType(tag_ty_ref, .Function); - const ptr_id = try self.accessChain(tag_ptr_ty_ref, var_id, &.{@as(u32, @intCast(layout.tag_index))}); - const tag_id = try self.constant(tag_ty, un.tag.toValue(), .indirect); - try self.func.body.emit(self.spv.gpa, .OpStore, .{ - .pointer = ptr_id, - .object = tag_id, - }); - } - - if (layout.active_field_size != 0) { - const active_field_ty_ref = try self.resolveType(layout.active_field_ty, .indirect); - const active_field_ptr_ty_ref = try self.spv.ptrType(active_field_ty_ref, .Function); - const ptr_id = try self.accessChain(active_field_ptr_ty_ref, var_id, &.{@as(u32, @intCast(layout.active_field_index))}); - const value_id = try self.constant(layout.active_field_ty, un.val.toValue(), .indirect); - try self.func.body.emit(self.spv.gpa, .OpStore, .{ - .pointer = ptr_id, - .object = value_id, - }); - } - - // Just leave the padding fields uninitialized... - // TODO: Or should we initialize them with undef explicitly? - - // Now cast the pointer and load it as the 'generic' union type. - - const casted_var_id = self.spv.allocId(); - try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ - .id_result_type = self.typeId(un_general_ptr_ty_ref), - .id_result = casted_var_id, - .operand = var_id, - }); - - const result_id = self.spv.allocId(); - try self.func.body.emit(self.spv.gpa, .OpLoad, .{ - .id_result_type = self.typeId(result_ty_ref), - .id_result = result_id, - .pointer = casted_var_id, - }); - return result_id; + return try self.unionInit(ty, active_field, payload); }, .memoized_call => unreachable, } @@ -1752,6 +1689,8 @@ pub const DeclGen = struct { .set_union_tag => return try self.airSetUnionTag(inst), .get_union_tag => try self.airGetUnionTag(inst), + .union_init => try self.airUnionInit(inst), + .struct_field_val => try self.airStructFieldVal(inst), .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0), @@ -2573,8 +2512,12 @@ pub const DeclGen = struct { const union_ptr_id = try self.resolve(bin_op.lhs); const new_tag_id = try self.resolve(bin_op.rhs); - const ptr_id = try self.accessChain(tag_ptr_ty_ref, union_ptr_id, &.{layout.tag_index}); - try self.store(tag_ty, ptr_id, new_tag_id, un_ptr_ty.isVolatilePtr(mod)); + if (layout.payload_size == 0) { + try self.store(tag_ty, union_ptr_id, new_tag_id, un_ptr_ty.isVolatilePtr(mod)); + } else { + const ptr_id = try self.accessChain(tag_ptr_ty_ref, union_ptr_id, &.{layout.tag_index}); + try self.store(tag_ty, ptr_id, new_tag_id, un_ptr_ty.isVolatilePtr(mod)); + } } fn airGetUnionTag(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { @@ -2594,6 +2537,113 @@ pub const DeclGen = struct { return try self.extractField(tag_ty, union_handle, layout.tag_index); } + fn unionInit( + self: *DeclGen, + ty: Type, + active_field: u32, + payload: ?IdRef, + ) !IdRef { + // To initialize a union, generate a temporary variable with the + // type that has the right field active, then pointer-cast and store + // the active field, and finally load and return the entire union. + + const mod = self.module; + const ip = &mod.intern_pool; + const union_ty = mod.typeToUnion(ty).?; + + if (union_ty.getLayout(ip) == .Packed) { + unreachable; // TODO + } + + const maybe_tag_ty = ty.unionTagTypeSafety(mod); + const layout = self.unionLayout(ty, active_field); + + const tag_int = if (layout.tag_size != 0) blk: { + const tag_ty = maybe_tag_ty.?; + const union_field_name = union_ty.field_names.get(ip)[active_field]; + const enum_field_index = tag_ty.enumFieldIndex(union_field_name, mod).?; + const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index); + const tag_int_val = try tag_val.intFromEnum(tag_ty, mod); + break :blk tag_int_val.toUnsignedInt(mod); + } else 0; + + if (layout.payload_size == 0) { + const tag_ty_ref = try self.resolveType(maybe_tag_ty.?, .direct); + return try self.constInt(tag_ty_ref, tag_int); + } + + const un_active_ty_ref = try self.resolveUnionType(ty, active_field); + const un_active_ptr_ty_ref = try self.spv.ptrType(un_active_ty_ref, .Function); + const un_general_ty_ref = try self.resolveType(ty, .direct); + const un_general_ptr_ty_ref = try self.spv.ptrType(un_general_ty_ref, .Function); + + const tmp_id = self.spv.allocId(); + try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{ + .id_result_type = self.typeId(un_active_ptr_ty_ref), + .id_result = tmp_id, + .storage_class = .Function, + }); + + if (layout.tag_size != 0) { + const tag_ty_ref = try self.resolveType(maybe_tag_ty.?, .direct); + const tag_ptr_ty_ref = try self.spv.ptrType(tag_ty_ref, .Function); + const ptr_id = try self.accessChain(tag_ptr_ty_ref, tmp_id, &.{@as(u32, @intCast(layout.tag_index))}); + const tag_id = try self.constInt(tag_ty_ref, tag_int); + try self.func.body.emit(self.spv.gpa, .OpStore, .{ + .pointer = ptr_id, + .object = tag_id, + }); + } + + if (layout.active_field_size != 0) { + const active_field_ty_ref = try self.resolveType(layout.active_field_ty, .indirect); + const active_field_ptr_ty_ref = try self.spv.ptrType(active_field_ty_ref, .Function); + const ptr_id = try self.accessChain(active_field_ptr_ty_ref, tmp_id, &.{@as(u32, @intCast(layout.active_field_index))}); + try self.func.body.emit(self.spv.gpa, .OpStore, .{ + .pointer = ptr_id, + .object = payload.?, + }); + } else { + assert(payload == null); + } + + // Just leave the padding fields uninitialized... + // TODO: Or should we initialize them with undef explicitly? + + // Now cast the pointer and load it as the 'generic' union type. + + const casted_var_id = self.spv.allocId(); + try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ + .id_result_type = self.typeId(un_general_ptr_ty_ref), + .id_result = casted_var_id, + .operand = tmp_id, + }); + + const result_id = self.spv.allocId(); + try self.func.body.emit(self.spv.gpa, .OpLoad, .{ + .id_result_type = self.typeId(un_general_ty_ref), + .id_result = result_id, + .pointer = casted_var_id, + }); + + return result_id; + } + + fn airUnionInit(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { + if (self.liveness.isUnused(inst)) return null; + + const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; + const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data; + const ty = self.typeOfIndex(inst); + const layout = self.unionLayout(ty, extra.field_index); + + const payload = if (layout.active_field_size != 0) + try self.resolve(extra.init) + else + null; + return try self.unionInit(ty, extra.field_index, payload); + } + fn airStructFieldVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { if (self.liveness.isUnused(inst)) return null; diff --git a/test/behavior/union.zig b/test/behavior/union.zig index d87b411e99..a81da9d69e 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -997,7 +997,6 @@ test "cast from pointer to anonymous struct to pointer to union" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { const U = union(enum) { -- cgit v1.2.3 From 66b1f6c163e5fa3fddd3361a1ff4b64b3cbfc6bf Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 17 Sep 2023 20:57:00 +0200 Subject: spirv: air sub_with_overflow --- src/codegen/spirv.zig | 35 ++++++++++++++++++++++++++--------- test/behavior/math.zig | 1 - 2 files changed, 26 insertions(+), 10 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 2d54fee891..3ee9cb181e 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -1658,7 +1658,8 @@ pub const DeclGen = struct { .rem_optimized, => try self.airArithOp(inst, .OpFRem, .OpSRem, .OpSRem, false), - .add_with_overflow => try self.airOverflowArithOp(inst), + .add_with_overflow => try self.airAddSubOverflow(inst, .OpIAdd, .OpULessThan, .OpSLessThan), + .sub_with_overflow => try self.airAddSubOverflow(inst, .OpISub, .OpUGreaterThan, .OpSGreaterThan), .shuffle => try self.airShuffle(inst), @@ -1878,7 +1879,13 @@ pub const DeclGen = struct { return result_id; } - fn airOverflowArithOp(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { + fn airAddSubOverflow( + self: *DeclGen, + inst: Air.Inst.Index, + comptime add: Opcode, + comptime ucmp: Opcode, + comptime scmp: Opcode, + ) !?IdRef { if (self.liveness.isUnused(inst)) return null; const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; @@ -1910,7 +1917,7 @@ pub const DeclGen = struct { // TODO: Operations other than addition. const value_id = self.spv.allocId(); - try self.func.body.emit(self.spv.gpa, .OpIAdd, .{ + try self.func.body.emit(self.spv.gpa, add, .{ .id_result_type = operand_ty_id, .id_result = value_id, .operand_1 = lhs, @@ -1920,8 +1927,9 @@ pub const DeclGen = struct { const overflowed_id = switch (info.signedness) { .unsigned => blk: { // Overflow happened if the result is smaller than either of the operands. It doesn't matter which. + // For subtraction the conditions need to be swapped. const overflowed_id = self.spv.allocId(); - try self.func.body.emit(self.spv.gpa, .OpULessThan, .{ + try self.func.body.emit(self.spv.gpa, ucmp, .{ .id_result_type = self.typeId(bool_ty_ref), .id_result = overflowed_id, .operand_1 = value_id, @@ -1930,13 +1938,22 @@ pub const DeclGen = struct { break :blk overflowed_id; }, .signed => blk: { - // Overflow happened if: + // lhs - rhs + // For addition, overflow happened if: // - rhs is negative and value > lhs // - rhs is positive and value < lhs // This can be shortened to: - // (rhs < 0 && value > lhs) || (rhs >= 0 && value <= lhs) + // (rhs < 0 and value > lhs) or (rhs >= 0 and value <= lhs) // = (rhs < 0) == (value > lhs) + // = (rhs < 0) == (lhs < value) // Note that signed overflow is also wrapping in spir-v. + // For subtraction, overflow happened if: + // - rhs is negative and value < lhs + // - rhs is positive and value > lhs + // This can be shortened to: + // (rhs < 0 and value < lhs) or (rhs >= 0 and value >= lhs) + // = (rhs < 0) == (value < lhs) + // = (rhs < 0) == (lhs > value) const rhs_lt_zero_id = self.spv.allocId(); const zero_id = try self.constInt(operand_ty_ref, 0); @@ -1948,11 +1965,11 @@ pub const DeclGen = struct { }); const value_gt_lhs_id = self.spv.allocId(); - try self.func.body.emit(self.spv.gpa, .OpSGreaterThan, .{ + try self.func.body.emit(self.spv.gpa, scmp, .{ .id_result_type = self.typeId(bool_ty_ref), .id_result = value_gt_lhs_id, - .operand_1 = value_id, - .operand_2 = lhs, + .operand_1 = lhs, + .operand_2 = value_id, }); const overflowed_id = self.spv.allocId(); diff --git a/test/behavior/math.zig b/test/behavior/math.zig index 64ee1c4cbf..afbe0f911d 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -1020,7 +1020,6 @@ test "@subWithOverflow" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; { var a: u8 = 1; -- cgit v1.2.3 From 8d49b2ef4ef0682d1c258a5270f0646f85d7fe63 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 17 Sep 2023 23:18:06 +0200 Subject: spirv: air array_to_slice --- src/codegen/spirv.zig | 26 ++++++++++++++++++++++++++ test/behavior/slice.zig | 7 ------- 2 files changed, 26 insertions(+), 7 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 3ee9cb181e..962310f28a 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -1681,6 +1681,8 @@ pub const DeclGen = struct { .int_from_float => try self.airIntFromFloat(inst), .not => try self.airNot(inst), + .array_to_slice => try self.airArrayToSlice(inst), + .slice_ptr => try self.airSliceField(inst, 0), .slice_len => try self.airSliceField(inst, 1), .slice_elem_ptr => try self.airSliceElemPtr(inst), @@ -2427,6 +2429,30 @@ pub const DeclGen = struct { return result_id; } + fn airArrayToSlice(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { + const mod = self.module; + const ty_op = self.air.instructions.items(.data)[inst].ty_op; + const array_ptr_ty = self.typeOf(ty_op.operand); + const array_ty = array_ptr_ty.childType(mod); + const elem_ty = array_ptr_ty.elemType2(mod); // use elemType() so that we get T for *[N]T. + const elem_ty_ref = try self.resolveType(elem_ty, .indirect); + const elem_ptr_ty_ref = try self.spv.ptrType(elem_ty_ref, spvStorageClass(array_ptr_ty.ptrAddressSpace(mod))); + const slice_ty = self.typeOfIndex(inst); + const slice_ty_ref = try self.resolveType(slice_ty, .direct); + const size_ty_ref = try self.sizeType(); + + const array_ptr_id = try self.resolve(ty_op.operand); + const len_id = try self.constInt(size_ty_ref, array_ty.arrayLen(mod)); + + if (!array_ty.hasRuntimeBitsIgnoreComptime(mod)) { + unreachable; // TODO + } + + // Convert the pointer-to-array to a pointer to the first element. + const elem_ptr_id = try self.accessChain(elem_ptr_ty_ref, array_ptr_id, &.{0}); + return try self.constructStruct(slice_ty_ref, &.{ elem_ptr_id, len_id }); + } + 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; diff --git a/test/behavior/slice.zig b/test/behavior/slice.zig index 4316aca34f..c04c018017 100644 --- a/test/behavior/slice.zig +++ b/test/behavior/slice.zig @@ -29,7 +29,6 @@ comptime { test "slicing" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var array: [20]i32 = undefined; @@ -346,7 +345,6 @@ test "empty array to slice" { test "@ptrCast slice to pointer" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -572,7 +570,6 @@ test "slice syntax resulting in pointer-to-array" { test "slice pointer-to-array null terminated" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; comptime { var array = [5:0]u8{ 1, 2, 3, 4, 5 }; @@ -714,7 +711,6 @@ test "slice sentinel access at comptime" { test "slicing array with sentinel as end index" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn do() !void { @@ -733,7 +729,6 @@ test "slicing array with sentinel as end index" { test "slicing slice with sentinel as end index" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn do() !void { @@ -762,7 +757,6 @@ test "slice len modification at comptime" { } test "slice field ptr const" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const const_slice: []const u8 = "string"; @@ -777,7 +771,6 @@ test "slice field ptr const" { test "slice field ptr var" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var var_slice: []const u8 = "string"; -- cgit v1.2.3 From 26c279cca2e9b9d93c2d8744ba45c49076ff4a32 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Mon, 18 Sep 2023 20:28:17 +0200 Subject: spirv: air aggregate_init for array --- src/codegen/spirv.zig | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 962310f28a..e05c8142db 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -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; -- cgit v1.2.3 From 5d844faf7c5c30555664b4161e5f9a903daaf562 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Mon, 18 Sep 2023 20:28:31 +0200 Subject: spirv: air array_elem_val using hack SPIR-V doesn't support true element indexing, so we probably need to switch over to isByRef like in llvm for this to work properly. Currently a temporary is used, which at least seems to work. --- src/codegen/spirv.zig | 35 +++++++++++++++++++++++++++++++++++ test/behavior/array.zig | 11 ----------- 2 files changed, 35 insertions(+), 11 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index e05c8142db..e4ce3e5f3f 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -1694,6 +1694,7 @@ pub const DeclGen = struct { .slice_elem_val => try self.airSliceElemVal(inst), .ptr_elem_ptr => try self.airPtrElemPtr(inst), .ptr_elem_val => try self.airPtrElemVal(inst), + .array_elem_val => try self.airArrayElemVal(inst), .set_union_tag => return try self.airSetUnionTag(inst), .get_union_tag => try self.airGetUnionTag(inst), @@ -2567,6 +2568,40 @@ pub const DeclGen = struct { return try self.ptrElemPtr(ptr_ty, ptr_id, index_id); } + fn airArrayElemVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { + if (self.liveness.isUnused(inst)) return null; + + const mod = self.module; + const bin_op = self.air.instructions.items(.data)[inst].bin_op; + const array_ty = self.typeOf(bin_op.lhs); + const array_ty_ref = try self.resolveType(array_ty, .direct); + const elem_ty = array_ty.childType(mod); + const elem_ty_ref = try self.resolveType(elem_ty, .indirect); + const array_id = try self.resolve(bin_op.lhs); + const index_id = try self.resolve(bin_op.rhs); + + // SPIR-V doesn't have an array indexing function for some damn reason. + // For now, just generate a temporary and use that. + // TODO: This backend probably also should use isByRef from llvm... + + const array_ptr_ty_ref = try self.spv.ptrType(array_ty_ref, .Function); + const elem_ptr_ty_ref = try self.spv.ptrType(elem_ty_ref, .Function); + + const tmp_id = self.spv.allocId(); + try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{ + .id_result_type = self.typeId(array_ptr_ty_ref), + .id_result = tmp_id, + .storage_class = .Function, + }); + try self.func.body.emit(self.spv.gpa, .OpStore, .{ + .pointer = tmp_id, + .object = array_id, + }); + + const elem_ptr_id = try self.accessChainId(elem_ptr_ty_ref, tmp_id, &.{index_id}); + return try self.load(elem_ty, elem_ptr_id, false); + } + fn airPtrElemVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { if (self.liveness.isUnused(inst)) return null; diff --git a/test/behavior/array.zig b/test/behavior/array.zig index b252265c5b..7edef09578 100644 --- a/test/behavior/array.zig +++ b/test/behavior/array.zig @@ -21,7 +21,6 @@ test "arrays" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var array: [5]u32 = undefined; @@ -141,7 +140,6 @@ test "array literal with specified size" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var array = [2]u8{ 1, 2 }; try expect(array[0] == 1); @@ -201,7 +199,6 @@ test "nested arrays of strings" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const array_of_strings = [_][]const u8{ "hello", "this", "is", "my", "thing" }; for (array_of_strings, 0..) |s, i| { @@ -288,7 +285,6 @@ test "anonymous list literal syntax" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -479,7 +475,6 @@ test "anonymous literal in array" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { const Foo = struct { @@ -504,7 +499,6 @@ test "anonymous literal in array" { test "access the null element of a null terminated array" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -522,7 +516,6 @@ test "type deduction for array subscript expression" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -620,7 +613,6 @@ test "type coercion of pointer to anon struct literal to pointer to array" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { const U = union { @@ -703,7 +695,6 @@ test "array of array agregate init" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var a = [1]u32{11} ** 10; var b = [1][10]u32{a} ** 2; @@ -763,8 +754,6 @@ test "slicing array of zero-sized values" { } test "array init with no result pointer sets field result types" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - const S = struct { // A function parameter has a result type, but no result pointer. fn f(arr: [1]u32) u32 { -- cgit v1.2.3 From b845c9d5326bc83691edcb483ac44793b88afe75 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Mon, 18 Sep 2023 22:39:44 +0200 Subject: spirv: generate module initializer --- src/codegen/spirv.zig | 5 +- src/codegen/spirv/Module.zig | 116 +++++++++++++++++++++++++++++++++++-------- test/behavior/array.zig | 7 --- test/behavior/basic.zig | 8 +-- 4 files changed, 97 insertions(+), 39 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index e4ce3e5f3f..9d44b8eb8f 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -1494,7 +1494,6 @@ pub const DeclGen = struct { .id_result = decl_id, .storage_class = actual_storage_class, }); - self.spv.globalPtr(spv_decl_index).?.result_id = decl_id; // Now emit the instructions that initialize the variable. const initializer_id = self.spv.allocId(); @@ -1517,14 +1516,12 @@ pub const DeclGen = struct { }); // TODO: We should be able to get rid of this by now... - self.spv.endGlobal(spv_decl_index, begin); + self.spv.endGlobal(spv_decl_index, begin, decl_id, initializer_id); try self.func.body.emit(self.spv.gpa, .OpReturn, {}); try self.func.body.emit(self.spv.gpa, .OpFunctionEnd, {}); try self.spv.addFunction(spv_decl_index, self.func); - try self.spv.initializers.append(self.spv.gpa, initializer_id); - const fqn = ip.stringToSlice(try decl.getFullyQualifiedName(self.module)); try self.spv.sections.debug_names.emit(self.gpa, .OpName, .{ .target = decl_id, diff --git a/src/codegen/spirv/Module.zig b/src/codegen/spirv/Module.zig index cafc2f0662..b6ed381360 100644 --- a/src/codegen/spirv/Module.zig +++ b/src/codegen/spirv/Module.zig @@ -94,6 +94,8 @@ pub const Global = struct { begin_inst: u32, /// The past-end offset into `self.flobals.section`. end_inst: u32, + /// The result-id of the function that initializes this value. + initializer_id: IdRef, }; /// This models a kernel entry point. @@ -174,9 +176,6 @@ globals: struct { section: Section = .{}, } = .{}, -/// The function IDs of global variable initializers -initializers: std.ArrayListUnmanaged(IdRef) = .{}, - pub fn init(gpa: Allocator, arena: Allocator) Module { return .{ .gpa = gpa, @@ -205,8 +204,6 @@ pub fn deinit(self: *Module) void { self.globals.globals.deinit(self.gpa); self.globals.section.deinit(self.gpa); - self.initializers.deinit(self.gpa); - self.* = undefined; } @@ -289,6 +286,10 @@ fn addEntryPointDeps( const decl = self.declPtr(decl_index); const deps = self.decl_deps.items[decl.begin_dep..decl.end_dep]; + if (seen.isSet(@intFromEnum(decl_index))) { + return; + } + seen.set(@intFromEnum(decl_index)); if (self.globalPtr(decl_index)) |global| { @@ -296,9 +297,7 @@ fn addEntryPointDeps( } for (deps) |dep| { - if (!seen.isSet(@intFromEnum(dep))) { - try self.addEntryPointDeps(dep, seen, interface); - } + try self.addEntryPointDeps(dep, seen, interface); } } @@ -330,20 +329,76 @@ fn entryPoints(self: *Module) !Section { return entry_points; } +/// Generate a function that calls all initialization functions, +/// in unspecified order (an order should not be required here). +/// It generated as follows: +/// %init = OpFunction %void None +/// foreach %initializer: +/// OpFunctionCall %initializer +/// OpReturn +/// OpFunctionEnd +fn initializer(self: *Module, entry_points: *Section) !Section { + var section = Section{}; + errdefer section.deinit(self.gpa); + + // const void_ty_ref = try self.resolveType(Type.void, .direct); + const void_ty_ref = try self.resolve(.void_type); + const void_ty_id = self.resultId(void_ty_ref); + const init_proto_ty_ref = try self.resolve(.{ .function_type = .{ + .return_type = void_ty_ref, + .parameters = &.{}, + } }); + + const init_id = self.allocId(); + try section.emit(self.gpa, .OpFunction, .{ + .id_result_type = void_ty_id, + .id_result = init_id, + .function_control = .{}, + .function_type = self.resultId(init_proto_ty_ref), + }); + try section.emit(self.gpa, .OpLabel, .{ + .id_result = self.allocId(), + }); + + var seen = try std.DynamicBitSetUnmanaged.initEmpty(self.gpa, self.decls.items.len); + defer seen.deinit(self.gpa); + + var interface = std.ArrayList(IdRef).init(self.gpa); + defer interface.deinit(); + + for (self.globals.globals.keys(), self.globals.globals.values()) |decl_index, global| { + try self.addEntryPointDeps(decl_index, &seen, &interface); + try section.emit(self.gpa, .OpFunctionCall, .{ + .id_result_type = void_ty_id, + .id_result = self.allocId(), + .function = global.initializer_id, + }); + } + + try section.emit(self.gpa, .OpReturn, {}); + try section.emit(self.gpa, .OpFunctionEnd, {}); + + try entry_points.emit(self.gpa, .OpEntryPoint, .{ + // TODO: Rusticl does not support this because its poorly defined. + // Do we need to generate a workaround here? + .execution_model = .Kernel, + .entry_point = init_id, + .name = "zig global initializer", + .interface = interface.items, + }); + + try self.sections.execution_modes.emit(self.gpa, .OpExecutionMode, .{ + .entry_point = init_id, + .mode = .Initializer, + }); + + return section; +} + /// Emit this module as a spir-v binary. pub fn flush(self: *Module, file: std.fs.File) !void { // See SPIR-V Spec section 2.3, "Physical Layout of a SPIR-V Module and Instruction" - const header = [_]Word{ - spec.magic_number, - // TODO: From cpu features - // Emit SPIR-V 1.4 for now. This is the highest version that Intel's CPU OpenCL supports. - (1 << 16) | (4 << 8), - 0, // TODO: Register Zig compiler magic number. - self.idBound(), - 0, // Schema (currently reserved for future use) - }; - // TODO: Perform topological sort on the globals. var globals = try self.orderGlobals(); defer globals.deinit(self.gpa); @@ -354,6 +409,19 @@ pub fn flush(self: *Module, file: std.fs.File) !void { var types_constants = try self.cache.materialize(self); defer types_constants.deinit(self.gpa); + var init_func = try self.initializer(&entry_points); + defer init_func.deinit(self.gpa); + + const header = [_]Word{ + spec.magic_number, + // TODO: From cpu features + // Emit SPIR-V 1.4 for now. This is the highest version that Intel's CPU OpenCL supports. + (1 << 16) | (4 << 8), + 0, // TODO: Register Zig compiler magic number. + self.idBound(), + 0, // Schema (currently reserved for future use) + }; + // Note: needs to be kept in order according to section 2.3! const buffers = &[_][]const Word{ &header, @@ -368,6 +436,7 @@ pub fn flush(self: *Module, file: std.fs.File) !void { self.sections.types_globals_constants.toWords(), globals.toWords(), self.sections.functions.toWords(), + init_func.toWords(), }; var iovc_buffers: [buffers.len]std.os.iovec_const = undefined; @@ -529,6 +598,7 @@ pub fn allocDecl(self: *Module, kind: DeclKind) !Decl.Index { .result_id = undefined, .begin_inst = undefined, .end_inst = undefined, + .initializer_id = undefined, }), } @@ -558,10 +628,14 @@ pub fn beginGlobal(self: *Module) u32 { return @as(u32, @intCast(self.globals.section.instructions.items.len)); } -pub fn endGlobal(self: *Module, global_index: Decl.Index, begin_inst: u32) void { +pub fn endGlobal(self: *Module, global_index: Decl.Index, begin_inst: u32, result_id: IdRef, initializer_id: IdRef) void { const global = self.globalPtr(global_index).?; - global.begin_inst = begin_inst; - global.end_inst = @as(u32, @intCast(self.globals.section.instructions.items.len)); + global.* = .{ + .result_id = result_id, + .begin_inst = begin_inst, + .end_inst = @intCast(self.globals.section.instructions.items.len), + .initializer_id = initializer_id, + }; } pub fn declareEntryPoint(self: *Module, decl_index: Decl.Index, name: []const u8) !void { diff --git a/test/behavior/array.zig b/test/behavior/array.zig index 7edef09578..6fa93b4657 100644 --- a/test/behavior/array.zig +++ b/test/behavior/array.zig @@ -48,7 +48,6 @@ fn getArrayLen(a: []const u32) usize { test "array concat with undefined" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -88,7 +87,6 @@ test "array concat with tuple" { test "array init with concat" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const a = 'a'; var i: [4]u8 = [2]u8{ a, 'b' } ++ [2]u8{ 'c', 'd' }; @@ -98,7 +96,6 @@ test "array init with concat" { test "array init with mult" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const a = 'a'; var i: [8]u8 = [2]u8{ a, 'b' } ** 4; @@ -241,7 +238,6 @@ fn plusOne(x: u32) u32 { test "single-item pointer to array indexing and slicing" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; try testSingleItemPtrArrayIndexSlice(); try comptime testSingleItemPtrArrayIndexSlice(); @@ -384,7 +380,6 @@ test "runtime initialize array elem and then implicit cast to slice" { test "array literal as argument to function" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn entry(two: i32) !void { @@ -413,7 +408,6 @@ test "double nested array to const slice cast in array literal" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn entry(two: i32) !void { @@ -651,7 +645,6 @@ test "tuple to array handles sentinel" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { const a = .{ 1, 2, 3 }; diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index 57a579cfdb..9a75a8495d 100644 --- a/test/behavior/basic.zig +++ b/test/behavior/basic.zig @@ -330,7 +330,6 @@ const FnPtrWrapper = struct { test "const ptr from var variable" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var x: u64 = undefined; var y: u64 = undefined; @@ -581,7 +580,7 @@ test "comptime cast fn to ptr" { } test "equality compare fn ptrs" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // Test passes but should not + if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var a = &emptyFn; try expect(a == a); @@ -639,7 +638,6 @@ test "global constant is loaded with a runtime-known index" { test "multiline string literal is null terminated" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const s1 = \\one @@ -711,7 +709,6 @@ test "comptime manyptr concatenation" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const s = "epic"; const actual = manyptrConcat(s); @@ -1027,7 +1024,6 @@ comptime { test "switch inside @as gets correct type" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var a: u32 = 0; var b: [2]u32 = undefined; @@ -1136,8 +1132,6 @@ test "orelse coercion as function argument" { } test "runtime-known globals initialized with undefined" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - const S = struct { var array: [10]u32 = [_]u32{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; var vp: [*]u32 = undefined; -- cgit v1.2.3 From 48ab11639ab54914043cc8011587fe3be47a0e1f Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Tue, 19 Sep 2023 20:09:15 +0200 Subject: spirv: air is_err, is_non_err --- src/codegen/spirv.zig | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 9d44b8eb8f..da8fbb8556 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -1736,6 +1736,8 @@ pub const DeclGen = struct { .is_null => try self.airIsNull(inst, .is_null), .is_non_null => try self.airIsNull(inst, .is_non_null), + .is_err => try self.airIsErr(inst, .is_err), + .is_non_err => try self.airIsErr(inst, .is_non_err), .optional_payload => try self.airUnwrapOptional(inst), .wrap_optional => try self.airWrapOptional(inst), @@ -3276,6 +3278,42 @@ pub const DeclGen = struct { }; } + fn airIsErr(self: *DeclGen, inst: Air.Inst.Index, pred: enum { is_err, is_non_err }) !?IdRef { + if (self.liveness.isUnused(inst)) return null; + + const mod = self.module; + const un_op = self.air.instructions.items(.data)[inst].un_op; + const operand_id = try self.resolve(un_op); + const err_union_ty = self.typeOf(un_op); + + if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { + return try self.constBool(pred == .is_non_err, .direct); + } + + const payload_ty = err_union_ty.errorUnionPayload(mod); + const eu_layout = self.errorUnionLayout(payload_ty); + const bool_ty_ref = try self.resolveType(Type.bool, .direct); + const err_ty_ref = try self.resolveType(Type.anyerror, .direct); + + const error_id = if (!eu_layout.payload_has_bits) + operand_id + else + try self.extractField(Type.anyerror, operand_id, eu_layout.errorFieldIndex()); + + const result_id = self.spv.allocId(); + const operands = .{ + .id_result_type = self.typeId(bool_ty_ref), + .id_result = result_id, + .operand_1 = error_id, + .operand_2 = try self.constInt(err_ty_ref, 0), + }; + switch (pred) { + .is_err => try self.func.body.emit(self.spv.gpa, .OpINotEqual, operands), + .is_non_err => try self.func.body.emit(self.spv.gpa, .OpIEqual, operands), + } + return result_id; + } + fn airUnwrapOptional(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { if (self.liveness.isUnused(inst)) return null; -- cgit v1.2.3 From 4f215a6d2894182f90328e2aa213f92d8e479ec7 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Tue, 19 Sep 2023 20:26:22 +0200 Subject: spirv: air unwrap_errunion_payload --- src/codegen/spirv.zig | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index da8fbb8556..c46be03548 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -1732,6 +1732,7 @@ pub const DeclGen = struct { .unreach, .trap => return self.airUnreach(), .unwrap_errunion_err => try self.airErrUnionErr(inst), + .unwrap_errunion_payload => try self.airErrUnionPayload(inst), .wrap_errunion_err => try self.airWrapErrUnionErr(inst), .is_null => try self.airIsNull(inst, .is_null), @@ -3185,6 +3186,21 @@ pub const DeclGen = struct { return try self.extractField(Type.anyerror, operand_id, eu_layout.errorFieldIndex()); } + fn airErrUnionPayload(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { + if (self.liveness.isUnused(inst)) return null; + + const ty_op = self.air.instructions.items(.data)[inst].ty_op; + const operand_id = try self.resolve(ty_op.operand); + const payload_ty = self.typeOfIndex(inst); + const eu_layout = self.errorUnionLayout(payload_ty); + + if (!eu_layout.payload_has_bits) { + return null; // No error possible. + } + + return try self.extractField(payload_ty, operand_id, eu_layout.payloadFieldIndex()); + } + fn airWrapErrUnionErr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { if (self.liveness.isUnused(inst)) return null; -- cgit v1.2.3 From 8895025688b599a7082669234d40b26001bd9ed0 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Tue, 19 Sep 2023 20:26:30 +0200 Subject: spirv: air wrap_errunion_payload --- src/codegen/spirv.zig | 38 +++++++++++++++++++++++++++----------- test/behavior/error.zig | 14 -------------- 2 files changed, 27 insertions(+), 25 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index c46be03548..aa5b56f58a 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -1734,6 +1734,7 @@ pub const DeclGen = struct { .unwrap_errunion_err => try self.airErrUnionErr(inst), .unwrap_errunion_payload => try self.airErrUnionPayload(inst), .wrap_errunion_err => try self.airWrapErrUnionErr(inst), + .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), .is_null => try self.airIsNull(inst, .is_null), .is_non_null => try self.airIsNull(inst, .is_non_null), @@ -3216,20 +3217,35 @@ pub const DeclGen = struct { } const payload_ty_ref = try self.resolveType(payload_ty, .indirect); - var members = std.BoundedArray(IdRef, 2){}; - const payload_id = try self.spv.constUndef(payload_ty_ref); - if (eu_layout.error_first) { - members.appendAssumeCapacity(operand_id); - members.appendAssumeCapacity(payload_id); - // TODO: ABI padding? - } else { - members.appendAssumeCapacity(payload_id); - members.appendAssumeCapacity(operand_id); - // TODO: ABI padding? + + var members: [2]IdRef = undefined; + members[eu_layout.errorFieldIndex()] = operand_id; + members[eu_layout.payloadFieldIndex()] = try self.spv.constUndef(payload_ty_ref); + + const err_union_ty_ref = try self.resolveType(err_union_ty, .direct); + return try self.constructStruct(err_union_ty_ref, &members); + } + + fn airWrapErrUnionPayload(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { + if (self.liveness.isUnused(inst)) return null; + + const ty_op = self.air.instructions.items(.data)[inst].ty_op; + const err_union_ty = self.typeOfIndex(inst); + const operand_id = try self.resolve(ty_op.operand); + const payload_ty = self.typeOf(ty_op.operand); + const err_ty_ref = try self.resolveType(Type.anyerror, .direct); + const eu_layout = self.errorUnionLayout(payload_ty); + + if (!eu_layout.payload_has_bits) { + return try self.constInt(err_ty_ref, 0); } + var members: [2]IdRef = undefined; + members[eu_layout.errorFieldIndex()] = try self.constInt(err_ty_ref, 0); + members[eu_layout.payloadFieldIndex()] = try self.convertToIndirect(payload_ty, operand_id); + const err_union_ty_ref = try self.resolveType(err_union_ty, .direct); - return try self.constructStruct(err_union_ty_ref, members.slice()); + return try self.constructStruct(err_union_ty_ref, &members); } fn airIsNull(self: *DeclGen, inst: Air.Inst.Index, pred: enum { is_null, is_non_null }) !?IdRef { diff --git a/test/behavior/error.zig b/test/behavior/error.zig index dc4cd838ec..038bd94dfa 100644 --- a/test/behavior/error.zig +++ b/test/behavior/error.zig @@ -30,7 +30,6 @@ fn shouldBeNotEqual(a: anyerror, b: anyerror) void { test "error binary operator" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const a = errBinaryOperatorG(true) catch 3; const b = errBinaryOperatorG(false) catch 3; @@ -62,14 +61,12 @@ pub fn baz() anyerror!i32 { test "error wrapping" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; try expect((baz() catch unreachable) == 15); } test "unwrap simple value from error" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const i = unwrapSimpleValueFromErrorDo() catch unreachable; try expect(i == 13); @@ -80,7 +77,6 @@ fn unwrapSimpleValueFromErrorDo() anyerror!isize { test "error return in assignment" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; doErrReturnInAssignment() catch unreachable; } @@ -103,7 +99,6 @@ test "syntax: optional operator in front of error union operator" { test "widen cast integer payload of error union function call" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn errorable() !u64 { @@ -150,7 +145,6 @@ test "implicit cast to optional to error union to return result loc" { } test "fn returning empty error set can be passed as fn returning any error" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; entry(); comptime entry(); } @@ -243,7 +237,6 @@ fn testExplicitErrorSetCast(set1: Set1) !void { test "comptime test error for empty error set" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; try testComptimeTestErrorEmptySet(1234); try comptime testComptimeTestErrorEmptySet(1234); @@ -279,7 +272,6 @@ test "inferred empty error set comptime catch" { } test "error inference with an empty set" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { const Struct = struct { pub fn func() (error{})!usize { @@ -334,7 +326,6 @@ fn quux_1() !i32 { test "error: Zero sized error set returned with value payload crash" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; _ = try foo3(0); _ = try comptime foo3(0); @@ -434,7 +425,6 @@ test "nested error union function call in optional unwrap" { test "return function call to error set from error union function" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn errorable() anyerror!i32 { @@ -670,7 +660,6 @@ test "peer type resolution of two different error unions" { } test "coerce error set to the current inferred error set" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn foo() !void { var a = false; @@ -862,8 +851,6 @@ fn non_errorable() void { } test "catch within a function that calls no errorable functions" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - non_errorable(); } @@ -895,7 +882,6 @@ test "field access of anyerror results in smaller error set" { test "optional error union return type" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn foo() ?anyerror!u32 { -- cgit v1.2.3 From a75300c8d8cfe21647db1d50f77a9a1ee8d62a0e Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Tue, 19 Sep 2023 23:32:49 +0200 Subject: spirv: air slice --- src/codegen/spirv.zig | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index aa5b56f58a..496bd0150b 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -1683,6 +1683,7 @@ pub const DeclGen = struct { .not => try self.airNot(inst), .array_to_slice => try self.airArrayToSlice(inst), + .slice => try self.airSlice(inst), .aggregate_init => try self.airAggregateInit(inst), .slice_ptr => try self.airSliceField(inst, 0), @@ -2462,6 +2463,22 @@ pub const DeclGen = struct { return try self.constructStruct(slice_ty_ref, &.{ elem_ptr_id, len_id }); } + fn airSlice(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { + 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 ptr_id = try self.resolve(bin_op.lhs); + const len_id = try self.resolve(bin_op.rhs); + const slice_ty = self.typeOfIndex(inst); + const slice_ty_ref = try self.resolveType(slice_ty, .direct); + + return try self.constructStruct(slice_ty_ref, &.{ + ptr_id, // Note: Type should not need to be converted to direct. + len_id, // Note: Type should not need to be converted to direct. + }); + } + fn airAggregateInit(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { if (self.liveness.isUnused(inst)) return null; -- cgit v1.2.3 From d9a8c779d8d7e251bcb549c4b1627508c012ee8c Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Wed, 20 Sep 2023 23:34:26 +0200 Subject: spirv: constant elem ptr --- src/codegen/spirv.zig | 51 ++++++++++++++++++++++++++++++---------------- test/behavior/pointers.zig | 8 -------- test/behavior/slice.zig | 3 --- 3 files changed, 33 insertions(+), 29 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 496bd0150b..11737943fe 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -694,24 +694,7 @@ pub const DeclGen = struct { .none => ty, else => ty.slicePtrFieldType(mod), }; - const ptr_id = switch (ptr.addr) { - .decl => |decl| try self.constructDeclRef(ptr_ty, decl), - .mut_decl => |mut_decl| try self.constructDeclRef(ptr_ty, mut_decl.decl), // TODO - .int => |int| blk: { - const ptr_id = self.spv.allocId(); - // TODO: This can probably be an OpSpecConstantOp Bitcast, but - // that is not implemented by Mesa yet. Therefore, just generate it - // as a runtime operation. - try self.func.body.emit(self.spv.gpa, .OpConvertUToPtr, .{ - .id_result_type = try self.resolveTypeId(ptr_ty), - .id_result = ptr_id, - .integer_value = try self.constant(Type.usize, int.toValue(), .direct), - }); - break :blk ptr_id; - }, - .comptime_field => unreachable, - else => |tag| return self.todo("pointer value of type {s}", .{@tagName(tag)}), - }; + const ptr_id = try self.constantPtr(ptr_ty, val); if (ptr.len == .none) { return ptr_id; } @@ -818,6 +801,38 @@ pub const DeclGen = struct { } } + fn constantPtr(self: *DeclGen, ptr_ty: Type, ptr_val: Value) !IdRef { + const result_ty_ref = try self.resolveType(ptr_ty, .direct); + const mod = self.module; + switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) { + .decl => |decl| return try self.constructDeclRef(ptr_ty, decl), + .mut_decl => |decl_mut| return try self.constructDeclRef(ptr_ty, decl_mut.decl), + .int => |int| { + const ptr_id = self.spv.allocId(); + // TODO: This can probably be an OpSpecConstantOp Bitcast, but + // that is not implemented by Mesa yet. Therefore, just generate it + // as a runtime operation. + try self.func.body.emit(self.spv.gpa, .OpConvertUToPtr, .{ + .id_result_type = self.typeId(result_ty_ref), + .id_result = ptr_id, + .integer_value = try self.constant(Type.usize, int.toValue(), .direct), + }); + return ptr_id; + }, + .eu_payload => unreachable, // TODO + .opt_payload => unreachable, // TODO + .comptime_field => unreachable, + .elem => |elem_ptr| { + const elem_ptr_ty = mod.intern_pool.typeOf(elem_ptr.base).toType(); + const parent_ptr_id = try self.constantPtr(elem_ptr_ty, elem_ptr.base.toValue()); + const size_ty_ref = try self.sizeType(); + const index_id = try self.constInt(size_ty_ref, elem_ptr.index); + return self.ptrAccessChain(result_ty_ref, parent_ptr_id, index_id, &.{}); + }, + .field => unreachable, // TODO + } + } + // Turn a Zig type's name into a cache reference. fn resolveTypeName(self: *DeclGen, ty: Type) !CacheString { var name = std.ArrayList(u8).init(self.gpa); diff --git a/test/behavior/pointers.zig b/test/behavior/pointers.zig index d007e7b480..2a878e89c9 100644 --- a/test/behavior/pointers.zig +++ b/test/behavior/pointers.zig @@ -141,7 +141,6 @@ test "peer type resolution with C pointers" { } test "peer type resolution with C pointer and const pointer" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var ptr_c: [*c]u8 = undefined; const ptr_const: u8 = undefined; try expect(@TypeOf(ptr_c, &ptr_const) == [*c]const u8); @@ -314,7 +313,6 @@ test "allow any sentinel" { test "pointer sentinel with enums" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { const Number = enum { @@ -336,7 +334,6 @@ test "pointer sentinel with optional element" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -353,7 +350,6 @@ test "pointer sentinel with +inf" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -374,7 +370,6 @@ test "pointer to array at fixed address" { } test "pointer arithmetic affects the alignment" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; { var ptr: [*]align(8) u32 = undefined; var x: usize = 1; @@ -430,7 +425,6 @@ test "indexing array with sentinel returns correct type" { test "element pointer to slice" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -453,7 +447,6 @@ test "element pointer to slice" { test "element pointer arithmetic to slice" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -478,7 +471,6 @@ test "element pointer arithmetic to slice" { test "array slicing to slice" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { diff --git a/test/behavior/slice.zig b/test/behavior/slice.zig index c04c018017..ce836eb337 100644 --- a/test/behavior/slice.zig +++ b/test/behavior/slice.zig @@ -121,7 +121,6 @@ test "slice of type" { test "generic malloc free" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const a = memAlloc(u8, 10) catch unreachable; memFree(u8, a); @@ -302,7 +301,6 @@ test "slice type with custom alignment" { test "obtaining a null terminated slice" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // here we have a normal array var buf: [50]u8 = undefined; @@ -623,7 +621,6 @@ test "type coercion of pointer to anon struct literal to pointer to slice" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { const U = union { -- cgit v1.2.3 From 075584a4d74276119372994d895bca747b1f861f Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 17 Sep 2023 23:41:10 +0200 Subject: spirv: enable passing tests --- src/codegen/spirv.zig | 8 ++++---- test/behavior/alignof.zig | 2 -- test/behavior/array.zig | 5 ----- test/behavior/basic.zig | 1 - test/behavior/bugs/10138.zig | 1 - test/behavior/bugs/10970.zig | 1 - test/behavior/bugs/11100.zig | 2 -- test/behavior/bugs/11165.zig | 2 -- test/behavior/bugs/11816.zig | 1 - test/behavior/bugs/12025.zig | 2 -- test/behavior/bugs/12033.zig | 2 -- test/behavior/bugs/12043.zig | 2 -- test/behavior/bugs/12119.zig | 1 - test/behavior/bugs/12891.zig | 8 -------- test/behavior/bugs/12928.zig | 4 ---- test/behavior/bugs/12984.zig | 1 - test/behavior/bugs/13113.zig | 1 - test/behavior/bugs/13159.zig | 1 - test/behavior/bugs/13285.zig | 1 - test/behavior/bugs/14854.zig | 2 -- test/behavior/bugs/1500.zig | 2 -- test/behavior/bugs/15778.zig | 2 -- test/behavior/bugs/2622.zig | 1 - test/behavior/bugs/3779.zig | 2 -- test/behavior/bugs/4954.zig | 1 - test/behavior/bugs/5398.zig | 1 - test/behavior/bugs/6456.zig | 1 - test/behavior/bugs/656.zig | 1 - test/behavior/bugs/7047.zig | 2 -- test/behavior/bugs/7187.zig | 2 -- test/behavior/bugs/8277.zig | 2 -- test/behavior/bugs/828.zig | 1 - test/behavior/byval_arg_var.zig | 1 - test/behavior/call.zig | 1 - test/behavior/cast.zig | 35 ----------------------------------- test/behavior/cast_int.zig | 1 - test/behavior/defer.zig | 2 -- test/behavior/empty_union.zig | 3 --- test/behavior/enum.zig | 4 ---- test/behavior/error.zig | 1 - test/behavior/eval.zig | 35 ----------------------------------- test/behavior/floatop.zig | 3 --- test/behavior/fn.zig | 12 ------------ test/behavior/for.zig | 4 ---- test/behavior/generics.zig | 14 -------------- test/behavior/inline_switch.zig | 3 --- test/behavior/math.zig | 2 -- test/behavior/maximum_minimum.zig | 2 -- test/behavior/slice.zig | 1 - test/behavior/struct.zig | 14 -------------- test/behavior/switch.zig | 10 ---------- test/behavior/this.zig | 1 - test/behavior/try.zig | 2 -- test/behavior/tuple.zig | 3 --- test/behavior/type_info.zig | 5 ----- test/behavior/undefined.zig | 3 --- test/behavior/underscore.zig | 1 - test/behavior/union.zig | 3 --- test/behavior/vector.zig | 2 -- test/behavior/while.zig | 15 --------------- 60 files changed, 4 insertions(+), 245 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 11737943fe..45c081c51d 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -801,7 +801,7 @@ pub const DeclGen = struct { } } - fn constantPtr(self: *DeclGen, ptr_ty: Type, ptr_val: Value) !IdRef { + fn constantPtr(self: *DeclGen, ptr_ty: Type, ptr_val: Value) Error!IdRef { const result_ty_ref = try self.resolveType(ptr_ty, .direct); const mod = self.module; switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) { @@ -1692,9 +1692,9 @@ pub const DeclGen = struct { .bitcast => try self.airBitCast(inst), .intcast, .trunc => try self.airIntCast(inst), - .int_from_ptr => try self.airIntFromPtr(inst), - .float_from_int => try self.airFloatFromInt(inst), - .int_from_float => try self.airIntFromFloat(inst), + .int_from_ptr => try self.airIntFromPtr(inst), + .float_from_int => try self.airFloatFromInt(inst), + .int_from_float => try self.airIntFromFloat(inst), .not => try self.airNot(inst), .array_to_slice => try self.airArrayToSlice(inst), diff --git a/test/behavior/alignof.zig b/test/behavior/alignof.zig index ddc514e4e3..0443b2d6b3 100644 --- a/test/behavior/alignof.zig +++ b/test/behavior/alignof.zig @@ -28,8 +28,6 @@ test "comparison of @alignOf(T) against zero" { } test "correct alignment for elements and slices of aligned array" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - var buf: [1024]u8 align(64) = undefined; var start: usize = 1; var end: usize = undefined; diff --git a/test/behavior/array.zig b/test/behavior/array.zig index 6fa93b4657..a291d3a7b7 100644 --- a/test/behavior/array.zig +++ b/test/behavior/array.zig @@ -158,7 +158,6 @@ test "array len field" { test "array with sentinels" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest(is_ct: bool) !void { @@ -225,7 +224,6 @@ test "nested arrays of integers" { test "implicit comptime in array type size" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var arr: [plusOne(10)]bool = undefined; try expect(arr.len == 11); @@ -318,7 +316,6 @@ test "read/write through global variable array of struct fields initialized via if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -358,7 +355,6 @@ fn testArrayByValAtComptime(b: [2]u8) u8 { test "comptime evaluating function that takes array by value" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const arr = [_]u8{ 1, 2 }; const x = comptime testArrayByValAtComptime(arr); @@ -370,7 +366,6 @@ test "comptime evaluating function that takes array by value" { test "runtime initialize array elem and then implicit cast to slice" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var two: i32 = 2; const x: []const i32 = &[_]i32{two}; diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index 9a75a8495d..aa4f41a25e 100644 --- a/test/behavior/basic.zig +++ b/test/behavior/basic.zig @@ -606,7 +606,6 @@ test "self reference through fn ptr field" { test "global variable initialized to global variable array element" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; try expect(global_ptr == &gdt[0]); } diff --git a/test/behavior/bugs/10138.zig b/test/behavior/bugs/10138.zig index 1c8ff7cf7c..56d8450f33 100644 --- a/test/behavior/bugs/10138.zig +++ b/test/behavior/bugs/10138.zig @@ -5,7 +5,6 @@ test "registers get overwritten when ignoring return" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.cpu.arch != .x86_64 or builtin.os.tag != .linux) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const fd = open(); _ = write(fd, "a", 1); diff --git a/test/behavior/bugs/10970.zig b/test/behavior/bugs/10970.zig index 008242196c..539dfaff71 100644 --- a/test/behavior/bugs/10970.zig +++ b/test/behavior/bugs/10970.zig @@ -7,7 +7,6 @@ test "breaking from a loop in an if statement" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var cond = true; const opt = while (cond) { diff --git a/test/behavior/bugs/11100.zig b/test/behavior/bugs/11100.zig index 1a55b94510..7e4ef7ce67 100644 --- a/test/behavior/bugs/11100.zig +++ b/test/behavior/bugs/11100.zig @@ -9,7 +9,5 @@ pub fn do() bool { } test "bug" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - try std.testing.expect(!do()); } diff --git a/test/behavior/bugs/11165.zig b/test/behavior/bugs/11165.zig index 129b605100..e23861ddc1 100644 --- a/test/behavior/bugs/11165.zig +++ b/test/behavior/bugs/11165.zig @@ -2,7 +2,6 @@ const builtin = @import("builtin"); test "bytes" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { a: u32, @@ -24,7 +23,6 @@ test "bytes" { test "aggregate" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { a: u32, diff --git a/test/behavior/bugs/11816.zig b/test/behavior/bugs/11816.zig index 6061d668f3..cb548ef2e9 100644 --- a/test/behavior/bugs/11816.zig +++ b/test/behavior/bugs/11816.zig @@ -4,7 +4,6 @@ const builtin = @import("builtin"); test { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var x: u32 = 3; const val: usize = while (true) switch (x) { diff --git a/test/behavior/bugs/12025.zig b/test/behavior/bugs/12025.zig index aa293aa6b5..92f8aff0aa 100644 --- a/test/behavior/bugs/12025.zig +++ b/test/behavior/bugs/12025.zig @@ -1,8 +1,6 @@ const builtin = @import("builtin"); test { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - comptime var st = .{ .foo = &1, .bar = &2, diff --git a/test/behavior/bugs/12033.zig b/test/behavior/bugs/12033.zig index dfe583f156..b7ff501e35 100644 --- a/test/behavior/bugs/12033.zig +++ b/test/behavior/bugs/12033.zig @@ -2,8 +2,6 @@ const std = @import("std"); const builtin = @import("builtin"); test { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - const string = "Hello!\x00World!"; try std.testing.expect(@TypeOf(string) == *const [13:0]u8); diff --git a/test/behavior/bugs/12043.zig b/test/behavior/bugs/12043.zig index 835b2f6b4e..1b04ecab46 100644 --- a/test/behavior/bugs/12043.zig +++ b/test/behavior/bugs/12043.zig @@ -7,8 +7,6 @@ fn foo(x: anytype) void { ok = x; } test { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - const x = &foo; x(true); try expect(ok); diff --git a/test/behavior/bugs/12119.zig b/test/behavior/bugs/12119.zig index 6cfb015eb0..e37c90b507 100644 --- a/test/behavior/bugs/12119.zig +++ b/test/behavior/bugs/12119.zig @@ -9,7 +9,6 @@ test { if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const zerox32: u8x32 = [_]u8{0} ** 32; const bigsum: u32x8 = @as(u32x8, @bitCast(zerox32)); diff --git a/test/behavior/bugs/12891.zig b/test/behavior/bugs/12891.zig index 9987a494e0..82995eb019 100644 --- a/test/behavior/bugs/12891.zig +++ b/test/behavior/bugs/12891.zig @@ -7,29 +7,21 @@ test "issue12891" { try std.testing.expect(i < f); } test "nan" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - const f = comptime std.math.nan(f64); var i: usize = 0; try std.testing.expect(!(f < i)); } test "inf" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - const f = comptime std.math.inf(f64); var i: usize = 0; try std.testing.expect(f > i); } test "-inf < 0" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - const f = comptime -std.math.inf(f64); var i: usize = 0; try std.testing.expect(f < i); } test "inf >= 1" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - const f = comptime std.math.inf(f64); var i: usize = 1; try std.testing.expect(f >= i); diff --git a/test/behavior/bugs/12928.zig b/test/behavior/bugs/12928.zig index dd5a7761d7..1d8afdd7c9 100644 --- a/test/behavior/bugs/12928.zig +++ b/test/behavior/bugs/12928.zig @@ -11,8 +11,6 @@ const B = extern struct { }; test { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - var a: *A = undefined; try expect(@TypeOf(&a.value.a) == *volatile u32); try expect(@TypeOf(&a.value.b) == *volatile i32); @@ -26,8 +24,6 @@ const D = extern union { b: i32, }; test { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - var c: *C = undefined; try expect(@TypeOf(&c.value.a) == *volatile u32); try expect(@TypeOf(&c.value.b) == *volatile i32); diff --git a/test/behavior/bugs/12984.zig b/test/behavior/bugs/12984.zig index 0b144ed159..75f2747eda 100644 --- a/test/behavior/bugs/12984.zig +++ b/test/behavior/bugs/12984.zig @@ -14,7 +14,6 @@ pub const CustomDraw = DeleagateWithContext(fn (?OnConfirm) void); test "simple test" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var c: CustomDraw = undefined; _ = c; diff --git a/test/behavior/bugs/13113.zig b/test/behavior/bugs/13113.zig index fd3a14f8f6..5a496aa29d 100644 --- a/test/behavior/bugs/13113.zig +++ b/test/behavior/bugs/13113.zig @@ -10,7 +10,6 @@ test { if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const foo = Foo{ .a = 1, diff --git a/test/behavior/bugs/13159.zig b/test/behavior/bugs/13159.zig index 6f8ae1842f..eec01658e6 100644 --- a/test/behavior/bugs/13159.zig +++ b/test/behavior/bugs/13159.zig @@ -11,7 +11,6 @@ const Bar = packed struct { test { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var foo = Bar.Baz.fizz; try expect(foo == .fizz); diff --git a/test/behavior/bugs/13285.zig b/test/behavior/bugs/13285.zig index b87020bf46..15ebfa5804 100644 --- a/test/behavior/bugs/13285.zig +++ b/test/behavior/bugs/13285.zig @@ -6,7 +6,6 @@ const Crasher = struct { test { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var a: Crasher = undefined; var crasher_ptr = &a; diff --git a/test/behavior/bugs/14854.zig b/test/behavior/bugs/14854.zig index 9c877bc688..8f01ccb3f4 100644 --- a/test/behavior/bugs/14854.zig +++ b/test/behavior/bugs/14854.zig @@ -2,8 +2,6 @@ const testing = @import("std").testing; const builtin = @import("builtin"); test { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - try testing.expect(getGeneric(u8, getU8) == 123); } diff --git a/test/behavior/bugs/1500.zig b/test/behavior/bugs/1500.zig index 3a6246b2c9..cc12c5d0be 100644 --- a/test/behavior/bugs/1500.zig +++ b/test/behavior/bugs/1500.zig @@ -6,8 +6,6 @@ const A = struct { const B = *const fn (A) void; test "allow these dependencies" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - var a: A = undefined; var b: B = undefined; if (false) { diff --git a/test/behavior/bugs/15778.zig b/test/behavior/bugs/15778.zig index 86b9fce7b6..5754eb6e11 100644 --- a/test/behavior/bugs/15778.zig +++ b/test/behavior/bugs/15778.zig @@ -6,7 +6,6 @@ test { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO const a = @Vector(0, i32){}; const b = @Vector(0, i32){}; _ = a + b; @@ -18,7 +17,6 @@ test { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO const a = @Vector(0, f32){}; const b = @Vector(0, f32){}; _ = a - b; diff --git a/test/behavior/bugs/2622.zig b/test/behavior/bugs/2622.zig index d3d2b078e2..89130a3974 100644 --- a/test/behavior/bugs/2622.zig +++ b/test/behavior/bugs/2622.zig @@ -7,7 +7,6 @@ test "reslice of undefined global var slice" { if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var mem: [100]u8 = [_]u8{0} ** 100; buf = &mem; diff --git a/test/behavior/bugs/3779.zig b/test/behavior/bugs/3779.zig index 2b1dad5de0..088443d529 100644 --- a/test/behavior/bugs/3779.zig +++ b/test/behavior/bugs/3779.zig @@ -8,7 +8,6 @@ const ptr_tag_name: [*:0]const u8 = tag_name; test "@tagName() returns a string literal" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; try std.testing.expect(*const [13:0]u8 == @TypeOf(tag_name)); try std.testing.expect(std.mem.eql(u8, "TestEnumValue", tag_name)); @@ -22,7 +21,6 @@ const ptr_error_name: [*:0]const u8 = error_name; test "@errorName() returns a string literal" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; try std.testing.expect(*const [13:0]u8 == @TypeOf(error_name)); try std.testing.expect(std.mem.eql(u8, "TestErrorCode", error_name)); diff --git a/test/behavior/bugs/4954.zig b/test/behavior/bugs/4954.zig index 15c3185fa9..8cae03d314 100644 --- a/test/behavior/bugs/4954.zig +++ b/test/behavior/bugs/4954.zig @@ -8,7 +8,6 @@ test "crash" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var buf: [4096]u8 = undefined; f(&buf); diff --git a/test/behavior/bugs/5398.zig b/test/behavior/bugs/5398.zig index 4dc4ab8d19..6f75bd9436 100644 --- a/test/behavior/bugs/5398.zig +++ b/test/behavior/bugs/5398.zig @@ -22,7 +22,6 @@ test "assignment of field with padding" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; renderable = Renderable{ .mesh = Mesh{ .id = 0 }, diff --git a/test/behavior/bugs/6456.zig b/test/behavior/bugs/6456.zig index 31dea02cf6..c74319a5bf 100644 --- a/test/behavior/bugs/6456.zig +++ b/test/behavior/bugs/6456.zig @@ -13,7 +13,6 @@ const text = test "issue 6456" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; comptime { var fields: []const StructField = &[0]StructField{}; diff --git a/test/behavior/bugs/656.zig b/test/behavior/bugs/656.zig index 161da66964..004f442165 100644 --- a/test/behavior/bugs/656.zig +++ b/test/behavior/bugs/656.zig @@ -14,7 +14,6 @@ test "optional if after an if in a switch prong of a switch with 2 prongs in an if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; try foo(false, true); } diff --git a/test/behavior/bugs/7047.zig b/test/behavior/bugs/7047.zig index a7a0966935..534624fa72 100644 --- a/test/behavior/bugs/7047.zig +++ b/test/behavior/bugs/7047.zig @@ -15,8 +15,6 @@ fn S(comptime query: U) type { } test "compiler doesn't consider equal unions with different 'type' payload" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - const s1 = S(U{ .T = u32 }).tag(); try std.testing.expectEqual(u32, s1); diff --git a/test/behavior/bugs/7187.zig b/test/behavior/bugs/7187.zig index be593d7fad..bb2e82af89 100644 --- a/test/behavior/bugs/7187.zig +++ b/test/behavior/bugs/7187.zig @@ -3,8 +3,6 @@ const builtin = @import("builtin"); const expect = std.testing.expect; test "miscompilation with bool return type" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - var x: usize = 1; var y: bool = getFalse(); _ = y; diff --git a/test/behavior/bugs/8277.zig b/test/behavior/bugs/8277.zig index 149962d996..8d64d49223 100644 --- a/test/behavior/bugs/8277.zig +++ b/test/behavior/bugs/8277.zig @@ -2,8 +2,6 @@ const std = @import("std"); const builtin = @import("builtin"); test "@sizeOf reified union zero-size payload fields" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - comptime { try std.testing.expect(0 == @sizeOf(@Type(@typeInfo(union {})))); try std.testing.expect(0 == @sizeOf(@Type(@typeInfo(union { a: void })))); diff --git a/test/behavior/bugs/828.zig b/test/behavior/bugs/828.zig index a0ac00817d..220d98ce09 100644 --- a/test/behavior/bugs/828.zig +++ b/test/behavior/bugs/828.zig @@ -31,7 +31,6 @@ fn constCount(comptime cb: *const CountBy, comptime unused: u32) void { test "comptime struct return should not return the same instance" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; //the first parameter must be passed by reference to trigger the bug //a second parameter is required to trigger the bug diff --git a/test/behavior/byval_arg_var.zig b/test/behavior/byval_arg_var.zig index 3a82ca86ad..01b5f90ef7 100644 --- a/test/behavior/byval_arg_var.zig +++ b/test/behavior/byval_arg_var.zig @@ -5,7 +5,6 @@ var result: []const u8 = "wrong"; test "pass string literal byvalue to a generic var param" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; start(); blowUpStack(10); diff --git a/test/behavior/call.zig b/test/behavior/call.zig index 6be66da174..beccb059d8 100644 --- a/test/behavior/call.zig +++ b/test/behavior/call.zig @@ -334,7 +334,6 @@ test "inline call preserves tail call" { test "inline call doesn't re-evaluate non generic struct" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn foo(f: struct { a: u8, b: u8 }) !void { diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index bdaece3533..f7ab8695c0 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -403,7 +403,6 @@ test "peer type unsigned int to signed" { test "expected [*c]const u8, found [*:0]const u8" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var a: [*:0]const u8 = "hello"; var b: [*c]const u8 = a; @@ -445,7 +444,6 @@ test "implicitly cast from T to anyerror!?T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; try castToOptionalTypeError(1); try comptime castToOptionalTypeError(1); @@ -521,7 +519,6 @@ fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 { test "implicit cast from *const [N]T to []const T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; try testCastConstArrayRefToConstSlice(); try comptime testCastConstArrayRefToConstSlice(); @@ -547,7 +544,6 @@ fn testCastConstArrayRefToConstSlice() !void { test "peer type resolution: error and [N]T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; try expect(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); try comptime expect(mem.eql(u8, try testPeerErrorAndArray(0), "OK")); @@ -709,7 +705,6 @@ test "peer type resolution: error set supersets" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const a: error{ One, Two } = undefined; const b: error{One} = undefined; @@ -739,7 +734,6 @@ test "peer type resolution: disjoint error sets" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const a: error{ One, Two } = undefined; const b: error{Three} = undefined; @@ -769,7 +763,6 @@ test "peer type resolution: error union and error set" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const a: error{Three} = undefined; const b: error{ One, Two }!u32 = undefined; @@ -803,7 +796,6 @@ test "peer type resolution: error union after non-error" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const a: u32 = undefined; const b: error{ One, Two }!u32 = undefined; @@ -863,7 +855,6 @@ test "peer cast *[0]T to []const T" { test "peer cast *[N]T to [*]T" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var array = [4:99]i32{ 1, 2, 3, 4 }; var dest: [*]i32 = undefined; @@ -930,7 +921,6 @@ test "peer cast [N:x]T to [N]T" { test "peer cast *[N:x]T to *[N]T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -946,7 +936,6 @@ test "peer cast *[N:x]T to *[N]T" { test "peer cast [*:x]T to [*]T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -967,7 +956,6 @@ test "peer cast [:x]T to [*:x]T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -988,7 +976,6 @@ test "peer cast [:x]T to [*:x]T" { test "peer type resolution implicit cast to return type" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -1009,7 +996,6 @@ test "peer type resolution implicit cast to return type" { test "peer type resolution implicit cast to variable type" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -1034,7 +1020,6 @@ test "variable initialization uses result locations properly with regards to the test "cast between C pointer with different but compatible types" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn foo(arg: [*]c_ushort) u16 { @@ -1052,7 +1037,6 @@ test "cast between C pointer with different but compatible types" { test "peer type resolve string lit with sentinel-terminated mutable slice" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var array: [4:0]u8 = undefined; array[4] = 0; // TODO remove this when #4372 is solved @@ -1062,8 +1046,6 @@ test "peer type resolve string lit with sentinel-terminated mutable slice" { } test "peer type resolve array pointers, one of them const" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - var array1: [4]u8 = undefined; const array2: [5]u8 = undefined; try comptime expect(@TypeOf(&array1, &array2) == []const u8); @@ -1071,8 +1053,6 @@ test "peer type resolve array pointers, one of them const" { } test "peer type resolve array pointer and unknown pointer" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - const const_array: [4]u8 = undefined; var array: [4]u8 = undefined; var const_ptr: [*]const u8 = undefined; @@ -1092,8 +1072,6 @@ test "peer type resolve array pointer and unknown pointer" { } test "comptime float casts" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - const a = @as(comptime_float, @floatFromInt(1)); try expect(a == 1); try expect(@TypeOf(a) == comptime_float); @@ -1140,8 +1118,6 @@ fn incrementVoidPtrArray(array: ?*anyopaque, len: usize) void { } test "compile time int to ptr of function" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - try foobar(FUNCTION_CONSTANT); } @@ -1341,8 +1317,6 @@ test "*const [N]null u8 to ?[]const u8" { } test "cast between [*c]T and ?[*:0]T on fn parameter" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - const S = struct { const Handler = ?fn ([*c]const u8) callconv(.C) void; fn addCallback(comptime handler: Handler) void { @@ -1382,7 +1356,6 @@ test "cast between *[N]void and []void" { test "peer resolve arrays of different size to const slice" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; try expect(mem.eql(u8, boolToStr(true), "true")); try expect(mem.eql(u8, boolToStr(false), "false")); @@ -1486,7 +1459,6 @@ test "cast compatible optional types" { test "coerce undefined single-item pointer of array to error union of slice" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const a = @as([*]u8, undefined)[0..0]; var b: error{a}![]const u8 = a; @@ -1496,7 +1468,6 @@ test "coerce undefined single-item pointer of array to error union of slice" { test "pointer to empty struct literal to mutable slice" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var x: []i32 = &.{}; try expect(x.len == 0); @@ -1585,7 +1556,6 @@ test "bitcast packed struct with u0" { test "optional pointer coerced to optional allowzero pointer" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var p: ?*u32 = undefined; var q: ?*allowzero u32 = undefined; @@ -1595,8 +1565,6 @@ test "optional pointer coerced to optional allowzero pointer" { } test "single item pointer to pointer to array to slice" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - var x: i32 = 1234; try expect(@as([]const i32, @as(*[1]i32, &x))[0] == 1234); const z1 = @as([]const i32, @as(*[1]i32, &x)); @@ -1632,8 +1600,6 @@ test "@volatileCast without a result location" { } test "coercion from single-item pointer to @as to slice" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - var x: u32 = 1; // Why the following line gets a compile error? @@ -2295,7 +2261,6 @@ test "cast builtins can wrap result in error union" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO const S = struct { const MyEnum = enum(u32) { _ }; diff --git a/test/behavior/cast_int.zig b/test/behavior/cast_int.zig index 09733d00a0..989f3d3aa1 100644 --- a/test/behavior/cast_int.zig +++ b/test/behavior/cast_int.zig @@ -19,7 +19,6 @@ test "coerce i8 to i32 and @intCast back" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var x: i8 = -5; var y: i32 = -5; diff --git a/test/behavior/defer.zig b/test/behavior/defer.zig index dd7ded911d..86a9a40246 100644 --- a/test/behavior/defer.zig +++ b/test/behavior/defer.zig @@ -5,8 +5,6 @@ const expectEqual = std.testing.expectEqual; const expectError = std.testing.expectError; test "break and continue inside loop inside defer expression" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - testBreakContInDefer(10); comptime testBreakContInDefer(10); } diff --git a/test/behavior/empty_union.zig b/test/behavior/empty_union.zig index 16606b5785..53408875ae 100644 --- a/test/behavior/empty_union.zig +++ b/test/behavior/empty_union.zig @@ -9,8 +9,6 @@ test "switch on empty enum" { } test "switch on empty enum with a specified tag type" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - const E = enum(u8) {}; var e: E = undefined; switch (e) {} @@ -18,7 +16,6 @@ test "switch on empty enum with a specified tag type" { test "switch on empty auto numbered tagged union" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const U = union(enum(u8)) {}; var u: U = undefined; diff --git a/test/behavior/enum.zig b/test/behavior/enum.zig index a472dc87a4..6701381085 100644 --- a/test/behavior/enum.zig +++ b/test/behavior/enum.zig @@ -935,7 +935,6 @@ const Bar = enum { A, B, C, D }; test "enum literal casting to error union with payload enum" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var bar: error{B}!Bar = undefined; bar = .B; // should never cast to the error set @@ -947,7 +946,6 @@ test "constant enum initialization with differing sizes" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; try test3_1(test3_foo); try test3_2(test3_bar); @@ -1054,7 +1052,6 @@ test "enum literal casting to optional" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var bar: ?Bar = undefined; bar = .B; @@ -1141,7 +1138,6 @@ test "tag name functions are unique" { test "size of enum with only one tag which has explicit integer tag type" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const E = enum(u8) { nope = 10 }; const S0 = struct { e: E }; diff --git a/test/behavior/error.zig b/test/behavior/error.zig index 038bd94dfa..5a25714d14 100644 --- a/test/behavior/error.zig +++ b/test/behavior/error.zig @@ -822,7 +822,6 @@ test "alignment of wrapping an error union payload" { test "compare error union and error set" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var a: anyerror = error.Foo; var b: anyerror!u32 = error.Bar; diff --git a/test/behavior/eval.zig b/test/behavior/eval.zig index 2812457388..c62ddda1aa 100644 --- a/test/behavior/eval.zig +++ b/test/behavior/eval.zig @@ -5,8 +5,6 @@ const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; test "compile time recursion" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - try expect(some_data.len == 21); } var some_data: [@as(usize, @intCast(fibonacci(7)))]u8 = undefined; @@ -74,7 +72,6 @@ fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 { test "constant expressions" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var array: [array_size]u8 = undefined; try expect(@sizeOf(@TypeOf(array)) == 20); @@ -143,7 +140,6 @@ test "pointer to type" { test "a type constructed in a global expression" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var l: List = undefined; l.array[0] = 10; @@ -202,8 +198,6 @@ test "@setEvalBranchQuota" { } test "constant struct with negation" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - try expect(vertices[0].x == @as(f32, -0.6)); } const Vertex = struct { @@ -308,8 +302,6 @@ fn performFn(comptime prefix_char: u8, start_value: i32) i32 { } test "comptime iterate over fn ptr list" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - try expect(performFn('t', 1) == 6); try expect(performFn('o', 0) == 1); try expect(performFn('w', 99) == 99); @@ -348,7 +340,6 @@ fn doesAlotT(comptime T: type, value: usize) T { test "@setEvalBranchQuota at same scope as generic function call" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; try expect(doesAlotT(u32, 2) == 2); } @@ -385,8 +376,6 @@ test "zero extend from u0 to u1" { } test "return 0 from function that has u0 return type" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - const S = struct { fn foo_zero() u0 { return 0; @@ -417,8 +406,6 @@ var st_init_str_foo = StInitStrFoo{ }; test "inline for with same type but different values" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - var res: usize = 0; inline for ([_]type{ [2]u8, [1]u8, [2]u8 }) |T| { var a: T = undefined; @@ -544,7 +531,6 @@ test "runtime 128 bit integer division" { test "@tagName of @typeInfo" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const str = @tagName(@typeInfo(u8)); try expect(std.mem.eql(u8, str, "Int")); @@ -554,7 +540,6 @@ test "static eval list init" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; try expect(static_vec3.data[2] == 1.0); try expect(vec3(0.0, 0.0, 3.0).data[2] == 3.0); @@ -586,7 +571,6 @@ test "inlined loop has array literal with elided runtime scope on first iteratio test "ptr to local array argument at comptime" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; comptime { var bytes: [10]u8 = undefined; @@ -623,7 +607,6 @@ const hi1 = "hi"; const hi2 = hi1; test "const global shares pointer with other same one" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; try assertEqualPtrs(&hi1[0], &hi2[0]); try comptime expect(&hi1[0] == &hi2[0]); @@ -659,8 +642,6 @@ pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type { } test "comptime function with mutable pointer is not memoized" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - comptime { var x: i32 = 1; const ptr = &x; @@ -753,7 +734,6 @@ test "array concatenation of function calls" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var a = oneItem(3) ++ oneItem(4); try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 4 })); @@ -763,7 +743,6 @@ test "array multiplication of function calls" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var a = oneItem(3) ** scalar(2); try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 3 })); @@ -852,7 +831,6 @@ test "array multiplication sets the sentinel - value" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var a = [2:7]u3{ 1, 6 }; var b = a ** 2; @@ -869,7 +847,6 @@ test "array multiplication sets the sentinel - pointer" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var a = [2:7]u3{ 1, 6 }; var b = &a ** 2; @@ -1004,7 +981,6 @@ test "closure capture type of runtime-known var" { test "comptime break passing through runtime condition converted to runtime break" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -1038,7 +1014,6 @@ test "comptime break to outer loop passing through runtime condition converted t if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -1110,7 +1085,6 @@ test "comptime break operand passing through runtime switch converted to runtime test "no dependency loop for alignment of self struct" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -1148,7 +1122,6 @@ test "no dependency loop for alignment of self struct" { test "no dependency loop for alignment of self bare union" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -1186,7 +1159,6 @@ test "no dependency loop for alignment of self bare union" { test "no dependency loop for alignment of self tagged union" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -1377,7 +1349,6 @@ test "lazy value is resolved as slice operand" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const A = struct { a: u32 }; var a: [512]u64 = undefined; @@ -1435,7 +1406,6 @@ test "inline for inside a runtime condition" { test "continue in inline for inside a comptime switch" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const arr = .{ 1, 2, 3 }; var count: u8 = 0; @@ -1501,7 +1471,6 @@ test "continue nested inline for loop in named block expr" { test "x and false is comptime-known false" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const T = struct { var x: u32 = 0; @@ -1529,7 +1498,6 @@ test "x and false is comptime-known false" { test "x or true is comptime-known true" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const T = struct { var x: u32 = 0; @@ -1559,7 +1527,6 @@ test "non-optional and optional array elements concatenated" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const array = [1]u8{'A'} ++ [1]?u8{null}; var index: usize = 0; @@ -1648,8 +1615,6 @@ test "result of nested switch assigned to variable" { } test "inline for loop of functions returning error unions" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - const T1 = struct { fn v() error{}!usize { return 1; diff --git a/test/behavior/floatop.zig b/test/behavior/floatop.zig index 0e79ba3254..33460b827e 100644 --- a/test/behavior/floatop.zig +++ b/test/behavior/floatop.zig @@ -736,7 +736,6 @@ test "@ceil" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; try comptime testCeil(); try testCeil(); @@ -1053,7 +1052,6 @@ test "negation f128" { test "eval @setFloatMode at compile-time" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const result = comptime fnWithFloatMode(); try expect(result == 1234.0); @@ -1089,7 +1087,6 @@ test "comptime fixed-width float non-zero divided by zero produces signed Inf" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; inline for (.{ f16, f32, f64, f80, f128 }) |F| { const pos = @as(F, 1) / @as(F, 0); diff --git a/test/behavior/fn.zig b/test/behavior/fn.zig index 7ccd9d5351..ed69a8d8e9 100644 --- a/test/behavior/fn.zig +++ b/test/behavior/fn.zig @@ -20,8 +20,6 @@ fn testLocVars(b: i32) void { } test "mutable local variables" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - var zero: i32 = 0; try expect(zero == 0); @@ -53,8 +51,6 @@ test "weird function name" { } test "assign inline fn to const variable" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - const a = inlineFn; a(); } @@ -190,7 +186,6 @@ test "function with complex callconv and return type expressions" { test "pass by non-copying value" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; try expect(addPointCoords(Point{ .x = 1, .y = 2 }) == 3); } @@ -218,7 +213,6 @@ fn addPointCoordsVar(pt: anytype) !i32 { test "pass by non-copying value as method" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var pt = Point2{ .x = 1, .y = 2 }; try expect(pt.addPointCoords() == 3); @@ -235,7 +229,6 @@ const Point2 = struct { test "pass by non-copying value as method, which is generic" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var pt = Point3{ .x = 1, .y = 2 }; try expect(pt.addPointCoords(i32) == 3); @@ -253,7 +246,6 @@ const Point3 = struct { test "pass by non-copying value as method, at comptime" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; comptime { var pt = Point2{ .x = 1, .y = 2 }; @@ -396,8 +388,6 @@ test "function call with anon list literal - 2D" { } test "ability to give comptime types and non comptime types to same parameter" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - const S = struct { fn doTheTest() !void { var x: i32 = 1; @@ -415,8 +405,6 @@ test "ability to give comptime types and non comptime types to same parameter" { } test "function with inferred error set but returning no error" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - const S = struct { fn foo() !void {} }; diff --git a/test/behavior/for.zig b/test/behavior/for.zig index 35f51da218..211fba932b 100644 --- a/test/behavior/for.zig +++ b/test/behavior/for.zig @@ -257,7 +257,6 @@ test "for loop with else branch" { test "count over fixed range" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var sum: usize = 0; for (0..6) |i| { @@ -270,7 +269,6 @@ test "count over fixed range" { test "two counters" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var sum: usize = 0; for (0..10, 10..20) |i, j| { @@ -318,7 +316,6 @@ test "slice and two counters, one is offset and one is runtime" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const slice: []const u8 = "blah"; var start: usize = 0; @@ -406,7 +403,6 @@ test "inline for with slice as the comptime-known" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const comptime_slice = "hello"; var runtime_i: usize = 3; diff --git a/test/behavior/generics.zig b/test/behavior/generics.zig index f2b4ebf309..8ecb069956 100644 --- a/test/behavior/generics.zig +++ b/test/behavior/generics.zig @@ -55,7 +55,6 @@ test "fn with comptime args" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; try expect(gimmeTheBigOne(1234, 5678) == 5678); try expect(shouldCallSameInstance(34, 12) == 34); @@ -66,7 +65,6 @@ test "anytype params" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; try expect(max_i32(12, 34) == 34); try expect(max_f64(1.2, 3.4) == 3.4); @@ -91,7 +89,6 @@ fn max_f64(a: f64, b: f64) f64 { test "type constructed by comptime function call" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var l: SimpleList(10) = undefined; l.array[0] = 10; @@ -115,7 +112,6 @@ test "function with return type type" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var list: List(i32) = undefined; var list2: List(i32) = undefined; @@ -147,8 +143,6 @@ fn GenericDataThing(comptime count: isize) type { } test "use generic param in generic param" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - try expect(aGenericFn(i32, 3, 4) == 7); } fn aGenericFn(comptime T: type, comptime a: T, b: T) T { @@ -178,7 +172,6 @@ test "generic fn keeps non-generic parameter types" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const A = 128; @@ -254,7 +247,6 @@ test "generic function instantiation turns into comptime call" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -305,7 +297,6 @@ test "generic function with void and comptime parameter" { test "anonymous struct return type referencing comptime parameter" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { pub fn extraData(comptime T: type, index: usize) struct { data: T, end: usize } { @@ -406,8 +397,6 @@ test "generic struct as parameter type" { } test "slice as parameter type" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - const S = struct { fn internComptimeString(comptime str: []const u8) *const []const u8 { return &struct { @@ -422,8 +411,6 @@ test "slice as parameter type" { } test "null sentinel pointer passed as generic argument" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - const S = struct { fn doTheTest(a: anytype) !void { try std.testing.expect(@intFromPtr(a) == 8); @@ -434,7 +421,6 @@ test "null sentinel pointer passed as generic argument" { test "generic function passed as comptime argument" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doMath(comptime f: fn (type, i32, i32) error{Overflow}!i32, a: i32, b: i32) !void { diff --git a/test/behavior/inline_switch.zig b/test/behavior/inline_switch.zig index fc2eae31be..43a02df01d 100644 --- a/test/behavior/inline_switch.zig +++ b/test/behavior/inline_switch.zig @@ -47,7 +47,6 @@ test "inline switch unions" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var x: U = .a; switch (x) { @@ -141,8 +140,6 @@ test "inline else int all values" { } test "inline switch capture is set when switch operand is comptime known" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - const U2 = union(enum) { a: u32, }; diff --git a/test/behavior/math.zig b/test/behavior/math.zig index afbe0f911d..9e4ec783e7 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -1145,8 +1145,6 @@ test "overflow arithmetic with u0 values" { } test "allow signed integer division/remainder when values are comptime-known and positive or exact" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - try expect(5 / 3 == 1); try expect(-5 / -3 == 1); try expect(-6 / 3 == -2); diff --git a/test/behavior/maximum_minimum.zig b/test/behavior/maximum_minimum.zig index ed2679aef4..22514128d0 100644 --- a/test/behavior/maximum_minimum.zig +++ b/test/behavior/maximum_minimum.zig @@ -200,7 +200,6 @@ test "@min/@max on comptime_int" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO const min = @min(1, 2, -2, -1); const max = @max(1, 2, -2, -1); @@ -257,7 +256,6 @@ test "@min/@max notices bounds from types when comptime-known value is undef" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var x: u32 = 1_000_000; const y: u16 = undefined; diff --git a/test/behavior/slice.zig b/test/behavior/slice.zig index ce836eb337..9f430a105a 100644 --- a/test/behavior/slice.zig +++ b/test/behavior/slice.zig @@ -754,7 +754,6 @@ test "slice len modification at comptime" { } test "slice field ptr const" { - const const_slice: []const u8 = "string"; const const_ptr_const_slice = &const_slice; diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index ac57f9176b..1ba9e946d1 100644 --- a/test/behavior/struct.zig +++ b/test/behavior/struct.zig @@ -109,7 +109,6 @@ fn testMutation(foo: *StructFoo) void { test "struct byval assign" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var foo1: StructFoo = undefined; var foo2: StructFoo = undefined; @@ -129,8 +128,6 @@ test "call struct static method" { const should_be_11 = StructWithNoFields.add(5, 6); test "invoke static method in global scope" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - try expect(should_be_11 == 11); } @@ -255,7 +252,6 @@ test "usingnamespace within struct scope" { test "struct field init with catch" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -367,8 +363,6 @@ test "self-referencing struct via array member" { } test "empty struct method call" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - const es = EmptyStruct{}; try expect(es.method() == 1234); } @@ -553,7 +547,6 @@ test "implicit cast packed struct field to const ptr" { test "zero-bit field in packed struct" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = packed struct { x: u10, @@ -949,8 +942,6 @@ test "tuple assigned to variable" { } test "comptime struct field" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest; // TODO @@ -988,7 +979,6 @@ test "struct with union field" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const Value = struct { ref: u32 = 2, @@ -1439,8 +1429,6 @@ test "struct field has a pointer to an aligned version of itself" { } test "struct has only one reference" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - const S = struct { fn optionalStructParam(_: ?struct { x: u8 }) void {} fn errorUnionStructParam(_: error{}!struct { x: u8 }) void {} @@ -1510,7 +1498,6 @@ test "discarded struct initialization works as expected" { test "function pointer in struct returns the struct" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const A = struct { const A = @This(); @@ -1560,7 +1547,6 @@ test "optional field init with tuple" { test "if inside struct init inside if" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const MyStruct = struct { x: u32 }; const b: u32 = 5; diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig index 4e6b7ad761..8460798c53 100644 --- a/test/behavior/switch.zig +++ b/test/behavior/switch.zig @@ -232,7 +232,6 @@ test "switch prong with variable" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; try switchProngWithVarFn(SwitchProngWithVarEnum{ .One = 13 }); try switchProngWithVarFn(SwitchProngWithVarEnum{ .Two = 13.0 }); @@ -257,7 +256,6 @@ test "switch on enum using pointer capture" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; try testSwitchEnumPtrCapture(); try comptime testSwitchEnumPtrCapture(); @@ -318,7 +316,6 @@ test "switch on union with some prongs capturing" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const X = union(enum) { a, @@ -355,7 +352,6 @@ test "switch on const enum with var" { test "anon enum literal used in switch on union enum" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const Foo = union(enum) { a: i32, @@ -394,7 +390,6 @@ fn switchWithUnreachable(x: i32) i32 { test "capture value of switch with all unreachable prongs" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const x = return_a_number() catch |err| switch (err) { else => unreachable, @@ -408,7 +403,6 @@ fn return_a_number() anyerror!i32 { test "switch on integer with else capturing expr" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -498,7 +492,6 @@ test "switch prongs with error set cases make a new error set type for capture v test "return result loc and then switch with range implicit casted to error union" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -539,7 +532,6 @@ test "switch prongs with cases with identical payload types" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const Union = union(enum) { A: usize, @@ -706,8 +698,6 @@ test "switch item sizeof" { } test "comptime inline switch" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - const U = union(enum) { a: type, b: type }; const value = comptime blk: { var u: U = .{ .a = u32 }; diff --git a/test/behavior/this.zig b/test/behavior/this.zig index 0bc765c8a7..a68e44df89 100644 --- a/test/behavior/this.zig +++ b/test/behavior/this.zig @@ -27,7 +27,6 @@ test "this refer to module call private fn" { test "this refer to container" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var pt: Point(i32) = undefined; pt.x = 12; diff --git a/test/behavior/try.zig b/test/behavior/try.zig index c7b0396051..49581977f9 100644 --- a/test/behavior/try.zig +++ b/test/behavior/try.zig @@ -24,8 +24,6 @@ fn returnsTen() anyerror!i32 { } test "try without vars" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - const result1 = if (failIfTrue(true)) 1 else |_| @as(i32, 2); try expect(result1 == 2); diff --git a/test/behavior/tuple.zig b/test/behavior/tuple.zig index 32ebfe89fd..57c1c920e7 100644 --- a/test/behavior/tuple.zig +++ b/test/behavior/tuple.zig @@ -289,7 +289,6 @@ test "coerce tuple to tuple" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const T = std.meta.Tuple(&.{u8}); const S = struct { @@ -304,7 +303,6 @@ test "tuple type with void field" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const T = std.meta.Tuple(&[_]type{void}); const x = T{{}}; @@ -343,7 +341,6 @@ test "zero sized struct in tuple handled correctly" { test "tuple type with void field and a runtime field" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const T = std.meta.Tuple(&[_]type{ usize, void }); var t: T = .{ 5, {} }; diff --git a/test/behavior/type_info.zig b/test/behavior/type_info.zig index 421800d6fd..30db77e0ea 100644 --- a/test/behavior/type_info.zig +++ b/test/behavior/type_info.zig @@ -160,7 +160,6 @@ test "type info: error set, error union info, anyerror" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; try testErrorSet(); try comptime testErrorSet(); @@ -192,7 +191,6 @@ test "type info: error set single value" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const TestSet = error.One; @@ -206,7 +204,6 @@ test "type info: error set merged" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const TestSet = error{ One, Two } || error{Three}; @@ -222,7 +219,6 @@ test "type info: enum info" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; try testEnum(); try comptime testEnum(); @@ -533,7 +529,6 @@ test "Struct.is_tuple for anon list literal" { test "Struct.is_tuple for anon struct literal" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const info = @typeInfo(@TypeOf(.{ .a = 0 })); try expect(!info.Struct.is_tuple); diff --git a/test/behavior/undefined.zig b/test/behavior/undefined.zig index 04172acfa1..6ae2807b2d 100644 --- a/test/behavior/undefined.zig +++ b/test/behavior/undefined.zig @@ -48,7 +48,6 @@ test "assign undefined to struct" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; comptime { var foo: Foo = undefined; @@ -66,7 +65,6 @@ test "assign undefined to struct with method" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; comptime { var foo: Foo = undefined; @@ -82,7 +80,6 @@ test "assign undefined to struct with method" { test "type name of undefined" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const x = undefined; try expect(mem.eql(u8, @typeName(@TypeOf(x)), "@TypeOf(undefined)")); diff --git a/test/behavior/underscore.zig b/test/behavior/underscore.zig index bb5dd156bc..66b49e52d5 100644 --- a/test/behavior/underscore.zig +++ b/test/behavior/underscore.zig @@ -8,7 +8,6 @@ test "ignore lval with underscore" { test "ignore lval with underscore (while loop)" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; while (optionalReturnError()) |_| { while (optionalReturnError()) |_| { diff --git a/test/behavior/union.zig b/test/behavior/union.zig index a81da9d69e..47e0b2f345 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -1160,7 +1160,6 @@ test "union with no result loc initiated with a runtime value" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const U = union { a: u32, @@ -1177,7 +1176,6 @@ test "union with a large struct field" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { a: [8]usize, @@ -1329,7 +1327,6 @@ test "@unionInit uses tag value instead of field index" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const E = enum(u8) { b = 255, diff --git a/test/behavior/vector.zig b/test/behavior/vector.zig index 0b95caa0d3..0ad326d36e 100644 --- a/test/behavior/vector.zig +++ b/test/behavior/vector.zig @@ -240,7 +240,6 @@ test "peer type resolution with coercible element types" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -1469,7 +1468,6 @@ test "boolean vector with 2 or more booleans" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO // TODO: try removing this after : if (!(builtin.os.tag == .linux and builtin.cpu.arch == .x86_64)) return; diff --git a/test/behavior/while.zig b/test/behavior/while.zig index e52b394746..bc051aca32 100644 --- a/test/behavior/while.zig +++ b/test/behavior/while.zig @@ -50,8 +50,6 @@ test "while with continue expression" { } test "while with else" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - var sum: i32 = 0; var i: i32 = 0; var got_else: i32 = 0; @@ -79,8 +77,6 @@ fn getNumberOrNull() ?i32 { } test "continue outer while loop" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - testContinueOuter(); comptime testContinueOuter(); } @@ -127,7 +123,6 @@ test "while copies its payload" { test "continue and break" { if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; try runContinueAndBreakTest(); try expect(continue_and_break_counter == 8); @@ -149,7 +144,6 @@ fn runContinueAndBreakTest() !void { test "while with optional as condition" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; numbers_left = 10; var sum: i32 = 0; @@ -162,7 +156,6 @@ test "while with optional as condition" { test "while with optional as condition with else" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; numbers_left = 10; var sum: i32 = 0; @@ -223,7 +216,6 @@ test "while on optional with else result follow break prong" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const result = while (returnOptional(10)) |value| { break value; @@ -251,8 +243,6 @@ fn returnTrue() bool { } test "return with implicit cast from while loop" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - returnWithImplicitCastFromWhileLoopTest() catch unreachable; } fn returnWithImplicitCastFromWhileLoopTest() anyerror!void { @@ -263,7 +253,6 @@ fn returnWithImplicitCastFromWhileLoopTest() anyerror!void { test "while on error union with else result follow else prong" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const result = while (returnError()) |value| { break value; @@ -273,7 +262,6 @@ test "while on error union with else result follow else prong" { test "while on error union with else result follow break prong" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const result = while (returnSuccess(10)) |value| { break value; @@ -319,7 +307,6 @@ test "while error 2 break statements and an else" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const S = struct { fn entry(opt_t: anyerror!bool, f: bool) !void { @@ -345,8 +332,6 @@ test "continue inline while loop" { } test "else continue outer while" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; - var i: usize = 0; while (true) { i += 1; -- cgit v1.2.3 From 63512192deeb2ba42e51a4dc7e1ba24eefcee7db Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Thu, 21 Sep 2023 20:26:52 +0200 Subject: spirv: fix source line numbers --- src/codegen/spirv.zig | 64 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 21 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 45c081c51d..b4f4df39b7 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -107,6 +107,10 @@ pub const DeclGen = struct { /// The code (prologue and body) for the function we are currently generating code for. func: SpvModule.Fn = .{}, + /// Stack of the base offsets of the current decl, which is what `dbg_stmt` is relative to. + /// This is a stack to keep track of inline functions. + base_line_stack: std.ArrayListUnmanaged(u32) = .{}, + /// If `gen` returned `Error.CodegenFail`, this contains an explanatory message. /// Memory is owned by `module.gpa`. error_msg: ?*Module.ErrorMsg, @@ -205,6 +209,7 @@ pub const DeclGen = struct { self.blocks.clearRetainingCapacity(); self.current_block_label_id = undefined; self.func.reset(); + self.base_line_stack.items.len = 0; self.error_msg = null; self.genDecl() catch |err| switch (err) { @@ -229,6 +234,7 @@ pub const DeclGen = struct { self.type_map.deinit(self.gpa); self.blocks.deinit(self.gpa); self.func.deinit(self.gpa); + self.base_line_stack.deinit(self.gpa); } /// Return the target which we are currently compiling for. @@ -1422,6 +1428,8 @@ pub const DeclGen = struct { const decl_id = self.spv.declPtr(spv_decl_index).result_id; + try self.base_line_stack.append(self.gpa, decl.src_line); + if (decl.val.getFunction(mod)) |_| { assert(decl.ty.zigTypeTag(mod) == .Fn); const prototype_id = try self.resolveTypeId(decl.ty); @@ -1739,7 +1747,6 @@ pub const DeclGen = struct { .br => return self.airBr(inst), .breakpoint => return, .cond_br => return self.airCondBr(inst), - .dbg_stmt => return self.airDbgStmt(inst), .loop => return self.airLoop(inst), .ret => return self.airRet(inst), .ret_load => return self.airRetLoad(inst), @@ -1747,6 +1754,14 @@ pub const DeclGen = struct { .switch_br => return self.airSwitchBr(inst), .unreach, .trap => return self.airUnreach(), + .dbg_stmt => return self.airDbgStmt(inst), + .dbg_inline_begin => return self.airDbgInlineBegin(inst), + .dbg_inline_end => return self.airDbgInlineEnd(inst), + .dbg_var_ptr => return, + .dbg_var_val => return, + .dbg_block_begin => return, + .dbg_block_end => return, + .unwrap_errunion_err => try self.airErrUnionErr(inst), .unwrap_errunion_payload => try self.airErrUnionPayload(inst), .wrap_errunion_err => try self.airWrapErrUnionErr(inst), @@ -1766,13 +1781,6 @@ pub const DeclGen = struct { .call_always_tail => try self.airCall(inst, .always_tail), .call_never_tail => try self.airCall(inst, .never_tail), .call_never_inline => try self.airCall(inst, .never_inline), - - .dbg_inline_begin => return, - .dbg_inline_end => return, - .dbg_var_ptr => return, - .dbg_var_val => return, - .dbg_block_begin => return, - .dbg_block_end => return, // zig fmt: on else => |tag| return self.todo("implement AIR tag {s}", .{@tagName(tag)}), @@ -3053,19 +3061,6 @@ pub const DeclGen = struct { try self.genBody(else_body); } - fn airDbgStmt(self: *DeclGen, inst: Air.Inst.Index) !void { - const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt; - const src_fname_id = try self.spv.resolveSourceFileName( - self.module, - self.module.declPtr(self.decl_index), - ); - try self.func.body.emit(self.spv.gpa, .OpLine, .{ - .file = src_fname_id, - .line = dbg_stmt.line, - .column = dbg_stmt.column, - }); - } - fn airLoad(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { const mod = self.module; const ty_op = self.air.instructions.items(.data)[inst].ty_op; @@ -3535,6 +3530,33 @@ pub const DeclGen = struct { try self.func.body.emit(self.spv.gpa, .OpUnreachable, {}); } + fn airDbgStmt(self: *DeclGen, inst: Air.Inst.Index) !void { + const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt; + const src_fname_id = try self.spv.resolveSourceFileName( + self.module, + self.module.declPtr(self.decl_index), + ); + const base_line = self.base_line_stack.getLast(); + try self.func.body.emit(self.spv.gpa, .OpLine, .{ + .file = src_fname_id, + .line = base_line + dbg_stmt.line + 1, + .column = dbg_stmt.column + 1, + }); + } + + fn airDbgInlineBegin(self: *DeclGen, inst: Air.Inst.Index) !void { + const mod = self.module; + const fn_ty = self.air.instructions.items(.data)[inst].ty_fn; + const decl_index = mod.funcInfo(fn_ty.func).owner_decl; + const decl = mod.declPtr(decl_index); + try self.base_line_stack.append(self.gpa, decl.src_line); + } + + fn airDbgInlineEnd(self: *DeclGen, inst: Air.Inst.Index) !void { + _ = inst; + _ = self.base_line_stack.pop(); + } + fn airAssembly(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { const mod = self.module; const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; -- cgit v1.2.3 From 68c7fc5c595b4a48f95b3f2f8c4d0a6c3a388667 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Thu, 21 Sep 2023 22:50:13 +0200 Subject: spirv: fix blocks that return no value --- src/codegen/spirv.zig | 77 ++++++++++++++++++++++++++-------------------- test/behavior/pointers.zig | 1 - 2 files changed, 43 insertions(+), 35 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index b4f4df39b7..b7d749e141 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -45,10 +45,12 @@ const IncomingBlock = struct { break_value_id: IdRef, }; -const BlockMap = std.AutoHashMapUnmanaged(Air.Inst.Index, struct { - label_id: IdRef, - incoming_blocks: *std.ArrayListUnmanaged(IncomingBlock), -}); +const Block = struct { + label_id: ?IdRef, + incoming_blocks: std.ArrayListUnmanaged(IncomingBlock), +}; + +const BlockMap = std.AutoHashMapUnmanaged(Air.Inst.Index, *Block); /// Maps Zig decl indices to linking SPIR-V linking information. pub const DeclLinkMap = std.AutoHashMap(Module.Decl.Index, SpvModule.Decl.Index); @@ -2970,50 +2972,50 @@ pub const DeclGen = struct { } fn airBlock(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { - // In AIR, a block doesn't really define an entry point like a block, but more like a scope that breaks can jump out of and - // "return" a value from. This cannot be directly modelled in SPIR-V, so in a block instruction, we're going to split up - // the current block by first generating the code of the block, then a label, and then generate the rest of the current + // In AIR, a block doesn't really define an entry point like a block, but + // more like a scope that breaks can jump out of and "return" a value from. + // This cannot be directly modelled in SPIR-V, so in a block instruction, + // we're going to split up the current block by first generating the code + // of the block, then a label, and then generate the rest of the current // ir.Block in a different SPIR-V block. const mod = self.module; - const label_id = self.spv.allocId(); - - // 4 chosen as arbitrary initial capacity. - var incoming_blocks = try std.ArrayListUnmanaged(IncomingBlock).initCapacity(self.gpa, 4); - - try self.blocks.putNoClobber(self.gpa, inst, .{ - .label_id = label_id, - .incoming_blocks = &incoming_blocks, - }); - defer { - assert(self.blocks.remove(inst)); - incoming_blocks.deinit(self.gpa); - } - const ty = self.typeOfIndex(inst); const inst_datas = self.air.instructions.items(.data); const extra = self.air.extraData(Air.Block, inst_datas[inst].ty_pl.payload); const body = self.air.extra[extra.end..][0..extra.data.body_len]; + const have_block_result = ty.isFnOrHasRuntimeBitsIgnoreComptime(mod); + + // 4 chosen as arbitrary initial capacity. + var block = Block{ + // Label id is lazily allocated if needed. + .label_id = null, + .incoming_blocks = try std.ArrayListUnmanaged(IncomingBlock).initCapacity(self.gpa, 4), + }; + defer block.incoming_blocks.deinit(self.gpa); + + try self.blocks.putNoClobber(self.gpa, inst, &block); + defer assert(self.blocks.remove(inst)); try self.genBody(body); - try self.beginSpvBlock(label_id); - // If this block didn't produce a value, simply return here. - if (!ty.hasRuntimeBitsIgnoreComptime(mod)) + // Only begin a new block if there were actually any breaks towards it. + if (block.label_id) |label_id| { + try self.beginSpvBlock(label_id); + } + + if (!have_block_result) return null; - // Combine the result from the blocks using the Phi instruction. + assert(block.label_id != null); const result_id = self.spv.allocId(); - - // TODO: OpPhi is limited in the types that it may produce, such as pointers. Figure out which other types - // are not allowed to be created from a phi node, and throw an error for those. const result_type_id = try self.resolveTypeId(ty); - try self.func.body.emitRaw(self.spv.gpa, .OpPhi, 2 + @as(u16, @intCast(incoming_blocks.items.len * 2))); // result type + result + variable/parent... + try self.func.body.emitRaw(self.spv.gpa, .OpPhi, 2 + @as(u16, @intCast(block.incoming_blocks.items.len * 2))); // result type + result + variable/parent... self.func.body.writeOperand(spec.IdResultType, result_type_id); self.func.body.writeOperand(spec.IdRef, result_id); - for (incoming_blocks.items) |incoming| { + for (block.incoming_blocks.items) |incoming| { self.func.body.writeOperand(spec.PairIdRefIdRef, .{ incoming.break_value_id, incoming.src_label_id }); } @@ -3022,17 +3024,24 @@ pub const DeclGen = struct { fn airBr(self: *DeclGen, inst: Air.Inst.Index) !void { const br = self.air.instructions.items(.data)[inst].br; - const block = self.blocks.get(br.block_inst).?; const operand_ty = self.typeOf(br.operand); + const block = self.blocks.get(br.block_inst).?; const mod = self.module; - if (operand_ty.hasRuntimeBits(mod)) { + if (operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) { const operand_id = try self.resolve(br.operand); // current_block_label_id should not be undefined here, lest there is a br or br_void in the function's body. - try block.incoming_blocks.append(self.gpa, .{ .src_label_id = self.current_block_label_id, .break_value_id = operand_id }); + try block.incoming_blocks.append(self.gpa, .{ + .src_label_id = self.current_block_label_id, + .break_value_id = operand_id, + }); + } + + if (block.label_id == null) { + block.label_id = self.spv.allocId(); } - try self.func.body.emit(self.spv.gpa, .OpBranch, .{ .target_label = block.label_id }); + try self.func.body.emit(self.spv.gpa, .OpBranch, .{ .target_label = block.label_id.? }); } fn airCondBr(self: *DeclGen, inst: Air.Inst.Index) !void { diff --git a/test/behavior/pointers.zig b/test/behavior/pointers.zig index 2a878e89c9..3122ae23d5 100644 --- a/test/behavior/pointers.zig +++ b/test/behavior/pointers.zig @@ -125,7 +125,6 @@ fn testDerefPtrOneVal() !void { } test "peer type resolution with C pointers" { - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; var ptr_one: *u8 = undefined; var ptr_many: [*]u8 = undefined; var ptr_c: [*c]u8 = undefined; -- cgit v1.2.3 From 572517376a7695693c59a0ec4ec6cc5442003e3a Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Thu, 21 Sep 2023 23:02:53 +0200 Subject: spirv: air dbg_var_val and dbg_var_ptr --- src/codegen/spirv.zig | 34 ++++++++++++++-------------------- src/codegen/spirv/Cache.zig | 12 ++++++------ src/codegen/spirv/Module.zig | 10 ++++++---- 3 files changed, 26 insertions(+), 30 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index b7d749e141..97574961bc 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -1474,10 +1474,7 @@ pub const DeclGen = struct { try self.spv.addFunction(spv_decl_index, self.func); const fqn = ip.stringToSlice(try decl.getFullyQualifiedName(self.module)); - try self.spv.sections.debug_names.emit(self.gpa, .OpName, .{ - .target = decl_id, - .name = fqn, - }); + try self.spv.debugName(decl_id, fqn); // Temporarily generate a test kernel declaration if this is a test function. if (self.module.test_functions.contains(self.decl_index)) { @@ -1548,17 +1545,8 @@ pub const DeclGen = struct { try self.spv.addFunction(spv_decl_index, self.func); const fqn = ip.stringToSlice(try decl.getFullyQualifiedName(self.module)); - try self.spv.sections.debug_names.emit(self.gpa, .OpName, .{ - .target = decl_id, - .name = fqn, - }); - - const init_name = try std.fmt.allocPrint(self.gpa, "initializer of {s}", .{fqn}); - defer self.gpa.free(init_name); - try self.spv.sections.debug_names.emit(self.gpa, .OpName, .{ - .target = initializer_id, - .name = init_name, - }); + try self.spv.debugName(decl_id, fqn); + try self.spv.debugNameFmt(initializer_id, "initializer of {s}", .{fqn}); } } @@ -1756,11 +1744,10 @@ pub const DeclGen = struct { .switch_br => return self.airSwitchBr(inst), .unreach, .trap => return self.airUnreach(), - .dbg_stmt => return self.airDbgStmt(inst), - .dbg_inline_begin => return self.airDbgInlineBegin(inst), - .dbg_inline_end => return self.airDbgInlineEnd(inst), - .dbg_var_ptr => return, - .dbg_var_val => return, + .dbg_stmt => return self.airDbgStmt(inst), + .dbg_inline_begin => return self.airDbgInlineBegin(inst), + .dbg_inline_end => return self.airDbgInlineEnd(inst), + .dbg_var_ptr, .dbg_var_val => return self.airDbgVar(inst), .dbg_block_begin => return, .dbg_block_end => return, @@ -3566,6 +3553,13 @@ pub const DeclGen = struct { _ = self.base_line_stack.pop(); } + fn airDbgVar(self: *DeclGen, inst: Air.Inst.Index) !void { + const pl_op = self.air.instructions.items(.data)[inst].pl_op; + const target_id = try self.resolve(pl_op.operand); + const name = self.air.nullTerminatedString(pl_op.payload); + try self.spv.debugName(target_id, name); + } + fn airAssembly(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { const mod = self.module; const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; diff --git a/src/codegen/spirv/Cache.zig b/src/codegen/spirv/Cache.zig index 7a3b6f61f5..68fea5c47a 100644 --- a/src/codegen/spirv/Cache.zig +++ b/src/codegen/spirv/Cache.zig @@ -462,11 +462,11 @@ fn emit( switch (key) { .void_type => { try section.emit(spv.gpa, .OpTypeVoid, .{ .id_result = result_id }); - try spv.debugName(result_id, "void", .{}); + try spv.debugName(result_id, "void"); }, .bool_type => { try section.emit(spv.gpa, .OpTypeBool, .{ .id_result = result_id }); - try spv.debugName(result_id, "bool", .{}); + try spv.debugName(result_id, "bool"); }, .int_type => |int| { try section.emit(spv.gpa, .OpTypeInt, .{ @@ -481,14 +481,14 @@ fn emit( .unsigned => "u", .signed => "i", }; - try spv.debugName(result_id, "{s}{}", .{ ui, int.bits }); + try spv.debugNameFmt(result_id, "{s}{}", .{ ui, int.bits }); }, .float_type => |float| { try section.emit(spv.gpa, .OpTypeFloat, .{ .id_result = result_id, .width = float.bits, }); - try spv.debugName(result_id, "f{}", .{float.bits}); + try spv.debugNameFmt(result_id, "f{}", .{float.bits}); }, .vector_type => |vector| { try section.emit(spv.gpa, .OpTypeVector, .{ @@ -530,11 +530,11 @@ fn emit( section.writeOperand(IdResult, self.resultId(member_type)); } if (self.getString(struct_type.name)) |name| { - try spv.debugName(result_id, "{s}", .{name}); + try spv.debugName(result_id, name); } for (struct_type.memberNames(), 0..) |member_name, i| { if (self.getString(member_name)) |name| { - try spv.memberDebugName(result_id, @as(u32, @intCast(i)), "{s}", .{name}); + try spv.memberDebugName(result_id, @as(u32, @intCast(i)), name); } } // TODO: Decorations? diff --git a/src/codegen/spirv/Module.zig b/src/codegen/spirv/Module.zig index b6ed381360..81b97ebae5 100644 --- a/src/codegen/spirv/Module.zig +++ b/src/codegen/spirv/Module.zig @@ -645,18 +645,20 @@ pub fn declareEntryPoint(self: *Module, decl_index: Decl.Index, name: []const u8 }); } -pub fn debugName(self: *Module, target: IdResult, comptime fmt: []const u8, args: anytype) !void { - const name = try std.fmt.allocPrint(self.gpa, fmt, args); - defer self.gpa.free(name); +pub fn debugName(self: *Module, target: IdResult, name: []const u8) !void { try self.sections.debug_names.emit(self.gpa, .OpName, .{ .target = target, .name = name, }); } -pub fn memberDebugName(self: *Module, target: IdResult, member: u32, comptime fmt: []const u8, args: anytype) !void { +pub fn debugNameFmt(self: *Module, target: IdResult, comptime fmt: []const u8, args: anytype) !void { const name = try std.fmt.allocPrint(self.gpa, fmt, args); defer self.gpa.free(name); + try self.debugName(target, name); +} + +pub fn memberDebugName(self: *Module, target: IdResult, member: u32, name: []const u8) !void { try self.sections.debug_names.emit(self.gpa, .OpMemberName, .{ .type = target, .member = member, -- cgit v1.2.3 From cff8ab88f5ffe24771aa9c6e839eef03bc22f3d2 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Fri, 22 Sep 2023 19:22:44 +0200 Subject: spirv: fixes --- src/codegen/spirv.zig | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'src/codegen/spirv.zig') diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 97574961bc..016604e1f6 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -771,21 +771,25 @@ pub const DeclGen = struct { return try self.constructArray(result_ty_ref, constituents); }, .struct_type => { - const struct_ty = mod.typeToStruct(ty).?; - if (struct_ty.layout == .Packed) { + const struct_type = mod.typeToStruct(ty).?; + if (struct_type.layout == .Packed) { return self.todo("packed struct constants", .{}); } var constituents = std.ArrayList(IdRef).init(self.gpa); defer constituents.deinit(); - var field_it = struct_ty.runtimeFieldIterator(mod); - while (field_it.next()) |field_and_index| { - const field = field_and_index.field; - const index = field_and_index.index; + var it = struct_type.iterateRuntimeOrder(ip); + while (it.next()) |field_index| { + const field_ty = struct_type.field_types.get(ip)[field_index].toType(); + if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) { + // This is a zero-bit field - we only needed it for the alignment. + continue; + } + // TODO: Padding? - const field_val = try val.fieldValue(mod, index); - const field_id = try self.constant(field.ty, field_val, .indirect); + const field_val = try val.fieldValue(mod, field_index); + const field_id = try self.constant(field_ty, field_val, .indirect); try constituents.append(field_id); } -- cgit v1.2.3