AstGen: implement align and linksection on globals

This commit is contained in:
Andrew Kelley
2021-04-22 19:21:33 -07:00
parent 507a8096d2
commit 329a359974
2 changed files with 135 additions and 87 deletions

View File

@@ -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);
},

View File

@@ -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;