| ... | @@ -19,6 +19,7 @@ const Word = spec.Word; | ... | @@ -19,6 +19,7 @@ const Word = spec.Word; |
| 19 | const IdRef = spec.IdRef; | 19 | const IdRef = spec.IdRef; |
| 20 | const IdResult = spec.IdResult; | 20 | const IdResult = spec.IdResult; |
| 21 | const IdResultType = spec.IdResultType; | 21 | const IdResultType = spec.IdResultType; |
| | 22 | const StorageClass = spec.StorageClass; |
| 22 | | 23 | |
| 23 | const SpvModule = @import("spirv/Module.zig"); | 24 | const SpvModule = @import("spirv/Module.zig"); |
| 24 | const SpvSection = @import("spirv/Section.zig"); | 25 | const SpvSection = @import("spirv/Section.zig"); |
| ... | @@ -37,23 +38,8 @@ const BlockMap = std.AutoHashMapUnmanaged(Air.Inst.Index, struct { | ... | @@ -37,23 +38,8 @@ const BlockMap = std.AutoHashMapUnmanaged(Air.Inst.Index, struct { |
| 37 | incoming_blocks: *std.ArrayListUnmanaged(IncomingBlock), | 38 | incoming_blocks: *std.ArrayListUnmanaged(IncomingBlock), |
| 38 | }); | 39 | }); |
| 39 | | 40 | |
| 40 | /// Linking information about a particular decl. | | |
| 41 | /// The active field of this enum depends on the type of the corresponding decl. | | |
| 42 | const DeclLink = union { | | |
| 43 | /// Linking information about a function. | | |
| 44 | /// Active when the decl is a function. | | |
| 45 | func: struct { | | |
| 46 | /// Result-id of the OpFunction instruction. | | |
| 47 | result_id: IdResult, | | |
| 48 | }, | | |
| 49 | /// Linking information about a global. This index points into the | | |
| 50 | /// SPIR-V module's `globals` array. | | |
| 51 | /// Active when the decl is a variable. | | |
| 52 | global: SpvModule.Global.Index, | | |
| 53 | }; | | |
| 54 | | | |
| 55 | /// Maps Zig decl indices to linking SPIR-V linking information. | 41 | /// Maps Zig decl indices to linking SPIR-V linking information. |
| 56 | pub const DeclLinkMap = std.AutoHashMap(Module.Decl.Index, DeclLink); | 42 | pub const DeclLinkMap = std.AutoHashMap(Module.Decl.Index, SpvModule.Decl.Index); |
| 57 | | 43 | |
| 58 | /// This structure is used to compile a declaration, and contains all relevant meta-information to deal with that. | 44 | /// This structure is used to compile a declaration, and contains all relevant meta-information to deal with that. |
| 59 | pub const DeclGen = struct { | 45 | pub const DeclGen = struct { |
| ... | @@ -251,8 +237,8 @@ pub const DeclGen = struct { | ... | @@ -251,8 +237,8 @@ pub const DeclGen = struct { |
| 251 | .function => val.castTag(.function).?.data.owner_decl, | 237 | .function => val.castTag(.function).?.data.owner_decl, |
| 252 | else => unreachable, | 238 | else => unreachable, |
| 253 | }; | 239 | }; |
| 254 | const link = try self.resolveDecl(fn_decl_index); | 240 | const spv_decl_index = try self.resolveDecl(fn_decl_index); |
| 255 | return link.func.result_id; | 241 | return self.spv.declPtr(spv_decl_index).result_id; |
| 256 | } | 242 | } |
| 257 | | 243 | |
| 258 | return try self.constant(ty, val); | 244 | return try self.constant(ty, val); |
| ... | @@ -263,19 +249,19 @@ pub const DeclGen = struct { | ... | @@ -263,19 +249,19 @@ pub const DeclGen = struct { |
| 263 | | 249 | |
| 264 | /// Fetch or allocate a result id for decl index. This function also marks the decl as alive. | 250 | /// Fetch or allocate a result id for decl index. This function also marks the decl as alive. |
| 265 | /// Note: Function does not actually generate the decl. | 251 | /// Note: Function does not actually generate the decl. |
| 266 | fn resolveDecl(self: *DeclGen, decl_index: Module.Decl.Index) !DeclLink { | 252 | fn resolveDecl(self: *DeclGen, decl_index: Module.Decl.Index) !SpvModule.Decl.Index { |
| 267 | const decl = self.module.declPtr(decl_index); | 253 | const decl = self.module.declPtr(decl_index); |
| 268 | self.module.markDeclAlive(decl); | 254 | self.module.markDeclAlive(decl); |
| 269 | | 255 | |
| 270 | const entry = try self.decl_link.getOrPut(decl_index); | 256 | const entry = try self.decl_link.getOrPut(decl_index); |
| 271 | const result_id = self.spv.allocId(); | | |
| 272 | | | |
| 273 | if (!entry.found_existing) { | 257 | if (!entry.found_existing) { |
| 274 | if (decl.val.castTag(.function)) |_| { | 258 | // TODO: Extern fn? |
| 275 | entry.value_ptr.* = .{ .func = .{ .result_id = result_id } }; | 259 | const kind: SpvModule.DeclKind = if (decl.val.tag() == .function) |
| 276 | } else { | 260 | .func |
| 277 | entry.value_ptr.* = .{ .global = try self.spv.allocGlobal() }; | 261 | else |
| 278 | } | 262 | .global; |
| | 263 | |
| | 264 | entry.value_ptr.* = try self.spv.allocDecl(kind); |
| 279 | } | 265 | } |
| 280 | | 266 | |
| 281 | return entry.value_ptr.*; | 267 | return entry.value_ptr.*; |
| ... | @@ -440,6 +426,8 @@ pub const DeclGen = struct { | ... | @@ -440,6 +426,8 @@ pub const DeclGen = struct { |
| 440 | /// The partially filled last constant. | 426 | /// The partially filled last constant. |
| 441 | /// If full, its flushed. | 427 | /// If full, its flushed. |
| 442 | partial_word: std.BoundedArray(u8, @sizeOf(Word)) = .{}, | 428 | partial_word: std.BoundedArray(u8, @sizeOf(Word)) = .{}, |
| | 429 | /// The declaration dependencies of the constant we are lowering. |
| | 430 | decl_deps: std.ArrayList(SpvModule.Decl.Index), |
| 443 | | 431 | |
| 444 | /// Utility function to get the section that instructions should be lowered to. | 432 | /// Utility function to get the section that instructions should be lowered to. |
| 445 | fn section(self: *@This()) *SpvSection { | 433 | fn section(self: *@This()) *SpvSection { |
| ... | @@ -554,7 +542,7 @@ pub const DeclGen = struct { | ... | @@ -554,7 +542,7 @@ pub const DeclGen = struct { |
| 554 | const ty_id = dg.typeId(ty_ref); | 542 | const ty_id = dg.typeId(ty_ref); |
| 555 | | 543 | |
| 556 | const decl = dg.module.declPtr(decl_index); | 544 | const decl = dg.module.declPtr(decl_index); |
| 557 | const link = try dg.resolveDecl(decl_index); | 545 | const spv_decl_index = try dg.resolveDecl(decl_index); |
| 558 | | 546 | |
| 559 | switch (decl.val.tag()) { | 547 | switch (decl.val.tag()) { |
| 560 | .function => { | 548 | .function => { |
| ... | @@ -569,14 +557,15 @@ pub const DeclGen = struct { | ... | @@ -569,14 +557,15 @@ pub const DeclGen = struct { |
| 569 | const result_id = dg.spv.allocId(); | 557 | const result_id = dg.spv.allocId(); |
| 570 | log.debug("addDeclRef {s} = {}", .{ decl.name, result_id.id }); | 558 | log.debug("addDeclRef {s} = {}", .{ decl.name, result_id.id }); |
| 571 | | 559 | |
| 572 | const global = dg.spv.globalPtr(link.global); | 560 | try self.decl_deps.append(spv_decl_index); |
| 573 | try dg.spv.addGlobalDependency(link.global); | 561 | |
| | 562 | const decl_id = dg.spv.declPtr(spv_decl_index).result_id; |
| 574 | // TODO: Do we need a storage class cast here? | 563 | // TODO: Do we need a storage class cast here? |
| 575 | // TODO: We can probably eliminate these casts | 564 | // TODO: We can probably eliminate these casts |
| 576 | try dg.spv.globals.section.emitSpecConstantOp(dg.spv.gpa, .OpBitcast, .{ | 565 | try dg.spv.globals.section.emitSpecConstantOp(dg.spv.gpa, .OpBitcast, .{ |
| 577 | .id_result_type = ty_id, | 566 | .id_result_type = ty_id, |
| 578 | .id_result = result_id, | 567 | .id_result = result_id, |
| 579 | .operand = global.result_id, | 568 | .operand = decl_id, |
| 580 | }); | 569 | }); |
| 581 | | 570 | |
| 582 | try self.addPtr(ty_ref, result_id); | 571 | try self.addPtr(ty_ref, result_id); |
| ... | @@ -810,10 +799,11 @@ pub const DeclGen = struct { | ... | @@ -810,10 +799,11 @@ pub const DeclGen = struct { |
| 810 | /// pointer points to. Note: result is not necessarily an OpVariable instruction! | 799 | /// pointer points to. Note: result is not necessarily an OpVariable instruction! |
| 811 | fn lowerIndirectConstant( | 800 | fn lowerIndirectConstant( |
| 812 | self: *DeclGen, | 801 | self: *DeclGen, |
| 813 | result_id: IdRef, | 802 | spv_decl_index: SpvModule.Decl.Index, |
| 814 | ty: Type, | 803 | ty: Type, |
| 815 | val: Value, | 804 | val: Value, |
| 816 | storage_class: spec.StorageClass, | 805 | storage_class: StorageClass, |
| | 806 | cast_to_generic: bool, |
| 817 | alignment: u32, | 807 | alignment: u32, |
| 818 | ) Error!void { | 808 | ) Error!void { |
| 819 | // To simplify constant generation, we're going to generate constants as a word-array, and | 809 | // To simplify constant generation, we're going to generate constants as a word-array, and |
| ... | @@ -844,23 +834,27 @@ pub const DeclGen = struct { | ... | @@ -844,23 +834,27 @@ pub const DeclGen = struct { |
| 844 | const ty_ref = try self.resolveType(ty, .indirect); | 834 | const ty_ref = try self.resolveType(ty, .indirect); |
| 845 | const ptr_ty_ref = try self.spv.ptrType(ty_ref, storage_class, alignment); | 835 | const ptr_ty_ref = try self.spv.ptrType(ty_ref, storage_class, alignment); |
| 846 | | 836 | |
| 847 | const target = self.getTarget(); | 837 | // const target = self.getTarget(); |
| 848 | | 838 | |
| 849 | if (val.isUndef()) { | 839 | // TODO: Fix the resulting global linking for these paths. |
| 850 | // Special case: the entire value is undefined. In this case, we can just | 840 | // if (val.isUndef()) { |
| 851 | // generate an OpVariable with no initializer. | 841 | // // Special case: the entire value is undefined. In this case, we can just |
| 852 | return try section.emit(self.spv.gpa, .OpVariable, .{ | 842 | // // generate an OpVariable with no initializer. |
| 853 | .id_result_type = self.typeId(ptr_ty_ref), | 843 | // return try section.emit(self.spv.gpa, .OpVariable, .{ |
| 854 | .id_result = result_id, | 844 | // .id_result_type = self.typeId(ptr_ty_ref), |
| 855 | .storage_class = storage_class, | 845 | // .id_result = result_id, |
| 856 | }); | 846 | // .storage_class = storage_class, |
| 857 | } else if (ty.abiSize(target) == 0) { | 847 | // }); |
| 858 | // Special case: if the type has no size, then return an undefined pointer. | 848 | // } else if (ty.abiSize(target) == 0) { |
| 859 | return try section.emit(self.spv.gpa, .OpUndef, .{ | 849 | // // Special case: if the type has no size, then return an undefined pointer. |
| 860 | .id_result_type = self.typeId(ptr_ty_ref), | 850 | // return try section.emit(self.spv.gpa, .OpUndef, .{ |
| 861 | .id_result = result_id, | 851 | // .id_result_type = self.typeId(ptr_ty_ref), |
| 862 | }); | 852 | // .id_result = result_id, |
| 863 | } | 853 | // }); |
| | 854 | // } |
| | 855 | |
| | 856 | // TODO: Capture the above stuff in here as well... |
| | 857 | const begin_inst = self.spv.beginGlobal(); |
| 864 | | 858 | |
| 865 | const u32_ty_ref = try self.intType(.unsigned, 32); | 859 | const u32_ty_ref = try self.intType(.unsigned, 32); |
| 866 | var icl = IndirectConstantLowering{ | 860 | var icl = IndirectConstantLowering{ |
| ... | @@ -869,10 +863,12 @@ pub const DeclGen = struct { | ... | @@ -869,10 +863,12 @@ pub const DeclGen = struct { |
| 869 | .u32_ty_id = self.typeId(u32_ty_ref), | 863 | .u32_ty_id = self.typeId(u32_ty_ref), |
| 870 | .members = std.ArrayList(SpvType.Payload.Struct.Member).init(self.gpa), | 864 | .members = std.ArrayList(SpvType.Payload.Struct.Member).init(self.gpa), |
| 871 | .initializers = std.ArrayList(IdRef).init(self.gpa), | 865 | .initializers = std.ArrayList(IdRef).init(self.gpa), |
| | 866 | .decl_deps = std.ArrayList(SpvModule.Decl.Index).init(self.gpa), |
| 872 | }; | 867 | }; |
| 873 | | 868 | |
| 874 | defer icl.members.deinit(); | 869 | defer icl.members.deinit(); |
| 875 | defer icl.initializers.deinit(); | 870 | defer icl.initializers.deinit(); |
| | 871 | defer icl.decl_deps.deinit(); |
| 876 | | 872 | |
| 877 | try icl.lower(ty, val); | 873 | try icl.lower(ty, val); |
| 878 | try icl.flush(); | 874 | try icl.flush(); |
| ... | @@ -888,6 +884,7 @@ pub const DeclGen = struct { | ... | @@ -888,6 +884,7 @@ pub const DeclGen = struct { |
| 888 | }); | 884 | }); |
| 889 | | 885 | |
| 890 | const var_id = self.spv.allocId(); | 886 | const var_id = self.spv.allocId(); |
| | 887 | self.spv.globalPtr(spv_decl_index).?.result_id = var_id; |
| 891 | try section.emit(self.spv.gpa, .OpVariable, .{ | 888 | try section.emit(self.spv.gpa, .OpVariable, .{ |
| 892 | .id_result_type = self.typeId(ptr_constant_struct_ty_ref), | 889 | .id_result_type = self.typeId(ptr_constant_struct_ty_ref), |
| 893 | .id_result = var_id, | 890 | .id_result = var_id, |
| ... | @@ -896,12 +893,32 @@ pub const DeclGen = struct { | ... | @@ -896,12 +893,32 @@ pub const DeclGen = struct { |
| 896 | }); | 893 | }); |
| 897 | // TODO: Set alignment of OpVariable. | 894 | // TODO: Set alignment of OpVariable. |
| 898 | // TODO: We may be able to eliminate these casts. | 895 | // TODO: We may be able to eliminate these casts. |
| | 896 | |
| 899 | const const_ptr_id = try self.makePointerConstant(section, ptr_constant_struct_ty_ref, var_id); | 897 | const const_ptr_id = try self.makePointerConstant(section, ptr_constant_struct_ty_ref, var_id); |
| | 898 | const result_id = self.spv.declPtr(spv_decl_index).result_id; |
| | 899 | |
| | 900 | const bitcast_result_id = if (cast_to_generic) |
| | 901 | self.spv.allocId() |
| | 902 | else |
| | 903 | result_id; |
| | 904 | |
| 900 | try section.emitSpecConstantOp(self.spv.gpa, .OpBitcast, .{ | 905 | try section.emitSpecConstantOp(self.spv.gpa, .OpBitcast, .{ |
| 901 | .id_result_type = self.typeId(ptr_ty_ref), | 906 | .id_result_type = self.typeId(ptr_ty_ref), |
| 902 | .id_result = result_id, | 907 | .id_result = bitcast_result_id, |
| 903 | .operand = const_ptr_id, | 908 | .operand = const_ptr_id, |
| 904 | }); | 909 | }); |
| | 910 | |
| | 911 | if (cast_to_generic) { |
| | 912 | const generic_ptr_ty_ref = try self.spv.ptrType(ty_ref, .Generic, alignment); |
| | 913 | try section.emitSpecConstantOp(self.spv.gpa, .OpPtrCastToGeneric, .{ |
| | 914 | .id_result_type = self.typeId(generic_ptr_ty_ref), |
| | 915 | .id_result = result_id, |
| | 916 | .pointer = bitcast_result_id, |
| | 917 | }); |
| | 918 | } |
| | 919 | |
| | 920 | try self.spv.declareDeclDeps(spv_decl_index, icl.decl_deps.items); |
| | 921 | self.spv.endGlobal(spv_decl_index, begin_inst); |
| 905 | } | 922 | } |
| 906 | | 923 | |
| 907 | /// This function generates a load for a constant in direct (ie, non-memory) representation. | 924 | /// This function generates a load for a constant in direct (ie, non-memory) representation. |
| ... | @@ -940,19 +957,28 @@ pub const DeclGen = struct { | ... | @@ -940,19 +957,28 @@ pub const DeclGen = struct { |
| 940 | try section.emit(self.spv.gpa, .OpConstantFalse, operands); | 957 | try section.emit(self.spv.gpa, .OpConstantFalse, operands); |
| 941 | } | 958 | } |
| 942 | }, | 959 | }, |
| | 960 | // TODO: We can handle most pointers here (decl refs etc), because now they emit an extra |
| | 961 | // OpVariable that is not really required. |
| 943 | else => { | 962 | else => { |
| 944 | // The value cannot be generated directly, so generate it as an indirect constant, | 963 | // The value cannot be generated directly, so generate it as an indirect constant, |
| 945 | // and then perform an OpLoad. | 964 | // and then perform an OpLoad. |
| 946 | const alignment = ty.abiAlignment(target); | 965 | const alignment = ty.abiAlignment(target); |
| 947 | const global_index = try self.spv.allocGlobal(); | 966 | const spv_decl_index = try self.spv.allocDecl(.global); |
| 948 | log.debug("constant {}", .{global_index}); | 967 | |
| 949 | const ptr_id = self.spv.beginGlobal(global_index); | 968 | try self.lowerIndirectConstant( |
| 950 | defer self.spv.endGlobal(); | 969 | spv_decl_index, |
| 951 | try self.lowerIndirectConstant(ptr_id, ty, val, .UniformConstant, alignment); | 970 | ty, |
| | 971 | val, |
| | 972 | .UniformConstant, |
| | 973 | false, |
| | 974 | alignment, |
| | 975 | ); |
| | 976 | try self.func.decl_deps.append(self.spv.gpa, spv_decl_index); |
| | 977 | |
| 952 | try self.func.body.emit(self.spv.gpa, .OpLoad, .{ | 978 | try self.func.body.emit(self.spv.gpa, .OpLoad, .{ |
| 953 | .id_result_type = result_ty_id, | 979 | .id_result_type = result_ty_id, |
| 954 | .id_result = result_id, | 980 | .id_result = result_id, |
| 955 | .pointer = ptr_id, | 981 | .pointer = self.spv.declPtr(spv_decl_index).result_id, |
| 956 | }); | 982 | }); |
| 957 | // TODO: Convert bools? This logic should hook into `load`. It should be a dead | 983 | // TODO: Convert bools? This logic should hook into `load`. It should be a dead |
| 958 | // path though considering .Bool is handled above. | 984 | // path though considering .Bool is handled above. |
| ... | @@ -1289,7 +1315,7 @@ pub const DeclGen = struct { | ... | @@ -1289,7 +1315,7 @@ pub const DeclGen = struct { |
| 1289 | } | 1315 | } |
| 1290 | } | 1316 | } |
| 1291 | | 1317 | |
| 1292 | fn spvStorageClass(as: std.builtin.AddressSpace) spec.StorageClass { | 1318 | fn spvStorageClass(as: std.builtin.AddressSpace) StorageClass { |
| 1293 | return switch (as) { | 1319 | return switch (as) { |
| 1294 | .generic => .Generic, // TODO: Disallow? | 1320 | .generic => .Generic, // TODO: Disallow? |
| 1295 | .gs, .fs, .ss => unreachable, | 1321 | .gs, .fs, .ss => unreachable, |
| ... | @@ -1370,16 +1396,17 @@ pub const DeclGen = struct { | ... | @@ -1370,16 +1396,17 @@ pub const DeclGen = struct { |
| 1370 | | 1396 | |
| 1371 | fn genDecl(self: *DeclGen) !void { | 1397 | fn genDecl(self: *DeclGen) !void { |
| 1372 | const decl = self.module.declPtr(self.decl_index); | 1398 | const decl = self.module.declPtr(self.decl_index); |
| 1373 | const link = try self.resolveDecl(self.decl_index); | 1399 | const spv_decl_index = try self.resolveDecl(self.decl_index); |
| 1374 | | 1400 | |
| 1375 | if (decl.val.castTag(.function)) |_| { | 1401 | const decl_id = self.spv.declPtr(spv_decl_index).result_id; |
| 1376 | log.debug("genDecl function {s} = {}", .{ decl.name, link.func.result_id.id }); | 1402 | log.debug("genDecl {s} = {}", .{ decl.name, decl_id }); |
| 1377 | | 1403 | |
| | 1404 | if (decl.val.castTag(.function)) |_| { |
| 1378 | assert(decl.ty.zigTypeTag() == .Fn); | 1405 | assert(decl.ty.zigTypeTag() == .Fn); |
| 1379 | const prototype_id = try self.resolveTypeId(decl.ty); | 1406 | const prototype_id = try self.resolveTypeId(decl.ty); |
| 1380 | try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{ | 1407 | try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{ |
| 1381 | .id_result_type = try self.resolveTypeId(decl.ty.fnReturnType()), | 1408 | .id_result_type = try self.resolveTypeId(decl.ty.fnReturnType()), |
| 1382 | .id_result = link.func.result_id, | 1409 | .id_result = decl_id, |
| 1383 | .function_control = .{}, // TODO: We can set inline here if the type requires it. | 1410 | .function_control = .{}, // TODO: We can set inline here if the type requires it. |
| 1384 | .function_type = prototype_id, | 1411 | .function_type = prototype_id, |
| 1385 | }); | 1412 | }); |
| ... | @@ -1413,18 +1440,18 @@ pub const DeclGen = struct { | ... | @@ -1413,18 +1440,18 @@ pub const DeclGen = struct { |
| 1413 | | 1440 | |
| 1414 | // Append the actual code into the functions section. | 1441 | // Append the actual code into the functions section. |
| 1415 | try self.func.body.emit(self.spv.gpa, .OpFunctionEnd, {}); | 1442 | try self.func.body.emit(self.spv.gpa, .OpFunctionEnd, {}); |
| 1416 | try self.spv.addFunction(self.func); | 1443 | try self.spv.addFunction(spv_decl_index, self.func); |
| 1417 | | 1444 | |
| 1418 | const fqn = try decl.getFullyQualifiedName(self.module); | 1445 | const fqn = try decl.getFullyQualifiedName(self.module); |
| 1419 | defer self.module.gpa.free(fqn); | 1446 | defer self.module.gpa.free(fqn); |
| 1420 | | 1447 | |
| 1421 | try self.spv.sections.debug_names.emit(self.gpa, .OpName, .{ | 1448 | try self.spv.sections.debug_names.emit(self.gpa, .OpName, .{ |
| 1422 | .target = link.func.result_id, | 1449 | .target = decl_id, |
| 1423 | .name = fqn, | 1450 | .name = fqn, |
| 1424 | }); | 1451 | }); |
| 1425 | | 1452 | |
| 1426 | if (self.module.test_functions.contains(self.decl_index)) { | 1453 | if (self.module.test_functions.contains(self.decl_index)) { |
| 1427 | try self.generateTestEntryPoint(fqn, link.func.result_id); | 1454 | try self.generateTestEntryPoint(fqn, decl_id); |
| 1428 | } | 1455 | } |
| 1429 | } else { | 1456 | } else { |
| 1430 | const init_val = if (decl.val.castTag(.variable)) |payload| | 1457 | const init_val = if (decl.val.castTag(.variable)) |payload| |
| ... | @@ -1438,41 +1465,33 @@ pub const DeclGen = struct { | ... | @@ -1438,41 +1465,33 @@ pub const DeclGen = struct { |
| 1438 | | 1465 | |
| 1439 | // TODO: integrate with variable(). | 1466 | // TODO: integrate with variable(). |
| 1440 | | 1467 | |
| 1441 | const storage_class = spvStorageClass(decl.@"addrspace"); | 1468 | const final_storage_class = spvStorageClass(decl.@"addrspace"); |
| 1442 | const actual_storage_class = switch (storage_class) { | 1469 | const actual_storage_class = switch (final_storage_class) { |
| 1443 | .Generic => .CrossWorkgroup, | 1470 | .Generic => .CrossWorkgroup, |
| 1444 | else => storage_class, | 1471 | else => final_storage_class, |
| 1445 | }; | | |
| 1446 | | | |
| 1447 | const global_result_id = self.spv.beginGlobal(link.global); | | |
| 1448 | defer self.spv.endGlobal(); | | |
| 1449 | log.debug("genDecl {}", .{link.global}); | | |
| 1450 | | | |
| 1451 | const var_result_id = switch (storage_class) { | | |
| 1452 | .Generic => self.spv.allocId(), | | |
| 1453 | else => global_result_id, | | |
| 1454 | }; | 1472 | }; |
| 1455 | | 1473 | |
| 1456 | try self.lowerIndirectConstant( | 1474 | try self.lowerIndirectConstant( |
| 1457 | var_result_id, | 1475 | spv_decl_index, |
| 1458 | decl.ty, | 1476 | decl.ty, |
| 1459 | init_val, | 1477 | init_val, |
| 1460 | actual_storage_class, | 1478 | actual_storage_class, |
| | 1479 | final_storage_class == .Generic, |
| 1461 | decl.@"align", | 1480 | decl.@"align", |
| 1462 | ); | 1481 | ); |
| 1463 | | 1482 | |
| 1464 | if (storage_class == .Generic) { | 1483 | // if (storage_class == .Generic) { |
| 1465 | const section = &self.spv.globals.section; | 1484 | // const section = &self.spv.globals.section; |
| 1466 | const ty_ref = try self.resolveType(decl.ty, .indirect); | 1485 | // const ty_ref = try self.resolveType(decl.ty, .indirect); |
| 1467 | const ptr_ty_ref = try self.spv.ptrType(ty_ref, storage_class, decl.@"align"); | 1486 | // const ptr_ty_ref = try self.spv.ptrType(ty_ref, storage_class, decl.@"align"); |
| 1468 | // TODO: Can we eliminate this cast? | 1487 | // // TODO: Can we eliminate this cast? |
| 1469 | // TODO: Const-wash pointer | 1488 | // // TODO: Const-wash pointer? |
| 1470 | try section.emitSpecConstantOp(self.spv.gpa, .OpPtrCastToGeneric, .{ | 1489 | // try section.emitSpecConstantOp(self.spv.gpa, .OpPtrCastToGeneric, .{ |
| 1471 | .id_result_type = self.typeId(ptr_ty_ref), | 1490 | // .id_result_type = self.typeId(ptr_ty_ref), |
| 1472 | .id_result = global_result_id, | 1491 | // .id_result = global_result_id, |
| 1473 | .pointer = var_result_id, | 1492 | // .pointer = casted_result_id, |
| 1474 | }); | 1493 | // }); |
| 1475 | } | 1494 | // } |
| 1476 | } | 1495 | } |
| 1477 | } | 1496 | } |
| 1478 | | 1497 | |