| ... | @@ -452,16 +452,12 @@ pub const DeclGen = struct { | ... | @@ -452,16 +452,12 @@ pub const DeclGen = struct { |
| 452 | .storage_class = .Function, | 452 | .storage_class = .Function, |
| 453 | }); | 453 | }); |
| 454 | | 454 | |
| 455 | // Note: using 32-bit ints here because usize crashes the translator as well | | |
| 456 | const index_ty_ref = try self.intType(.unsigned, 32); | | |
| 457 | | | |
| 458 | const spv_composite_ty = self.spv.cache.lookup(result_ty_ref).struct_type; | 455 | const spv_composite_ty = self.spv.cache.lookup(result_ty_ref).struct_type; |
| 459 | const member_types = spv_composite_ty.member_types; | 456 | const member_types = spv_composite_ty.member_types; |
| 460 | | 457 | |
| 461 | for (constituents, member_types, 0..) |constitent_id, member_ty_ref, index| { | 458 | for (constituents, member_types, 0..) |constitent_id, member_ty_ref, index| { |
| 462 | const index_id = try self.constInt(index_ty_ref, index); | | |
| 463 | const ptr_member_ty_ref = try self.spv.ptrType(member_ty_ref, .Function); | 459 | const ptr_member_ty_ref = try self.spv.ptrType(member_ty_ref, .Function); |
| 464 | const ptr_id = try self.accessChain(ptr_member_ty_ref, ptr_composite_id, &.{index_id}); | 460 | const ptr_id = try self.accessChain(ptr_member_ty_ref, ptr_composite_id, &.{@as(u32, @intCast(index))}); |
| 465 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ | 461 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| 466 | .pointer = ptr_id, | 462 | .pointer = ptr_id, |
| 467 | .object = constitent_id, | 463 | .object = constitent_id, |
| ... | @@ -493,16 +489,12 @@ pub const DeclGen = struct { | ... | @@ -493,16 +489,12 @@ pub const DeclGen = struct { |
| 493 | .storage_class = .Function, | 489 | .storage_class = .Function, |
| 494 | }); | 490 | }); |
| 495 | | 491 | |
| 496 | // Note: using 32-bit ints here because usize crashes the translator as well | | |
| 497 | const index_ty_ref = try self.intType(.unsigned, 32); | | |
| 498 | | | |
| 499 | const spv_composite_ty = self.spv.cache.lookup(result_ty_ref).array_type; | 492 | const spv_composite_ty = self.spv.cache.lookup(result_ty_ref).array_type; |
| 500 | const elem_ty_ref = spv_composite_ty.element_type; | 493 | const elem_ty_ref = spv_composite_ty.element_type; |
| 501 | const ptr_elem_ty_ref = try self.spv.ptrType(elem_ty_ref, .Function); | 494 | const ptr_elem_ty_ref = try self.spv.ptrType(elem_ty_ref, .Function); |
| 502 | | 495 | |
| 503 | for (constituents, 0..) |constitent_id, index| { | 496 | for (constituents, 0..) |constitent_id, index| { |
| 504 | const index_id = try self.constInt(index_ty_ref, index); | 497 | const ptr_id = try self.accessChain(ptr_elem_ty_ref, ptr_composite_id, &.{@as(u32, @intCast(index))}); |
| 505 | const ptr_id = try self.accessChain(ptr_elem_ty_ref, ptr_composite_id, &.{index_id}); | | |
| 506 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ | 498 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| 507 | .pointer = ptr_id, | 499 | .pointer = ptr_id, |
| 508 | .object = constitent_id, | 500 | .object = constitent_id, |
| ... | @@ -535,18 +527,36 @@ pub const DeclGen = struct { | ... | @@ -535,18 +527,36 @@ pub const DeclGen = struct { |
| 535 | const decl_id = self.spv.declPtr(spv_decl_index).result_id; | 527 | const decl_id = self.spv.declPtr(spv_decl_index).result_id; |
| 536 | try self.func.decl_deps.put(self.spv.gpa, spv_decl_index, {}); | 528 | try self.func.decl_deps.put(self.spv.gpa, spv_decl_index, {}); |
| 537 | | 529 | |
| 538 | switch (decl.@"addrspace") { | 530 | const final_storage_class = spvStorageClass(decl.@"addrspace"); |
| 539 | .generic => { | 531 | |
| 540 | // Pointer should be generic, but is actually placed in CrossWorkgroup. | 532 | const decl_ty_ref = try self.resolveType(decl.ty, .indirect); |
| | 533 | const decl_ptr_ty_ref = try self.spv.ptrType(decl_ty_ref, final_storage_class); |
| | 534 | |
| | 535 | const ptr_id = switch (final_storage_class) { |
| | 536 | .Generic => blk: { |
| | 537 | // Pointer should be Generic, but is actually placed in CrossWorkgroup. |
| 541 | const result_id = self.spv.allocId(); | 538 | const result_id = self.spv.allocId(); |
| 542 | try self.func.body.emit(self.spv.gpa, .OpPtrCastToGeneric, .{ | 539 | try self.func.body.emit(self.spv.gpa, .OpPtrCastToGeneric, .{ |
| 543 | .id_result_type = ty_id, | 540 | .id_result_type = self.typeId(decl_ptr_ty_ref), |
| 544 | .id_result = result_id, | 541 | .id_result = result_id, |
| 545 | .pointer = decl_id, | 542 | .pointer = decl_id, |
| 546 | }); | 543 | }); |
| 547 | return result_id; | 544 | break :blk result_id; |
| 548 | }, | 545 | }, |
| 549 | else => return decl_id, // Variable is already correct, probably. Maybe needs a bitcast? | 546 | else => decl_id, |
| | 547 | }; |
| | 548 | |
| | 549 | if (decl_ptr_ty_ref != ty_ref) { |
| | 550 | // Differing pointer types, insert a cast. |
| | 551 | const casted_ptr_id = self.spv.allocId(); |
| | 552 | try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ |
| | 553 | .id_result_type = ty_id, |
| | 554 | .id_result = casted_ptr_id, |
| | 555 | .operand = ptr_id, |
| | 556 | }); |
| | 557 | return casted_ptr_id; |
| | 558 | } else { |
| | 559 | return ptr_id; |
| 550 | } | 560 | } |
| 551 | }, | 561 | }, |
| 552 | } | 562 | } |
| ... | @@ -820,14 +830,11 @@ pub const DeclGen = struct { | ... | @@ -820,14 +830,11 @@ pub const DeclGen = struct { |
| 820 | .storage_class = .Function, | 830 | .storage_class = .Function, |
| 821 | }); | 831 | }); |
| 822 | | 832 | |
| 823 | const index_ty_ref = try self.intType(.unsigned, 32); | | |
| 824 | | | |
| 825 | if (layout.tag_size != 0) { | 833 | if (layout.tag_size != 0) { |
| 826 | const index_id = try self.constInt(index_ty_ref, @as(u32, @intCast(layout.tag_index))); | | |
| 827 | const tag_ty = ty.unionTagTypeSafety(mod).?; | 834 | const tag_ty = ty.unionTagTypeSafety(mod).?; |
| 828 | const tag_ty_ref = try self.resolveType(tag_ty, .indirect); | 835 | const tag_ty_ref = try self.resolveType(tag_ty, .indirect); |
| 829 | const tag_ptr_ty_ref = try self.spv.ptrType(tag_ty_ref, .Function); | 836 | const tag_ptr_ty_ref = try self.spv.ptrType(tag_ty_ref, .Function); |
| 830 | const ptr_id = try self.accessChain(tag_ptr_ty_ref, var_id, &.{index_id}); | 837 | const ptr_id = try self.accessChain(tag_ptr_ty_ref, var_id, &.{@as(u32, @intCast(layout.tag_index))}); |
| 831 | const tag_id = try self.constant(tag_ty, un.tag.toValue(), .indirect); | 838 | const tag_id = try self.constant(tag_ty, un.tag.toValue(), .indirect); |
| 832 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ | 839 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| 833 | .pointer = ptr_id, | 840 | .pointer = ptr_id, |
| ... | @@ -836,10 +843,9 @@ pub const DeclGen = struct { | ... | @@ -836,10 +843,9 @@ pub const DeclGen = struct { |
| 836 | } | 843 | } |
| 837 | | 844 | |
| 838 | if (layout.active_field_size != 0) { | 845 | if (layout.active_field_size != 0) { |
| 839 | const index_id = try self.constInt(index_ty_ref, @as(u32, @intCast(layout.active_field_index))); | | |
| 840 | const active_field_ty_ref = try self.resolveType(layout.active_field_ty, .indirect); | 846 | const active_field_ty_ref = try self.resolveType(layout.active_field_ty, .indirect); |
| 841 | const active_field_ptr_ty_ref = try self.spv.ptrType(active_field_ty_ref, .Function); | 847 | const active_field_ptr_ty_ref = try self.spv.ptrType(active_field_ty_ref, .Function); |
| 842 | const ptr_id = try self.accessChain(active_field_ptr_ty_ref, var_id, &.{index_id}); | 848 | const ptr_id = try self.accessChain(active_field_ptr_ty_ref, var_id, &.{@as(u32, @intCast(layout.active_field_index))}); |
| 843 | const value_id = try self.constant(layout.active_field_ty, un.val.toValue(), .indirect); | 849 | const value_id = try self.constant(layout.active_field_ty, un.val.toValue(), .indirect); |
| 844 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ | 850 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| 845 | .pointer = ptr_id, | 851 | .pointer = ptr_id, |
| ... | @@ -2070,40 +2076,65 @@ pub const DeclGen = struct { | ... | @@ -2070,40 +2076,65 @@ pub const DeclGen = struct { |
| 2070 | return result_id; | 2076 | return result_id; |
| 2071 | } | 2077 | } |
| 2072 | | 2078 | |
| 2073 | /// AccessChain is essentially PtrAccessChain with 0 as initial argument. The effective | 2079 | fn indicesToIds(self: *DeclGen, indices: []const u32) ![]IdRef { |
| 2074 | /// difference lies in whether the resulting type of the first dereference will be the | 2080 | const index_ty_ref = try self.intType(.unsigned, 32); |
| 2075 | /// same as that of the base pointer, or that of a dereferenced base pointer. AccessChain | 2081 | const ids = try self.gpa.alloc(IdRef, indices.len); |
| 2076 | /// is the latter and PtrAccessChain is the former. | 2082 | errdefer self.gpa.free(ids); |
| 2077 | fn accessChain( | 2083 | for (indices, ids) |index, *id| { |
| | 2084 | id.* = try self.constInt(index_ty_ref, index); |
| | 2085 | } |
| | 2086 | |
| | 2087 | return ids; |
| | 2088 | } |
| | 2089 | |
| | 2090 | fn accessChainId( |
| 2078 | self: *DeclGen, | 2091 | self: *DeclGen, |
| 2079 | result_ty_ref: CacheRef, | 2092 | result_ty_ref: CacheRef, |
| 2080 | base: IdRef, | 2093 | base: IdRef, |
| 2081 | indexes: []const IdRef, | 2094 | indices: []const IdRef, |
| 2082 | ) !IdRef { | 2095 | ) !IdRef { |
| 2083 | const result_id = self.spv.allocId(); | 2096 | const result_id = self.spv.allocId(); |
| 2084 | try self.func.body.emit(self.spv.gpa, .OpInBoundsAccessChain, .{ | 2097 | try self.func.body.emit(self.spv.gpa, .OpInBoundsAccessChain, .{ |
| 2085 | .id_result_type = self.typeId(result_ty_ref), | 2098 | .id_result_type = self.typeId(result_ty_ref), |
| 2086 | .id_result = result_id, | 2099 | .id_result = result_id, |
| 2087 | .base = base, | 2100 | .base = base, |
| 2088 | .indexes = indexes, | 2101 | .indexes = indices, |
| 2089 | }); | 2102 | }); |
| 2090 | return result_id; | 2103 | return result_id; |
| 2091 | } | 2104 | } |
| 2092 | | 2105 | |
| | 2106 | /// AccessChain is essentially PtrAccessChain with 0 as initial argument. The effective |
| | 2107 | /// difference lies in whether the resulting type of the first dereference will be the |
| | 2108 | /// same as that of the base pointer, or that of a dereferenced base pointer. AccessChain |
| | 2109 | /// is the latter and PtrAccessChain is the former. |
| | 2110 | fn accessChain( |
| | 2111 | self: *DeclGen, |
| | 2112 | result_ty_ref: CacheRef, |
| | 2113 | base: IdRef, |
| | 2114 | indices: []const u32, |
| | 2115 | ) !IdRef { |
| | 2116 | const ids = try self.indicesToIds(indices); |
| | 2117 | defer self.gpa.free(ids); |
| | 2118 | return try self.accessChainId(result_ty_ref, base, ids); |
| | 2119 | } |
| | 2120 | |
| 2093 | fn ptrAccessChain( | 2121 | fn ptrAccessChain( |
| 2094 | self: *DeclGen, | 2122 | self: *DeclGen, |
| 2095 | result_ty_ref: CacheRef, | 2123 | result_ty_ref: CacheRef, |
| 2096 | base: IdRef, | 2124 | base: IdRef, |
| 2097 | element: IdRef, | 2125 | element: IdRef, |
| 2098 | indexes: []const IdRef, | 2126 | indices: []const u32, |
| 2099 | ) !IdRef { | 2127 | ) !IdRef { |
| | 2128 | const ids = try self.indicesToIds(indices); |
| | 2129 | defer self.gpa.free(ids); |
| | 2130 | |
| 2100 | const result_id = self.spv.allocId(); | 2131 | const result_id = self.spv.allocId(); |
| 2101 | try self.func.body.emit(self.spv.gpa, .OpInBoundsPtrAccessChain, .{ | 2132 | try self.func.body.emit(self.spv.gpa, .OpInBoundsPtrAccessChain, .{ |
| 2102 | .id_result_type = self.typeId(result_ty_ref), | 2133 | .id_result_type = self.typeId(result_ty_ref), |
| 2103 | .id_result = result_id, | 2134 | .id_result = result_id, |
| 2104 | .base = base, | 2135 | .base = base, |
| 2105 | .element = element, | 2136 | .element = element, |
| 2106 | .indexes = indexes, | 2137 | .indexes = ids, |
| 2107 | }); | 2138 | }); |
| 2108 | return result_id; | 2139 | return result_id; |
| 2109 | } | 2140 | } |
| ... | @@ -2116,7 +2147,7 @@ pub const DeclGen = struct { | ... | @@ -2116,7 +2147,7 @@ pub const DeclGen = struct { |
| 2116 | .One => { | 2147 | .One => { |
| 2117 | // Pointer to array | 2148 | // Pointer to array |
| 2118 | // TODO: Is this correct? | 2149 | // TODO: Is this correct? |
| 2119 | return try self.accessChain(result_ty_ref, ptr_id, &.{offset_id}); | 2150 | return try self.accessChainId(result_ty_ref, ptr_id, &.{offset_id}); |
| 2120 | }, | 2151 | }, |
| 2121 | .C, .Many => { | 2152 | .C, .Many => { |
| 2122 | return try self.ptrAccessChain(result_ty_ref, ptr_id, offset_id, &.{}); | 2153 | return try self.ptrAccessChain(result_ty_ref, ptr_id, offset_id, &.{}); |
| ... | @@ -2493,7 +2524,7 @@ pub const DeclGen = struct { | ... | @@ -2493,7 +2524,7 @@ pub const DeclGen = struct { |
| 2493 | if (ptr_ty.isSinglePointer(mod)) { | 2524 | if (ptr_ty.isSinglePointer(mod)) { |
| 2494 | // Pointer-to-array. In this case, the resulting pointer is not of the same type | 2525 | // Pointer-to-array. In this case, the resulting pointer is not of the same type |
| 2495 | // as the ptr_ty (we want a *T, not a *[N]T), and hence we need to use accessChain. | 2526 | // as the ptr_ty (we want a *T, not a *[N]T), and hence we need to use accessChain. |
| 2496 | return try self.accessChain(elem_ptr_ty_ref, ptr_id, &.{index_id}); | 2527 | return try self.accessChainId(elem_ptr_ty_ref, ptr_id, &.{index_id}); |
| 2497 | } else { | 2528 | } else { |
| 2498 | // Resulting pointer type is the same as the ptr_ty, so use ptrAccessChain | 2529 | // Resulting pointer type is the same as the ptr_ty, so use ptrAccessChain |
| 2499 | return try self.ptrAccessChain(elem_ptr_ty_ref, ptr_id, index_id, &.{}); | 2530 | return try self.ptrAccessChain(elem_ptr_ty_ref, ptr_id, index_id, &.{}); |
| ... | @@ -2540,15 +2571,14 @@ pub const DeclGen = struct { | ... | @@ -2540,15 +2571,14 @@ pub const DeclGen = struct { |
| 2540 | const un_ty = self.typeOf(ty_op.operand); | 2571 | const un_ty = self.typeOf(ty_op.operand); |
| 2541 | | 2572 | |
| 2542 | const mod = self.module; | 2573 | const mod = self.module; |
| 2543 | const layout = un_ty.unionGetLayout(mod); | 2574 | const layout = self.unionLayout(un_ty, null); |
| 2544 | if (layout.tag_size == 0) return null; | 2575 | if (layout.tag_size == 0) return null; |
| 2545 | | 2576 | |
| 2546 | const union_handle = try self.resolve(ty_op.operand); | 2577 | const union_handle = try self.resolve(ty_op.operand); |
| 2547 | if (layout.payload_size == 0) return union_handle; | 2578 | if (layout.payload_size == 0) return union_handle; |
| 2548 | | 2579 | |
| 2549 | const tag_ty = un_ty.unionTagTypeSafety(mod).?; | 2580 | const tag_ty = un_ty.unionTagTypeSafety(mod).?; |
| 2550 | const tag_index = @intFromBool(layout.tag_align.compare(.lt, layout.payload_align)); | 2581 | return try self.extractField(tag_ty, union_handle, layout.tag_index); |
| 2551 | return try self.extractField(tag_ty, union_handle, tag_index); | | |
| 2552 | } | 2582 | } |
| 2553 | | 2583 | |
| 2554 | fn airStructFieldVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 2584 | fn airStructFieldVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| ... | @@ -2558,16 +2588,60 @@ pub const DeclGen = struct { | ... | @@ -2558,16 +2588,60 @@ pub const DeclGen = struct { |
| 2558 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 2588 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2559 | const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data; | 2589 | const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 2560 | | 2590 | |
| 2561 | const struct_ty = self.typeOf(struct_field.struct_operand); | 2591 | const container_ty = self.typeOf(struct_field.struct_operand); |
| 2562 | const object_id = try self.resolve(struct_field.struct_operand); | 2592 | const object_id = try self.resolve(struct_field.struct_operand); |
| 2563 | const field_index = struct_field.field_index; | 2593 | const field_index = struct_field.field_index; |
| 2564 | const field_ty = struct_ty.structFieldType(field_index, mod); | 2594 | const field_ty = container_ty.structFieldType(field_index, mod); |
| 2565 | | 2595 | |
| 2566 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) return null; | 2596 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) return null; |
| 2567 | | 2597 | |
| 2568 | assert(struct_ty.zigTypeTag(mod) == .Struct); // Cannot do unions yet. | 2598 | switch (container_ty.zigTypeTag(mod)) { |
| | 2599 | .Struct => switch (container_ty.containerLayout(mod)) { |
| | 2600 | .Packed => unreachable, // TODO |
| | 2601 | else => return try self.extractField(field_ty, object_id, field_index), |
| | 2602 | }, |
| | 2603 | .Union => switch (container_ty.containerLayout(mod)) { |
| | 2604 | .Packed => unreachable, // TODO |
| | 2605 | else => { |
| | 2606 | // Store, pointer-cast, load |
| | 2607 | const un_general_ty_ref = try self.resolveType(container_ty, .indirect); |
| | 2608 | const un_general_ptr_ty_ref = try self.spv.ptrType(un_general_ty_ref, .Function); |
| | 2609 | const un_active_ty_ref = try self.resolveUnionType(container_ty, field_index); |
| | 2610 | const un_active_ptr_ty_ref = try self.spv.ptrType(un_active_ty_ref, .Function); |
| | 2611 | const field_ty_ref = try self.resolveType(field_ty, .indirect); |
| | 2612 | const field_ptr_ty_ref = try self.spv.ptrType(field_ty_ref, .Function); |
| | 2613 | |
| | 2614 | const tmp_id = self.spv.allocId(); |
| | 2615 | try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{ |
| | 2616 | .id_result_type = self.typeId(un_general_ptr_ty_ref), |
| | 2617 | .id_result = tmp_id, |
| | 2618 | .storage_class = .Function, |
| | 2619 | }); |
| | 2620 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| | 2621 | .pointer = tmp_id, |
| | 2622 | .object = object_id, |
| | 2623 | }); |
| | 2624 | const casted_tmp_id = self.spv.allocId(); |
| | 2625 | try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ |
| | 2626 | .id_result_type = self.typeId(un_active_ptr_ty_ref), |
| | 2627 | .id_result = casted_tmp_id, |
| | 2628 | .operand = tmp_id, |
| | 2629 | }); |
| | 2630 | const layout = self.unionLayout(container_ty, field_index); |
| | 2631 | const field_ptr_id = try self.accessChain(field_ptr_ty_ref, casted_tmp_id, &.{layout.active_field_index}); |
| | 2632 | const result_id = self.spv.allocId(); |
| | 2633 | try self.func.body.emit(self.spv.gpa, .OpLoad, .{ |
| | 2634 | .id_result_type = self.typeId(field_ty_ref), |
| | 2635 | .id_result = result_id, |
| | 2636 | .pointer = field_ptr_id, |
| | 2637 | }); |
| | 2638 | return try self.convertToDirect(field_ty, result_id); |
| | 2639 | }, |
| | 2640 | }, |
| | 2641 | else => unreachable, |
| | 2642 | } |
| 2569 | | 2643 | |
| 2570 | return try self.extractField(field_ty, object_id, field_index); | 2644 | // return try self.extractField(field_ty, object_id, field_index); |
| 2571 | } | 2645 | } |
| 2572 | | 2646 | |
| 2573 | fn structFieldPtr( | 2647 | fn structFieldPtr( |
| ... | @@ -2583,10 +2657,8 @@ pub const DeclGen = struct { | ... | @@ -2583,10 +2657,8 @@ pub const DeclGen = struct { |
| 2583 | .Struct => switch (object_ty.containerLayout(mod)) { | 2657 | .Struct => switch (object_ty.containerLayout(mod)) { |
| 2584 | .Packed => unreachable, // TODO | 2658 | .Packed => unreachable, // TODO |
| 2585 | else => { | 2659 | else => { |
| 2586 | const field_index_ty_ref = try self.intType(.unsigned, 32); | | |
| 2587 | const field_index_id = try self.constInt(field_index_ty_ref, field_index); | | |
| 2588 | const result_ty_ref = try self.resolveType(result_ptr_ty, .direct); | 2660 | const result_ty_ref = try self.resolveType(result_ptr_ty, .direct); |
| 2589 | return try self.accessChain(result_ty_ref, object_ptr, &.{field_index_id}); | 2661 | return try self.accessChain(result_ty_ref, object_ptr, &.{field_index}); |
| 2590 | }, | 2662 | }, |
| 2591 | }, | 2663 | }, |
| 2592 | else => unreachable, // TODO | 2664 | else => unreachable, // TODO |