| ... | ... | @@ -41,6 +41,8 @@ fn_block: ?*GenZir = null, |
| 41 | 41 | /// Maps string table indexes to the first `@import` ZIR instruction |
| 42 | 42 | /// that uses this string as the operand. |
| 43 | 43 | imports: std.AutoArrayHashMapUnmanaged(u32, Ast.TokenIndex) = .{}, |
| 44 | /// Used for temporary storage when building payloads. |
| 45 | scratch: std.ArrayListUnmanaged(u32) = .{}, |
| 44 | 46 | |
| 45 | 47 | const InnerError = error{ OutOfMemory, AnalysisFail }; |
| 46 | 48 | |
| ... | ... | @@ -198,6 +200,7 @@ pub fn deinit(astgen: *AstGen, gpa: *Allocator) void { |
| 198 | 200 | astgen.string_bytes.deinit(gpa); |
| 199 | 201 | astgen.compile_errors.deinit(gpa); |
| 200 | 202 | astgen.imports.deinit(gpa); |
| 203 | astgen.scratch.deinit(gpa); |
| 201 | 204 | } |
| 202 | 205 | |
| 203 | 206 | pub const ResultLoc = union(enum) { |
| ... | ... | @@ -2996,7 +2999,8 @@ fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.I |
| 2996 | 2999 | } |
| 2997 | 3000 | |
| 2998 | 3001 | const WipMembers = struct { |
| 2999 | | payload: []u32, |
| 3002 | payload: *ArrayListUnmanaged(u32), |
| 3003 | payload_top: usize, |
| 3000 | 3004 | decls_start: u32, |
| 3001 | 3005 | decls_end: u32, |
| 3002 | 3006 | field_bits_start: u32, |
| ... | ... | @@ -3013,16 +3017,19 @@ const WipMembers = struct { |
| 3013 | 3017 | /// (4 for src_hash + line + name + value + align + link_section + address_space) |
| 3014 | 3018 | const max_decl_size = 10; |
| 3015 | 3019 | |
| 3016 | | pub fn init(gpa: *Allocator, decl_count: u32, field_count: u32, comptime bits_per_field: u32, comptime max_field_size: u32) Allocator.Error!Self { |
| 3017 | | const decls_start = (decl_count + decls_per_u32 - 1) / decls_per_u32; |
| 3020 | pub fn init(gpa: *Allocator, payload: *ArrayListUnmanaged(u32), decl_count: u32, field_count: u32, comptime bits_per_field: u32, comptime max_field_size: u32) Allocator.Error!Self { |
| 3021 | const payload_top = @intCast(u32, payload.items.len); |
| 3022 | const decls_start = payload_top + (decl_count + decls_per_u32 - 1) / decls_per_u32; |
| 3018 | 3023 | const field_bits_start = decls_start + decl_count * max_decl_size; |
| 3019 | | const fields_start = if (bits_per_field > 0) blk: { |
| 3024 | const fields_start = field_bits_start + if (bits_per_field > 0) blk: { |
| 3020 | 3025 | const fields_per_u32 = 32 / bits_per_field; |
| 3021 | | break :blk field_bits_start + (field_count + fields_per_u32 - 1) / fields_per_u32; |
| 3022 | | } else field_bits_start; |
| 3023 | | const capacity = fields_start + field_count * max_field_size; |
| 3026 | break :blk (field_count + fields_per_u32 - 1) / fields_per_u32; |
| 3027 | } else 0; |
| 3028 | const payload_end = fields_start + field_count * max_field_size; |
| 3029 | try payload.resize(gpa, payload_end); |
| 3024 | 3030 | return Self{ |
| 3025 | | .payload = try gpa.alloc(u32, capacity), |
| 3031 | .payload = payload, |
| 3032 | .payload_top = payload_top, |
| 3026 | 3033 | .decls_start = decls_start, |
| 3027 | 3034 | .field_bits_start = field_bits_start, |
| 3028 | 3035 | .fields_start = fields_start, |
| ... | ... | @@ -3032,10 +3039,10 @@ const WipMembers = struct { |
| 3032 | 3039 | } |
| 3033 | 3040 | |
| 3034 | 3041 | pub fn nextDecl(self: *Self, is_pub: bool, is_export: bool, has_align: bool, has_section_or_addrspace: bool) void { |
| 3035 | | const index = self.decl_index / decls_per_u32; |
| 3042 | const index = self.payload_top + self.decl_index / decls_per_u32; |
| 3036 | 3043 | assert(index < self.decls_start); |
| 3037 | | const bit_bag: u32 = if (self.decl_index % decls_per_u32 == 0) 0 else self.payload[index]; |
| 3038 | | self.payload[index] = (bit_bag >> bits_per_decl) | |
| 3044 | const bit_bag: u32 = if (self.decl_index % decls_per_u32 == 0) 0 else self.payload.items[index]; |
| 3045 | self.payload.items[index] = (bit_bag >> bits_per_decl) | |
| 3039 | 3046 | (@as(u32, @boolToInt(is_pub)) << 28) | |
| 3040 | 3047 | (@as(u32, @boolToInt(is_export)) << 29) | |
| 3041 | 3048 | (@as(u32, @boolToInt(has_align)) << 30) | |
| ... | ... | @@ -3047,60 +3054,60 @@ const WipMembers = struct { |
| 3047 | 3054 | const fields_per_u32 = 32 / bits_per_field; |
| 3048 | 3055 | const index = self.field_bits_start + self.field_index / fields_per_u32; |
| 3049 | 3056 | assert(index < self.fields_start); |
| 3050 | | var bit_bag: u32 = if (self.field_index % fields_per_u32 == 0) 0 else self.payload[index]; |
| 3057 | var bit_bag: u32 = if (self.field_index % fields_per_u32 == 0) 0 else self.payload.items[index]; |
| 3051 | 3058 | bit_bag >>= bits_per_field; |
| 3052 | 3059 | comptime var i = 0; |
| 3053 | 3060 | inline while (i < bits_per_field) : (i += 1) { |
| 3054 | 3061 | bit_bag |= @as(u32, @boolToInt(bits[i])) << (32 - bits_per_field + i); |
| 3055 | 3062 | } |
| 3056 | | self.payload[index] = bit_bag; |
| 3063 | self.payload.items[index] = bit_bag; |
| 3057 | 3064 | self.field_index += 1; |
| 3058 | 3065 | } |
| 3059 | 3066 | |
| 3060 | 3067 | pub fn appendToDecl(self: *Self, data: u32) void { |
| 3061 | 3068 | assert(self.decls_end < self.field_bits_start); |
| 3062 | | self.payload[self.decls_end] = data; |
| 3069 | self.payload.items[self.decls_end] = data; |
| 3063 | 3070 | self.decls_end += 1; |
| 3064 | 3071 | } |
| 3065 | 3072 | |
| 3066 | 3073 | pub fn appendToDeclSlice(self: *Self, data: []const u32) void { |
| 3067 | 3074 | assert(self.decls_end + data.len <= self.field_bits_start); |
| 3068 | | mem.copy(u32, self.payload[self.decls_end..], data); |
| 3075 | mem.copy(u32, self.payload.items[self.decls_end..], data); |
| 3069 | 3076 | self.decls_end += @intCast(u32, data.len); |
| 3070 | 3077 | } |
| 3071 | 3078 | |
| 3072 | 3079 | pub fn appendToField(self: *Self, data: u32) void { |
| 3073 | | assert(self.fields_end < self.payload.len); |
| 3074 | | self.payload[self.fields_end] = data; |
| 3080 | assert(self.fields_end < self.payload.items.len); |
| 3081 | self.payload.items[self.fields_end] = data; |
| 3075 | 3082 | self.fields_end += 1; |
| 3076 | 3083 | } |
| 3077 | 3084 | |
| 3078 | 3085 | pub fn finishBits(self: *Self, comptime bits_per_field: u32) void { |
| 3079 | 3086 | const empty_decl_slots = decls_per_u32 - (self.decl_index % decls_per_u32); |
| 3080 | 3087 | if (self.decl_index > 0 and empty_decl_slots < decls_per_u32) { |
| 3081 | | const index = self.decl_index / decls_per_u32; |
| 3082 | | self.payload[index] >>= @intCast(u5, empty_decl_slots * bits_per_decl); |
| 3088 | const index = self.payload_top + self.decl_index / decls_per_u32; |
| 3089 | self.payload.items[index] >>= @intCast(u5, empty_decl_slots * bits_per_decl); |
| 3083 | 3090 | } |
| 3084 | 3091 | if (bits_per_field > 0) { |
| 3085 | 3092 | const fields_per_u32 = 32 / bits_per_field; |
| 3086 | 3093 | const empty_field_slots = fields_per_u32 - (self.field_index % fields_per_u32); |
| 3087 | 3094 | if (self.field_index > 0 and empty_field_slots < fields_per_u32) { |
| 3088 | 3095 | const index = self.field_bits_start + self.field_index / fields_per_u32; |
| 3089 | | self.payload[index] >>= @intCast(u5, empty_field_slots * bits_per_field); |
| 3096 | self.payload.items[index] >>= @intCast(u5, empty_field_slots * bits_per_field); |
| 3090 | 3097 | } |
| 3091 | 3098 | } |
| 3092 | 3099 | } |
| 3093 | 3100 | |
| 3094 | 3101 | pub fn declsSlice(self: *Self) []u32 { |
| 3095 | | return self.payload[0..self.decls_end]; |
| 3102 | return self.payload.items[self.payload_top..self.decls_end]; |
| 3096 | 3103 | } |
| 3097 | 3104 | |
| 3098 | 3105 | pub fn fieldsSlice(self: *Self) []u32 { |
| 3099 | | return self.payload[self.field_bits_start..self.fields_end]; |
| 3106 | return self.payload.items[self.field_bits_start..self.fields_end]; |
| 3100 | 3107 | } |
| 3101 | 3108 | |
| 3102 | | pub fn deinit(self: *Self, gpa: *Allocator) void { |
| 3103 | | gpa.free(self.payload); |
| 3109 | pub fn deinit(self: *Self) void { |
| 3110 | self.payload.items.len = self.payload_top; |
| 3104 | 3111 | } |
| 3105 | 3112 | }; |
| 3106 | 3113 | |
| ... | ... | @@ -3777,8 +3784,8 @@ fn structDeclInner( |
| 3777 | 3784 | |
| 3778 | 3785 | const bits_per_field = 4; |
| 3779 | 3786 | const max_field_size = 4; |
| 3780 | | var wip_members = try WipMembers.init(gpa, decl_count, field_count, bits_per_field, max_field_size); |
| 3781 | | defer wip_members.deinit(gpa); |
| 3787 | var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size); |
| 3788 | defer wip_members.deinit(); |
| 3782 | 3789 | |
| 3783 | 3790 | var known_has_bits = false; |
| 3784 | 3791 | for (container_decl.ast.members) |member_node| { |
| ... | ... | @@ -3893,8 +3900,8 @@ fn unionDeclInner( |
| 3893 | 3900 | |
| 3894 | 3901 | const bits_per_field = 4; |
| 3895 | 3902 | const max_field_size = 4; |
| 3896 | | var wip_members = try WipMembers.init(gpa, decl_count, field_count, bits_per_field, max_field_size); |
| 3897 | | defer wip_members.deinit(gpa); |
| 3903 | var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size); |
| 3904 | defer wip_members.deinit(); |
| 3898 | 3905 | |
| 3899 | 3906 | for (members) |member_node| { |
| 3900 | 3907 | const member = switch (try containerMember(gz, &namespace.base, &wip_members, member_node)) { |
| ... | ... | @@ -4166,8 +4173,8 @@ fn containerDecl( |
| 4166 | 4173 | |
| 4167 | 4174 | const bits_per_field = 1; |
| 4168 | 4175 | const max_field_size = 2; |
| 4169 | | var wip_members = try WipMembers.init(gpa, @intCast(u32, counts.decls), @intCast(u32, counts.total_fields), bits_per_field, max_field_size); |
| 4170 | | defer wip_members.deinit(gpa); |
| 4176 | var wip_members = try WipMembers.init(gpa, &astgen.scratch, @intCast(u32, counts.decls), @intCast(u32, counts.total_fields), bits_per_field, max_field_size); |
| 4177 | defer wip_members.deinit(); |
| 4171 | 4178 | |
| 4172 | 4179 | for (container_decl.ast.members) |member_node| { |
| 4173 | 4180 | if (member_node == counts.nonexhaustive_node) |
| ... | ... | @@ -4244,8 +4251,8 @@ fn containerDecl( |
| 4244 | 4251 | |
| 4245 | 4252 | const decl_count = try astgen.scanDecls(&namespace, container_decl.ast.members); |
| 4246 | 4253 | |
| 4247 | | var wip_members = try WipMembers.init(gpa, decl_count, 0, 0, 0); |
| 4248 | | defer wip_members.deinit(gpa); |
| 4254 | var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, 0, 0, 0); |
| 4255 | defer wip_members.deinit(); |
| 4249 | 4256 | |
| 4250 | 4257 | for (container_decl.ast.members) |member_node| { |
| 4251 | 4258 | _ = try containerMember(gz, &namespace.base, &wip_members, member_node); |
| ... | ... | @@ -5579,12 +5586,14 @@ fn switchExpr( |
| 5579 | 5586 | // This contains the data that goes into the `extra` array for the SwitchBlock/SwitchBlockMulti, |
| 5580 | 5587 | // except the first cases_nodes.len slots are a table that indexes payloads later in the array, with |
| 5581 | 5588 | // the special case index coming first, then scalar_case_len indexes, then multi_cases_len indexes |
| 5582 | | var payloads = ArrayListUnmanaged(u32){}; |
| 5583 | | defer payloads.deinit(gpa); |
| 5584 | | const scalar_case_table: u32 = @boolToInt(special_prong != .none); |
| 5589 | const payloads = &astgen.scratch; |
| 5590 | const scratch_top = astgen.scratch.items.len; |
| 5591 | const case_table_start = scratch_top; |
| 5592 | const scalar_case_table = case_table_start + @boolToInt(special_prong != .none); |
| 5585 | 5593 | const multi_case_table = scalar_case_table + scalar_cases_len; |
| 5586 | | const case_table_len = multi_case_table + multi_cases_len; |
| 5587 | | try payloads.resize(gpa, case_table_len); |
| 5594 | const case_table_end = multi_case_table + multi_cases_len; |
| 5595 | try astgen.scratch.resize(gpa, case_table_end); |
| 5596 | defer astgen.scratch.items.len = scratch_top; |
| 5588 | 5597 | |
| 5589 | 5598 | var block_scope = parent_gz.makeSubBlock(scope); |
| 5590 | 5599 | block_scope.setBreakResultLoc(rl); |
| ... | ... | @@ -5702,7 +5711,7 @@ fn switchExpr( |
| 5702 | 5711 | payloads.items[header_index + 1] = ranges_len; |
| 5703 | 5712 | break :blk header_index + 2; |
| 5704 | 5713 | } else if (case_node == special_node) blk: { |
| 5705 | | payloads.items[0] = header_index; |
| 5714 | payloads.items[case_table_start] = header_index; |
| 5706 | 5715 | try payloads.resize(gpa, header_index + 1); // body_len |
| 5707 | 5716 | break :blk header_index; |
| 5708 | 5717 | } else blk: { |
| ... | ... | @@ -5729,7 +5738,7 @@ fn switchExpr( |
| 5729 | 5738 | |
| 5730 | 5739 | try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.SwitchBlock).Struct.fields.len + |
| 5731 | 5740 | @boolToInt(multi_cases_len != 0) + |
| 5732 | | payloads.items.len - case_table_len); |
| 5741 | payloads.items.len - case_table_end); |
| 5733 | 5742 | |
| 5734 | 5743 | const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.SwitchBlock{ |
| 5735 | 5744 | .operand = cond, |
| ... | ... | @@ -5752,9 +5761,10 @@ fn switchExpr( |
| 5752 | 5761 | zir_datas[switch_block].pl_node.payload_index = payload_index; |
| 5753 | 5762 | |
| 5754 | 5763 | const strat = rl.strategy(&block_scope); |
| 5755 | | for (payloads.items[0..case_table_len]) |start_index, table_index| { |
| 5764 | for (payloads.items[case_table_start..case_table_end]) |start_index, i| { |
| 5756 | 5765 | var body_len_index = start_index; |
| 5757 | 5766 | var end_index = start_index; |
| 5767 | const table_index = case_table_start + i; |
| 5758 | 5768 | if (table_index < scalar_case_table) { |
| 5759 | 5769 | end_index += 1; |
| 5760 | 5770 | } else if (table_index < multi_case_table) { |