authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-29 16:57:13-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-29 16:57:13-07:00
log55e86b724a2ce60b777bd94d1203f243435727b7
treecf799707230163746c9642c04a6545fd96a57657
parentfb4cb430e096d3142eeedb129425b01e80442516

AstGen: implement comptime struct fields


5 files changed, 50 insertions(+), 19 deletions(-)

BRANCH_TODO+4
......@@ -52,6 +52,10 @@
5252 - not sure why this happened, it's stage1 code??
5353 - search the behavior test diff for "TODO"
5454
55 * memory efficiency: add another representation for structs which use
56 natural alignment for fields and do not have any comptime fields. this
57 will save 16 bytes per struct field in the compilation.
58
5559fn getAnonTypeName(mod: *Module, scope: *Scope, base_token: std.zig.ast.TokenIndex) ![]u8 {
5660 // TODO add namespaces, generic function signatrues
5761 const tree = scope.tree();
src/AstGen.zig+16-11
......@@ -3220,7 +3220,9 @@ fn structDeclInner(
32203220 var fields_data = ArrayListUnmanaged(u32){};
32213221 defer fields_data.deinit(gpa);
32223222
3223 // We only need this if there are greater than 16 fields.
3223 const bits_per_field = 4;
3224 const fields_per_u32 = 32 / bits_per_field;
3225 // We only need this if there are greater than fields_per_u32 fields.
32243226 var bit_bag = ArrayListUnmanaged(u32){};
32253227 defer bit_bag.deinit(gpa);
32263228
......@@ -3307,13 +3309,10 @@ fn structDeclInner(
33073309 },
33083310 else => unreachable,
33093311 };
3310 if (field_index % 16 == 0 and field_index != 0) {
3312 if (field_index % fields_per_u32 == 0 and field_index != 0) {
33113313 try bit_bag.append(gpa, cur_bit_bag);
33123314 cur_bit_bag = 0;
33133315 }
3314 if (member.comptime_token) |comptime_token| {
3315 return astgen.failTok(comptime_token, "TODO implement comptime struct fields", .{});
3316 }
33173316 try fields_data.ensureUnusedCapacity(gpa, 4);
33183317
33193318 const field_name = try gz.identAsString(member.ast.name_token);
......@@ -3324,9 +3323,13 @@ fn structDeclInner(
33243323
33253324 const have_align = member.ast.align_expr != 0;
33263325 const have_value = member.ast.value_expr != 0;
3327 cur_bit_bag = (cur_bit_bag >> 2) |
3328 (@as(u32, @boolToInt(have_align)) << 30) |
3329 (@as(u32, @boolToInt(have_value)) << 31);
3326 const is_comptime = member.comptime_token != null;
3327 const unused = false;
3328 cur_bit_bag = (cur_bit_bag >> bits_per_field) |
3329 (@as(u32, @boolToInt(have_align)) << 28) |
3330 (@as(u32, @boolToInt(have_value)) << 29) |
3331 (@as(u32, @boolToInt(is_comptime)) << 30) |
3332 (@as(u32, @boolToInt(unused)) << 31);
33303333
33313334 if (have_align) {
33323335 const align_inst = try expr(&block_scope, &block_scope.base, align_rl, member.ast.align_expr);
......@@ -3335,14 +3338,16 @@ fn structDeclInner(
33353338 if (have_value) {
33363339 const default_inst = try expr(&block_scope, &block_scope.base, .{ .ty = field_type }, member.ast.value_expr);
33373340 fields_data.appendAssumeCapacity(@enumToInt(default_inst));
3341 } else if (member.comptime_token) |comptime_token| {
3342 return astgen.failTok(comptime_token, "comptime field without default initialization value", .{});
33383343 }
33393344
33403345 field_index += 1;
33413346 }
33423347 {
3343 const empty_slot_count = 16 - (field_index % 16);
3344 if (empty_slot_count < 16) {
3345 cur_bit_bag >>= @intCast(u5, empty_slot_count * 2);
3348 const empty_slot_count = fields_per_u32 - (field_index % fields_per_u32);
3349 if (empty_slot_count < fields_per_u32) {
3350 cur_bit_bag >>= @intCast(u5, empty_slot_count * bits_per_field);
33463351 }
33473352 }
33483353 {
src/Module.zig+1
......@@ -471,6 +471,7 @@ pub const Struct = struct {
471471 abi_align: Value,
472472 /// Uses `unreachable_value` to indicate no default.
473473 default_val: Value,
474 is_comptime: bool,
474475 };
475476
476477 pub fn getFullyQualifiedName(s: *Struct, gpa: *Allocator) ![]u8 {
src/Sema.zig+11-2
......@@ -719,14 +719,16 @@ pub fn zirStructDecl(
719719 sema.branch_count = struct_sema.branch_count;
720720 sema.branch_quota = struct_sema.branch_quota;
721721 }
722 const bit_bags_count = std.math.divCeil(usize, fields_len, 16) catch unreachable;
722 const bits_per_field = 4;
723 const fields_per_u32 = 32 / bits_per_field;
724 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
723725 const body_end = extra_index + body.len;
724726 extra_index += bit_bags_count;
725727 var bit_bag_index: usize = body_end;
726728 var cur_bit_bag: u32 = undefined;
727729 var field_i: u32 = 0;
728730 while (field_i < fields_len) : (field_i += 1) {
729 if (field_i % 16 == 0) {
731 if (field_i % fields_per_u32 == 0) {
730732 cur_bit_bag = sema.code.extra[bit_bag_index];
731733 bit_bag_index += 1;
732734 }
......@@ -734,6 +736,12 @@ pub fn zirStructDecl(
734736 cur_bit_bag >>= 1;
735737 const has_default = @truncate(u1, cur_bit_bag) != 0;
736738 cur_bit_bag >>= 1;
739 const is_comptime = @truncate(u1, cur_bit_bag) != 0;
740 cur_bit_bag >>= 1;
741 const unused = @truncate(u1, cur_bit_bag) != 0;
742 cur_bit_bag >>= 1;
743
744 _ = unused;
737745
738746 const field_name_zir = sema.code.nullTerminatedString(sema.code.extra[extra_index]);
739747 extra_index += 1;
......@@ -753,6 +761,7 @@ pub fn zirStructDecl(
753761 .ty = field_ty,
754762 .abi_align = Value.initTag(.abi_align_default),
755763 .default_val = Value.initTag(.unreachable_value),
764 .is_comptime = is_comptime,
756765 };
757766
758767 if (has_align) {
src/Zir.zig+18-6
......@@ -2387,13 +2387,16 @@ pub const Inst = struct {
23872387 /// link_section: Ref, // if corresponding bit is set
23882388 /// }
23892389 /// 2. inst: Index // for every body_len
2390 /// 3. has_bits: u32 // for every 16 fields
2391 /// - sets of 2 bits:
2392 /// 0b0X: whether corresponding field has an align expression
2393 /// 0bX0: whether corresponding field has a default expression
2390 /// 3. flags: u32 // for every 8 fields
2391 /// - sets of 4 bits:
2392 /// 0b000X: whether corresponding field has an align expression
2393 /// 0b00X0: whether corresponding field has a default expression
2394 /// 0b0X00: whether corresponding field is comptime
2395 /// 0bX000: unused
23942396 /// 4. fields: { // for every fields_len
23952397 /// field_name: u32,
23962398 /// field_type: Ref,
2399 /// - if none, means `anytype`.
23972400 /// align: Ref, // if corresponding bit is set
23982401 /// default_value: Ref, // if corresponding bit is set
23992402 /// }
......@@ -3394,14 +3397,16 @@ const Writer = struct {
33943397 try stream.writeAll("}, {\n");
33953398 }
33963399
3397 const bit_bags_count = std.math.divCeil(usize, fields_len, 16) catch unreachable;
3400 const bits_per_field = 4;
3401 const fields_per_u32 = 32 / bits_per_field;
3402 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
33983403 const body_end = extra_index;
33993404 extra_index += bit_bags_count;
34003405 var bit_bag_index: usize = body_end;
34013406 var cur_bit_bag: u32 = undefined;
34023407 var field_i: u32 = 0;
34033408 while (field_i < fields_len) : (field_i += 1) {
3404 if (field_i % 16 == 0) {
3409 if (field_i % fields_per_u32 == 0) {
34053410 cur_bit_bag = self.code.extra[bit_bag_index];
34063411 bit_bag_index += 1;
34073412 }
......@@ -3409,6 +3414,12 @@ const Writer = struct {
34093414 cur_bit_bag >>= 1;
34103415 const has_default = @truncate(u1, cur_bit_bag) != 0;
34113416 cur_bit_bag >>= 1;
3417 const is_comptime = @truncate(u1, cur_bit_bag) != 0;
3418 cur_bit_bag >>= 1;
3419 const unused = @truncate(u1, cur_bit_bag) != 0;
3420 cur_bit_bag >>= 1;
3421
3422 _ = unused;
34123423
34133424 const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
34143425 extra_index += 1;
......@@ -3416,6 +3427,7 @@ const Writer = struct {
34163427 extra_index += 1;
34173428
34183429 try stream.writeByteNTimes(' ', self.indent);
3430 try self.writeFlag(stream, "comptime ", is_comptime);
34193431 try stream.print("{}: ", .{std.zig.fmtId(field_name)});
34203432 try self.writeInstRef(stream, field_type);
34213433