diff --git a/src/AstGen.zig b/src/AstGen.zig index 2d34a938a7..1d9cf23c39 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -2482,11 +2482,14 @@ const WipDecls = struct { decl_index: usize = 0, cur_bit_bag: u32 = 0, bit_bag: ArrayListUnmanaged(u32) = .{}, - name_and_value: ArrayListUnmanaged(u32) = .{}, + payload: ArrayListUnmanaged(u32) = .{}, + + const bits_per_field = 4; + const fields_per_u32 = 32 / bits_per_field; fn deinit(wip_decls: *WipDecls, gpa: *Allocator) void { wip_decls.bit_bag.deinit(gpa); - wip_decls.name_and_value.deinit(gpa); + wip_decls.payload.deinit(gpa); } }; @@ -2501,6 +2504,15 @@ fn fnDecl( const tree = &astgen.file.tree; const token_tags = tree.tokens.items(.tag); + var decl_gz: GenZir = .{ + .force_comptime = true, + .decl_node_index = fn_proto.ast.proto_node, + .parent = &gz.base, + .astgen = astgen, + .ref_start_index = @intCast(u32, Zir.Inst.Ref.typed_value_map.len), + }; + defer decl_gz.instructions.deinit(gpa); + const is_pub = fn_proto.visib_token != null; const is_export = blk: { const maybe_export_token = fn_proto.extern_export_token orelse break :blk false; @@ -2510,13 +2522,22 @@ fn fnDecl( const maybe_extern_token = fn_proto.extern_export_token orelse break :blk false; break :blk token_tags[maybe_extern_token] == .keyword_extern; }; - if (wip_decls.decl_index % 16 == 0 and wip_decls.decl_index != 0) { + const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: { + break :inst try expr(&decl_gz, &decl_gz.base, align_rl, fn_proto.ast.align_expr); + }; + const section_inst: Zir.Inst.Ref = if (fn_proto.ast.section_expr == 0) .none else inst: { + break :inst try comptimeExpr(&decl_gz, &decl_gz.base, .{ .ty = .const_slice_u8_type }, fn_proto.ast.section_expr); + }; + + if (wip_decls.decl_index % WipDecls.fields_per_u32 == 0 and wip_decls.decl_index != 0) { try wip_decls.bit_bag.append(gpa, wip_decls.cur_bit_bag); wip_decls.cur_bit_bag = 0; } - wip_decls.cur_bit_bag = (wip_decls.cur_bit_bag >> 2) | - (@as(u32, @boolToInt(is_pub)) << 30) | - (@as(u32, @boolToInt(is_export)) << 31); + wip_decls.cur_bit_bag = (wip_decls.cur_bit_bag >> WipDecls.bits_per_field) | + (@as(u32, @boolToInt(is_pub)) << 28) | + (@as(u32, @boolToInt(is_export)) << 29) | + (@as(u32, @boolToInt(align_inst != .none)) << 30) | + (@as(u32, @boolToInt(section_inst != .none)) << 31); wip_decls.decl_index += 1; // The AST params array does not contain anytype and ... parameters. @@ -2537,15 +2558,6 @@ fn fnDecl( const param_types = try gpa.alloc(Zir.Inst.Ref, param_count); defer gpa.free(param_types); - var decl_gz: GenZir = .{ - .force_comptime = true, - .decl_node_index = fn_proto.ast.proto_node, - .parent = &gz.base, - .astgen = astgen, - .ref_start_index = @intCast(u32, Zir.Inst.Ref.typed_value_map.len), - }; - defer decl_gz.instructions.deinit(gpa); - var is_var_args = false; { var param_type_i: usize = 0; @@ -2577,21 +2589,6 @@ fn fnDecl( break :blk lib_name_str.index; } else 0; - if (fn_proto.ast.align_expr != 0) { - return astgen.failNode( - fn_proto.ast.align_expr, - "TODO implement function align expression", - .{}, - ); - } - if (fn_proto.ast.section_expr != 0) { - return astgen.failNode( - fn_proto.ast.section_expr, - "TODO implement function section expression", - .{}, - ); - } - const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1; const is_inferred_error = token_tags[maybe_bang] == .bang; @@ -2713,9 +2710,15 @@ fn fnDecl( _ = try decl_gz.addBreak(.break_inline, block_inst, func_inst); try decl_gz.setBlockBody(block_inst); - try wip_decls.name_and_value.ensureCapacity(gpa, wip_decls.name_and_value.items.len + 2); - wip_decls.name_and_value.appendAssumeCapacity(fn_name_str_index); - wip_decls.name_and_value.appendAssumeCapacity(block_inst); + try wip_decls.payload.ensureUnusedCapacity(gpa, 4); + wip_decls.payload.appendAssumeCapacity(fn_name_str_index); + wip_decls.payload.appendAssumeCapacity(block_inst); + if (align_inst != .none) { + wip_decls.payload.appendAssumeCapacity(@enumToInt(align_inst)); + } + if (section_inst != .none) { + wip_decls.payload.appendAssumeCapacity(@enumToInt(section_inst)); + } } fn globalVarDecl( @@ -2730,6 +2733,14 @@ fn globalVarDecl( const tree = &astgen.file.tree; const token_tags = tree.tokens.items(.tag); + var block_scope: GenZir = .{ + .parent = scope, + .decl_node_index = node, + .astgen = astgen, + .force_comptime = true, + }; + defer block_scope.instructions.deinit(gpa); + const is_pub = var_decl.visib_token != null; const is_export = blk: { const maybe_export_token = var_decl.extern_export_token orelse break :blk false; @@ -2739,13 +2750,21 @@ fn globalVarDecl( const maybe_extern_token = var_decl.extern_export_token orelse break :blk false; break :blk token_tags[maybe_extern_token] == .keyword_extern; }; - if (wip_decls.decl_index % 16 == 0 and wip_decls.decl_index != 0) { + const align_inst: Zir.Inst.Ref = if (var_decl.ast.align_node == 0) .none else inst: { + break :inst try expr(&block_scope, &block_scope.base, align_rl, var_decl.ast.align_node); + }; + const section_inst: Zir.Inst.Ref = if (var_decl.ast.section_node == 0) .none else inst: { + break :inst try comptimeExpr(&block_scope, &block_scope.base, .{ .ty = .const_slice_u8_type }, var_decl.ast.section_node); + }; + if (wip_decls.decl_index % WipDecls.fields_per_u32 == 0 and wip_decls.decl_index != 0) { try wip_decls.bit_bag.append(gpa, wip_decls.cur_bit_bag); wip_decls.cur_bit_bag = 0; } - wip_decls.cur_bit_bag = (wip_decls.cur_bit_bag >> 2) | - (@as(u32, @boolToInt(is_pub)) << 30) | - (@as(u32, @boolToInt(is_export)) << 31); + wip_decls.cur_bit_bag = (wip_decls.cur_bit_bag >> WipDecls.bits_per_field) | + (@as(u32, @boolToInt(is_pub)) << 28) | + (@as(u32, @boolToInt(is_export)) << 29) | + (@as(u32, @boolToInt(align_inst != .none)) << 30) | + (@as(u32, @boolToInt(section_inst != .none)) << 31); wip_decls.decl_index += 1; const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var; @@ -2762,12 +2781,6 @@ fn globalVarDecl( } else 0; assert(var_decl.comptime_token == null); // handled by parser - if (var_decl.ast.align_node != 0) { - return astgen.failNode(var_decl.ast.align_node, "TODO implement alignment on globals", .{}); - } - if (var_decl.ast.section_node != 0) { - return astgen.failNode(var_decl.ast.section_node, "TODO linksection on globals", .{}); - } const var_inst: Zir.Inst.Index = if (var_decl.ast.init_node != 0) vi: { if (is_extern) { @@ -2778,14 +2791,6 @@ fn globalVarDecl( ); } - var block_scope: GenZir = .{ - .parent = scope, - .decl_node_index = node, - .astgen = astgen, - .force_comptime = true, - }; - defer block_scope.instructions.deinit(gpa); - const init_result_loc: AstGen.ResultLoc = if (var_decl.ast.type_node != 0) .{ .ty = try expr( &block_scope, @@ -2812,7 +2817,7 @@ fn globalVarDecl( } else if (var_decl.ast.type_node != 0) { // Extern variable which has an explicit type. - const type_inst = try typeExpr(gz, scope, var_decl.ast.type_node); + const type_inst = try typeExpr(&block_scope, &block_scope.base, var_decl.ast.type_node); return astgen.failNode(node, "TODO AstGen extern global variable", .{}); } else { @@ -2822,9 +2827,15 @@ fn globalVarDecl( const name_token = var_decl.ast.mut_token + 1; const name_str_index = try gz.identAsString(name_token); - try wip_decls.name_and_value.ensureCapacity(gpa, wip_decls.name_and_value.items.len + 2); - wip_decls.name_and_value.appendAssumeCapacity(name_str_index); - wip_decls.name_and_value.appendAssumeCapacity(var_inst); + try wip_decls.payload.ensureUnusedCapacity(gpa, 4); + wip_decls.payload.appendAssumeCapacity(name_str_index); + wip_decls.payload.appendAssumeCapacity(var_inst); + if (align_inst != .none) { + wip_decls.payload.appendAssumeCapacity(@enumToInt(align_inst)); + } + if (section_inst != .none) { + wip_decls.payload.appendAssumeCapacity(@enumToInt(section_inst)); + } } fn comptimeDecl( @@ -3080,7 +3091,7 @@ fn structDeclInner( (@as(u32, @boolToInt(have_value)) << 31); if (have_align) { - const align_inst = try expr(&block_scope, &block_scope.base, .{ .ty = .u32_type }, member.ast.align_expr); + const align_inst = try expr(&block_scope, &block_scope.base, align_rl, member.ast.align_expr); fields_data.appendAssumeCapacity(@enumToInt(align_inst)); } if (have_value) { @@ -3097,9 +3108,9 @@ fn structDeclInner( } } { - const empty_slot_count = 16 - (wip_decls.decl_index % 16); - if (empty_slot_count < 16) { - wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * 2); + const empty_slot_count = WipDecls.fields_per_u32 - (wip_decls.decl_index % WipDecls.fields_per_u32); + if (empty_slot_count < WipDecls.fields_per_u32) { + wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * WipDecls.bits_per_field); } } @@ -3113,7 +3124,7 @@ fn structDeclInner( bit_bag.items.len + @boolToInt(field_index != 0) + fields_data.items.len + block_scope.instructions.items.len + wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) + - wip_decls.name_and_value.items.len); + wip_decls.payload.items.len); const zir_datas = astgen.instructions.items(.data); zir_datas[decl_inst].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.StructDecl{ .body_len = @intCast(u32, block_scope.instructions.items.len), @@ -3132,7 +3143,7 @@ fn structDeclInner( if (wip_decls.decl_index != 0) { astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag); } - astgen.extra.appendSliceAssumeCapacity(wip_decls.name_and_value.items); + astgen.extra.appendSliceAssumeCapacity(wip_decls.payload.items); return gz.indexToRef(decl_inst); } @@ -3321,9 +3332,9 @@ fn unionDeclInner( } } { - const empty_slot_count = 16 - (wip_decls.decl_index % 16); - if (empty_slot_count < 16) { - wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * 2); + const empty_slot_count = WipDecls.fields_per_u32 - (wip_decls.decl_index % WipDecls.fields_per_u32); + if (empty_slot_count < WipDecls.fields_per_u32) { + wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * WipDecls.bits_per_field); } } @@ -3337,7 +3348,7 @@ fn unionDeclInner( bit_bag.items.len + 1 + fields_data.items.len + block_scope.instructions.items.len + wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) + - wip_decls.name_and_value.items.len); + wip_decls.payload.items.len); const zir_datas = astgen.instructions.items(.data); zir_datas[decl_inst].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.UnionDecl{ .tag_type = arg_inst, @@ -3355,7 +3366,7 @@ fn unionDeclInner( if (wip_decls.decl_index != 0) { astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag); } - astgen.extra.appendSliceAssumeCapacity(wip_decls.name_and_value.items); + astgen.extra.appendSliceAssumeCapacity(wip_decls.payload.items); return gz.indexToRef(decl_inst); } @@ -3653,9 +3664,9 @@ fn containerDecl( } } { - const empty_slot_count = 16 - (wip_decls.decl_index % 16); - if (empty_slot_count < 16) { - wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * 2); + const empty_slot_count = WipDecls.fields_per_u32 - (wip_decls.decl_index % WipDecls.fields_per_u32); + if (empty_slot_count < WipDecls.fields_per_u32) { + wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * WipDecls.bits_per_field); } } @@ -3669,7 +3680,7 @@ fn containerDecl( bit_bag.items.len + 1 + fields_data.items.len + block_scope.instructions.items.len + wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) + - wip_decls.name_and_value.items.len); + wip_decls.payload.items.len); const zir_datas = astgen.instructions.items(.data); zir_datas[decl_inst].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.EnumDecl{ .tag_type = arg_inst, @@ -3686,7 +3697,7 @@ fn containerDecl( if (wip_decls.decl_index != 0) { astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag); } - astgen.extra.appendSliceAssumeCapacity(wip_decls.name_and_value.items); + astgen.extra.appendSliceAssumeCapacity(wip_decls.payload.items); return rvalue(gz, scope, rl, gz.indexToRef(decl_inst), node); }, diff --git a/src/Zir.zig b/src/Zir.zig index 485d72992e..ce1b64191a 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -2021,13 +2021,17 @@ pub const Inst = struct { /// align: Ref, // if corresponding bit is set /// default_value: Ref, // if corresponding bit is set /// } - /// 3. decl_bits: u32 // for every 16 decls - /// - sets of 2 bits: - /// 0b0X: whether corresponding decl is pub - /// 0bX0: whether corresponding decl is exported + /// 3. decl_bits: u32 // for every 8 decls + /// - sets of 4 bits: + /// 0b000X: whether corresponding decl is pub + /// 0b00X0: whether corresponding decl is exported + /// 0b0X00: whether corresponding decl has an align expression + /// 0bX000: whether corresponding decl has a linksection expression /// 4. decl: { // for every decls_len /// name: u32, // null terminated string index /// value: Index, + /// align: Ref, // if corresponding bit is set + /// link_section: Ref, // if corresponding bit is set /// } pub const StructDecl = struct { body_len: u32, @@ -2043,13 +2047,17 @@ pub const Inst = struct { /// field_name: u32, /// value: Ref, // if corresponding bit is set /// } - /// 3. decl_bits: u32 // for every 16 decls - /// - sets of 2 bits: - /// 0b0X: whether corresponding decl is pub - /// 0bX0: whether corresponding decl is exported + /// 3. decl_bits: u32 // for every 8 decls + /// - sets of 4 bits: + /// 0b000X: whether corresponding decl is pub + /// 0b00X0: whether corresponding decl is exported + /// 0b0X00: whether corresponding decl has an align expression + /// 0bX000: whether corresponding decl has a linksection expression /// 4. decl: { // for every decls_len /// name: u32, // null terminated string index /// value: Index, + /// align: Ref, // if corresponding bit is set + /// link_section: Ref, // if corresponding bit is set /// } pub const EnumDecl = struct { /// Can be `Ref.none`. @@ -2077,13 +2085,17 @@ pub const Inst = struct { /// align: Ref, // if corresponding bit is set /// tag_value: Ref, // if corresponding bit is set /// } - /// 3. decl_bits: u32 // for every 16 decls - /// - sets of 2 bits: - /// 0b0X: whether corresponding decl is pub - /// 0bX0: whether corresponding decl is exported + /// 3. decl_bits: u32 // for every 8 decls + /// - sets of 4 bits: + /// 0b000X: whether corresponding decl is pub + /// 0b00X0: whether corresponding decl is exported + /// 0b0X00: whether corresponding decl has an align expression + /// 0bX000: whether corresponding decl has a linksection expression /// 4. decl: { // for every decls_len /// name: u32, // null terminated string index /// value: Index, + /// align: Ref, // if corresponding bit is set + /// link_section: Ref, // if corresponding bit is set /// } pub const UnionDecl = struct { /// Can be `Ref.none`. @@ -3072,13 +3084,13 @@ const Writer = struct { fn writeDecls(self: *Writer, stream: anytype, decls_len: u32, extra_start: usize) !void { const parent_decl_node = self.parent_decl_node; - const bit_bags_count = std.math.divCeil(usize, decls_len, 16) catch unreachable; + const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable; var extra_index = extra_start + bit_bags_count; var bit_bag_index: usize = extra_start; var cur_bit_bag: u32 = undefined; var decl_i: u32 = 0; while (decl_i < decls_len) : (decl_i += 1) { - if (decl_i % 16 == 0) { + if (decl_i % 8 == 0) { cur_bit_bag = self.code.extra[bit_bag_index]; bit_bag_index += 1; } @@ -3086,19 +3098,44 @@ const Writer = struct { cur_bit_bag >>= 1; const is_exported = @truncate(u1, cur_bit_bag) != 0; cur_bit_bag >>= 1; + const has_align = @truncate(u1, cur_bit_bag) != 0; + cur_bit_bag >>= 1; + const has_section = @truncate(u1, cur_bit_bag) != 0; + cur_bit_bag >>= 1; const decl_name = self.code.nullTerminatedString(self.code.extra[extra_index]); extra_index += 1; const decl_index = self.code.extra[extra_index]; extra_index += 1; + const align_inst: Inst.Ref = if (!has_align) .none else inst: { + const inst = @intToEnum(Inst.Ref, self.code.extra[extra_index]); + extra_index += 1; + break :inst inst; + }; + const section_inst: Inst.Ref = if (!has_section) .none else inst: { + const inst = @intToEnum(Inst.Ref, self.code.extra[extra_index]); + extra_index += 1; + break :inst inst; + }; const tag = self.code.instructions.items(.tag)[decl_index]; const pub_str = if (is_pub) "pub " else ""; const export_str = if (is_exported) "export " else ""; try stream.writeByteNTimes(' ', self.indent); - try stream.print("{s}{s}{}: %{d} = {s}(", .{ - pub_str, export_str, std.zig.fmtId(decl_name), decl_index, @tagName(tag), + try stream.print("{s}{s}{}", .{ + pub_str, export_str, std.zig.fmtId(decl_name), }); + if (align_inst != .none) { + try stream.writeAll(" align("); + try self.writeInstRef(stream, align_inst); + try stream.writeAll(")"); + } + if (section_inst != .none) { + try stream.writeAll(" linksection("); + try self.writeInstRef(stream, section_inst); + try stream.writeAll(")"); + } + try stream.print(": %{d} = {s}(", .{ decl_index, @tagName(tag) }); const decl_block_inst_data = self.code.instructions.items(.data)[decl_index].pl_node; const sub_decl_node_off = decl_block_inst_data.src_node;