| ... | ... | @@ -452,16 +452,12 @@ pub const DeclGen = struct { |
| 452 | 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 | 455 | const spv_composite_ty = self.spv.cache.lookup(result_ty_ref).struct_type; |
| 459 | 456 | const member_types = spv_composite_ty.member_types; |
| 460 | 457 | |
| 461 | 458 | for (constituents, member_types, 0..) |constitent_id, member_ty_ref, index| { |
| 462 | | const index_id = try self.constInt(index_ty_ref, index); |
| 463 | 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 | 461 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| 466 | 462 | .pointer = ptr_id, |
| 467 | 463 | .object = constitent_id, |
| ... | ... | @@ -493,16 +489,12 @@ pub const DeclGen = struct { |
| 493 | 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 | 492 | const spv_composite_ty = self.spv.cache.lookup(result_ty_ref).array_type; |
| 500 | 493 | const elem_ty_ref = spv_composite_ty.element_type; |
| 501 | 494 | const ptr_elem_ty_ref = try self.spv.ptrType(elem_ty_ref, .Function); |
| 502 | 495 | |
| 503 | 496 | for (constituents, 0..) |constitent_id, index| { |
| 504 | | const index_id = try self.constInt(index_ty_ref, index); |
| 505 | | const ptr_id = try self.accessChain(ptr_elem_ty_ref, ptr_composite_id, &.{index_id}); |
| 497 | const ptr_id = try self.accessChain(ptr_elem_ty_ref, ptr_composite_id, &.{@as(u32, @intCast(index))}); |
| 506 | 498 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| 507 | 499 | .pointer = ptr_id, |
| 508 | 500 | .object = constitent_id, |
| ... | ... | @@ -535,18 +527,36 @@ pub const DeclGen = struct { |
| 535 | 527 | const decl_id = self.spv.declPtr(spv_decl_index).result_id; |
| 536 | 528 | try self.func.decl_deps.put(self.spv.gpa, spv_decl_index, {}); |
| 537 | 529 | |
| 538 | | switch (decl.@"addrspace") { |
| 539 | | .generic => { |
| 540 | | // Pointer should be generic, but is actually placed in CrossWorkgroup. |
| 530 | const final_storage_class = spvStorageClass(decl.@"addrspace"); |
| 531 | |
| 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 | 538 | const result_id = self.spv.allocId(); |
| 542 | 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 | 541 | .id_result = result_id, |
| 545 | 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 | 830 | .storage_class = .Function, |
| 821 | 831 | }); |
| 822 | 832 | |
| 823 | | const index_ty_ref = try self.intType(.unsigned, 32); |
| 824 | | |
| 825 | 833 | if (layout.tag_size != 0) { |
| 826 | | const index_id = try self.constInt(index_ty_ref, @as(u32, @intCast(layout.tag_index))); |
| 827 | 834 | const tag_ty = ty.unionTagTypeSafety(mod).?; |
| 828 | 835 | const tag_ty_ref = try self.resolveType(tag_ty, .indirect); |
| 829 | 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 | 838 | const tag_id = try self.constant(tag_ty, un.tag.toValue(), .indirect); |
| 832 | 839 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| 833 | 840 | .pointer = ptr_id, |
| ... | ... | @@ -836,10 +843,9 @@ pub const DeclGen = struct { |
| 836 | 843 | } |
| 837 | 844 | |
| 838 | 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 | 846 | const active_field_ty_ref = try self.resolveType(layout.active_field_ty, .indirect); |
| 841 | 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 | 849 | const value_id = try self.constant(layout.active_field_ty, un.val.toValue(), .indirect); |
| 844 | 850 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| 845 | 851 | .pointer = ptr_id, |
| ... | ... | @@ -2070,40 +2076,65 @@ pub const DeclGen = struct { |
| 2070 | 2076 | return result_id; |
| 2071 | 2077 | } |
| 2072 | 2078 | |
| 2073 | | /// AccessChain is essentially PtrAccessChain with 0 as initial argument. The effective |
| 2074 | | /// difference lies in whether the resulting type of the first dereference will be the |
| 2075 | | /// same as that of the base pointer, or that of a dereferenced base pointer. AccessChain |
| 2076 | | /// is the latter and PtrAccessChain is the former. |
| 2077 | | fn accessChain( |
| 2079 | fn indicesToIds(self: *DeclGen, indices: []const u32) ![]IdRef { |
| 2080 | const index_ty_ref = try self.intType(.unsigned, 32); |
| 2081 | const ids = try self.gpa.alloc(IdRef, indices.len); |
| 2082 | errdefer self.gpa.free(ids); |
| 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 | 2091 | self: *DeclGen, |
| 2079 | 2092 | result_ty_ref: CacheRef, |
| 2080 | 2093 | base: IdRef, |
| 2081 | | indexes: []const IdRef, |
| 2094 | indices: []const IdRef, |
| 2082 | 2095 | ) !IdRef { |
| 2083 | 2096 | const result_id = self.spv.allocId(); |
| 2084 | 2097 | try self.func.body.emit(self.spv.gpa, .OpInBoundsAccessChain, .{ |
| 2085 | 2098 | .id_result_type = self.typeId(result_ty_ref), |
| 2086 | 2099 | .id_result = result_id, |
| 2087 | 2100 | .base = base, |
| 2088 | | .indexes = indexes, |
| 2101 | .indexes = indices, |
| 2089 | 2102 | }); |
| 2090 | 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 | 2121 | fn ptrAccessChain( |
| 2094 | 2122 | self: *DeclGen, |
| 2095 | 2123 | result_ty_ref: CacheRef, |
| 2096 | 2124 | base: IdRef, |
| 2097 | 2125 | element: IdRef, |
| 2098 | | indexes: []const IdRef, |
| 2126 | indices: []const u32, |
| 2099 | 2127 | ) !IdRef { |
| 2128 | const ids = try self.indicesToIds(indices); |
| 2129 | defer self.gpa.free(ids); |
| 2130 | |
| 2100 | 2131 | const result_id = self.spv.allocId(); |
| 2101 | 2132 | try self.func.body.emit(self.spv.gpa, .OpInBoundsPtrAccessChain, .{ |
| 2102 | 2133 | .id_result_type = self.typeId(result_ty_ref), |
| 2103 | 2134 | .id_result = result_id, |
| 2104 | 2135 | .base = base, |
| 2105 | 2136 | .element = element, |
| 2106 | | .indexes = indexes, |
| 2137 | .indexes = ids, |
| 2107 | 2138 | }); |
| 2108 | 2139 | return result_id; |
| 2109 | 2140 | } |
| ... | ... | @@ -2116,7 +2147,7 @@ pub const DeclGen = struct { |
| 2116 | 2147 | .One => { |
| 2117 | 2148 | // Pointer to array |
| 2118 | 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 | 2152 | .C, .Many => { |
| 2122 | 2153 | return try self.ptrAccessChain(result_ty_ref, ptr_id, offset_id, &.{}); |
| ... | ... | @@ -2493,7 +2524,7 @@ pub const DeclGen = struct { |
| 2493 | 2524 | if (ptr_ty.isSinglePointer(mod)) { |
| 2494 | 2525 | // Pointer-to-array. In this case, the resulting pointer is not of the same type |
| 2495 | 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 | 2528 | } else { |
| 2498 | 2529 | // Resulting pointer type is the same as the ptr_ty, so use ptrAccessChain |
| 2499 | 2530 | return try self.ptrAccessChain(elem_ptr_ty_ref, ptr_id, index_id, &.{}); |
| ... | ... | @@ -2540,15 +2571,14 @@ pub const DeclGen = struct { |
| 2540 | 2571 | const un_ty = self.typeOf(ty_op.operand); |
| 2541 | 2572 | |
| 2542 | 2573 | const mod = self.module; |
| 2543 | | const layout = un_ty.unionGetLayout(mod); |
| 2574 | const layout = self.unionLayout(un_ty, null); |
| 2544 | 2575 | if (layout.tag_size == 0) return null; |
| 2545 | 2576 | |
| 2546 | 2577 | const union_handle = try self.resolve(ty_op.operand); |
| 2547 | 2578 | if (layout.payload_size == 0) return union_handle; |
| 2548 | 2579 | |
| 2549 | 2580 | const tag_ty = un_ty.unionTagTypeSafety(mod).?; |
| 2550 | | const tag_index = @intFromBool(layout.tag_align.compare(.lt, layout.payload_align)); |
| 2551 | | return try self.extractField(tag_ty, union_handle, tag_index); |
| 2581 | return try self.extractField(tag_ty, union_handle, layout.tag_index); |
| 2552 | 2582 | } |
| 2553 | 2583 | |
| 2554 | 2584 | fn airStructFieldVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| ... | ... | @@ -2558,16 +2588,60 @@ pub const DeclGen = struct { |
| 2558 | 2588 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2559 | 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 | 2592 | const object_id = try self.resolve(struct_field.struct_operand); |
| 2563 | 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 | 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 | 2647 | fn structFieldPtr( |
| ... | ... | @@ -2583,10 +2657,8 @@ pub const DeclGen = struct { |
| 2583 | 2657 | .Struct => switch (object_ty.containerLayout(mod)) { |
| 2584 | 2658 | .Packed => unreachable, // TODO |
| 2585 | 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 | 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 | 2664 | else => unreachable, // TODO |