authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-11-16 15:46:43+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-11-20 20:25:11+02:00
loge5a3eb9777ff165d936b0811f3825eabb8bcd6a4
tree15b67ec852dc6b41d1b54a1039bcdd6581aa0449
parent44f8714dfb69fac2e8c7a6a35ad9f2abe7c4513a

Type: make `hasRuntimeBitsAdvanced` take `AbiAlignmentAdvancedStrat`

I wasn't able to create a reduced test case for this but the reasoning can be seen in `abiAlignmentAdvancedUnion` where if `strat` was lazy `hasRuntimeBitsAdvanced` would be given `null` instead of `sema` which would cause eager evaluation when it is not valid or desired.

4 files changed, 81 insertions(+), 37 deletions(-)

src/Sema.zig+5-2
...@@ -128,7 +128,7 @@ pub const Block = struct {...@@ -128,7 +128,7 @@ pub const Block = struct {
128 /// Shared among all child blocks.128 /// Shared among all child blocks.
129 sema: *Sema,129 sema: *Sema,
130 /// The namespace to use for lookups from this source block130 /// The namespace to use for lookups from this source block
131 /// When analyzing fields, this is different from src_decl.src_namepsace.131 /// When analyzing fields, this is different from src_decl.src_namespace.
132 namespace: *Namespace,132 namespace: *Namespace,
133 /// The AIR instructions generated for this block.133 /// The AIR instructions generated for this block.
134 instructions: std.ArrayListUnmanaged(Air.Inst.Index),134 instructions: std.ArrayListUnmanaged(Air.Inst.Index),
...@@ -31298,7 +31298,10 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {...@@ -31298,7 +31298,10 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
31298}31298}
3129931299
31300pub fn typeHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool {31300pub fn typeHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool {
31301 return ty.hasRuntimeBitsAdvanced(false, sema);31301 return ty.hasRuntimeBitsAdvanced(false, .{ .sema = sema }) catch |err| switch (err) {
31302 error.NeedLazy => unreachable,
31303 else => |e| return e,
31304 };
31302}31305}
3130331306
31304fn typeAbiSize(sema: *Sema, ty: Type) !u64 {31307fn typeAbiSize(sema: *Sema, ty: Type) !u64 {
src/print_zir.zig+17-1
...@@ -262,9 +262,10 @@ const Writer = struct {...@@ -262,9 +262,10 @@ const Writer = struct {
262 => try self.writeBreak(stream, inst),262 => try self.writeBreak(stream, inst),
263 .array_init,263 .array_init,
264 .array_init_ref,264 .array_init_ref,
265 => try self.writeArrayInit(stream, inst),
265 .array_init_anon,266 .array_init_anon,
266 .array_init_anon_ref,267 .array_init_anon_ref,
267 => try self.writeArrayInit(stream, inst),268 => try self.writeArrayInitAnon(stream, inst),
268269
269 .slice_start => try self.writeSliceStart(stream, inst),270 .slice_start => try self.writeSliceStart(stream, inst),
270 .slice_end => try self.writeSliceEnd(stream, inst),271 .slice_end => try self.writeSliceEnd(stream, inst),
...@@ -2316,6 +2317,21 @@ const Writer = struct {...@@ -2316,6 +2317,21 @@ const Writer = struct {
2316 try self.writeSrc(stream, inst_data.src());2317 try self.writeSrc(stream, inst_data.src());
2317 }2318 }
23182319
2320 fn writeArrayInitAnon(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2321 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2322
2323 const extra = self.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
2324 const args = self.code.refSlice(extra.end, extra.data.operands_len);
2325
2326 try stream.writeAll("{");
2327 for (args) |arg, i| {
2328 if (i != 0) try stream.writeAll(", ");
2329 try self.writeInstRef(stream, arg);
2330 }
2331 try stream.writeAll("}) ");
2332 try self.writeSrc(stream, inst_data.src());
2333 }
2334
2319 fn writeArrayInitSent(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {2335 fn writeArrayInitSent(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2320 const inst_data = self.code.instructions.items(.data)[inst].pl_node;2336 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
23212337
src/type.zig+49-32
...@@ -2312,6 +2312,8 @@ pub const Type = extern union {...@@ -2312,6 +2312,8 @@ pub const Type = extern union {
2312 }2312 }
2313 }2313 }
23142314
2315 const RuntimeBitsError = Module.CompileError || error{NeedLazy};
2316
2315 /// true if and only if the type takes up space in memory at runtime.2317 /// true if and only if the type takes up space in memory at runtime.
2316 /// There are two reasons a type will return false:2318 /// There are two reasons a type will return false:
2317 /// * the type is a comptime-only type. For example, the type `type` itself.2319 /// * the type is a comptime-only type. For example, the type `type` itself.
...@@ -2326,8 +2328,8 @@ pub const Type = extern union {...@@ -2326,8 +2328,8 @@ pub const Type = extern union {
2326 pub fn hasRuntimeBitsAdvanced(2328 pub fn hasRuntimeBitsAdvanced(
2327 ty: Type,2329 ty: Type,
2328 ignore_comptime_only: bool,2330 ignore_comptime_only: bool,
2329 opt_sema: ?*Sema,2331 strat: AbiAlignmentAdvancedStrat,
2330 ) Module.CompileError!bool {2332 ) RuntimeBitsError!bool {
2331 switch (ty.tag()) {2333 switch (ty.tag()) {
2332 .u1,2334 .u1,
2333 .u8,2335 .u8,
...@@ -2406,8 +2408,8 @@ pub const Type = extern union {...@@ -2406,8 +2408,8 @@ pub const Type = extern union {
2406 return true;2408 return true;
2407 } else if (ty.childType().zigTypeTag() == .Fn) {2409 } else if (ty.childType().zigTypeTag() == .Fn) {
2408 return !ty.childType().fnInfo().is_generic;2410 return !ty.childType().fnInfo().is_generic;
2409 } else if (opt_sema) |sema| {2411 } else if (strat == .sema) {
2410 return !(try sema.typeRequiresComptime(ty));2412 return !(try strat.sema.typeRequiresComptime(ty));
2411 } else {2413 } else {
2412 return !comptimeOnly(ty);2414 return !comptimeOnly(ty);
2413 }2415 }
...@@ -2445,8 +2447,8 @@ pub const Type = extern union {...@@ -2445,8 +2447,8 @@ pub const Type = extern union {
2445 }2447 }
2446 if (ignore_comptime_only) {2448 if (ignore_comptime_only) {
2447 return true;2449 return true;
2448 } else if (opt_sema) |sema| {2450 } else if (strat == .sema) {
2449 return !(try sema.typeRequiresComptime(child_ty));2451 return !(try strat.sema.typeRequiresComptime(child_ty));
2450 } else {2452 } else {
2451 return !comptimeOnly(child_ty);2453 return !comptimeOnly(child_ty);
2452 }2454 }
...@@ -2459,13 +2461,14 @@ pub const Type = extern union {...@@ -2459,13 +2461,14 @@ pub const Type = extern union {
2459 // and then later if our guess was incorrect, we emit a compile error.2461 // and then later if our guess was incorrect, we emit a compile error.
2460 return true;2462 return true;
2461 }2463 }
2462 if (opt_sema) |sema| {2464 switch (strat) {
2463 _ = try sema.resolveTypeFields(ty);2465 .sema => |sema| _ = try sema.resolveTypeFields(ty),
2466 .eager => assert(struct_obj.haveFieldTypes()),
2467 .lazy => if (!struct_obj.haveFieldTypes()) return error.NeedLazy,
2464 }2468 }
2465 assert(struct_obj.haveFieldTypes());
2466 for (struct_obj.fields.values()) |field| {2469 for (struct_obj.fields.values()) |field| {
2467 if (field.is_comptime) continue;2470 if (field.is_comptime) continue;
2468 if (try field.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema))2471 if (try field.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat))
2469 return true;2472 return true;
2470 } else {2473 } else {
2471 return false;2474 return false;
...@@ -2474,7 +2477,7 @@ pub const Type = extern union {...@@ -2474,7 +2477,7 @@ pub const Type = extern union {
24742477
2475 .enum_full => {2478 .enum_full => {
2476 const enum_full = ty.castTag(.enum_full).?.data;2479 const enum_full = ty.castTag(.enum_full).?.data;
2477 return enum_full.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema);2480 return enum_full.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat);
2478 },2481 },
2479 .enum_simple => {2482 .enum_simple => {
2480 const enum_simple = ty.castTag(.enum_simple).?.data;2483 const enum_simple = ty.castTag(.enum_simple).?.data;
...@@ -2483,17 +2486,18 @@ pub const Type = extern union {...@@ -2483,17 +2486,18 @@ pub const Type = extern union {
2483 .enum_numbered, .enum_nonexhaustive => {2486 .enum_numbered, .enum_nonexhaustive => {
2484 var buffer: Payload.Bits = undefined;2487 var buffer: Payload.Bits = undefined;
2485 const int_tag_ty = ty.intTagType(&buffer);2488 const int_tag_ty = ty.intTagType(&buffer);
2486 return int_tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema);2489 return int_tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat);
2487 },2490 },
24882491
2489 .@"union" => {2492 .@"union" => {
2490 const union_obj = ty.castTag(.@"union").?.data;2493 const union_obj = ty.castTag(.@"union").?.data;
2491 if (opt_sema) |sema| {2494 switch (strat) {
2492 _ = try sema.resolveTypeFields(ty);2495 .sema => |sema| _ = try sema.resolveTypeFields(ty),
2496 .eager => assert(union_obj.haveFieldTypes()),
2497 .lazy => if (!union_obj.haveFieldTypes()) return error.NeedLazy,
2493 }2498 }
2494 assert(union_obj.haveFieldTypes());
2495 for (union_obj.fields.values()) |value| {2499 for (union_obj.fields.values()) |value| {
2496 if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema))2500 if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat))
2497 return true;2501 return true;
2498 } else {2502 } else {
2499 return false;2503 return false;
...@@ -2501,16 +2505,17 @@ pub const Type = extern union {...@@ -2501,16 +2505,17 @@ pub const Type = extern union {
2501 },2505 },
2502 .union_safety_tagged, .union_tagged => {2506 .union_safety_tagged, .union_tagged => {
2503 const union_obj = ty.cast(Payload.Union).?.data;2507 const union_obj = ty.cast(Payload.Union).?.data;
2504 if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema)) {2508 if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat)) {
2505 return true;2509 return true;
2506 }2510 }
25072511
2508 if (opt_sema) |sema| {2512 switch (strat) {
2509 _ = try sema.resolveTypeFields(ty);2513 .sema => |sema| _ = try sema.resolveTypeFields(ty),
2514 .eager => assert(union_obj.haveFieldTypes()),
2515 .lazy => if (!union_obj.haveFieldTypes()) return error.NeedLazy,
2510 }2516 }
2511 assert(union_obj.haveFieldTypes());
2512 for (union_obj.fields.values()) |value| {2517 for (union_obj.fields.values()) |value| {
2513 if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema))2518 if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat))
2514 return true;2519 return true;
2515 } else {2520 } else {
2516 return false;2521 return false;
...@@ -2518,9 +2523,9 @@ pub const Type = extern union {...@@ -2518,9 +2523,9 @@ pub const Type = extern union {
2518 },2523 },
25192524
2520 .array, .vector => return ty.arrayLen() != 0 and2525 .array, .vector => return ty.arrayLen() != 0 and
2521 try ty.elemType().hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema),2526 try ty.elemType().hasRuntimeBitsAdvanced(ignore_comptime_only, strat),
2522 .array_u8 => return ty.arrayLen() != 0,2527 .array_u8 => return ty.arrayLen() != 0,
2523 .array_sentinel => return ty.childType().hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema),2528 .array_sentinel => return ty.childType().hasRuntimeBitsAdvanced(ignore_comptime_only, strat),
25242529
2525 .int_signed, .int_unsigned => return ty.cast(Payload.Bits).?.data != 0,2530 .int_signed, .int_unsigned => return ty.cast(Payload.Bits).?.data != 0,
25262531
...@@ -2529,7 +2534,7 @@ pub const Type = extern union {...@@ -2529,7 +2534,7 @@ pub const Type = extern union {
2529 for (tuple.types) |field_ty, i| {2534 for (tuple.types) |field_ty, i| {
2530 const val = tuple.values[i];2535 const val = tuple.values[i];
2531 if (val.tag() != .unreachable_value) continue; // comptime field2536 if (val.tag() != .unreachable_value) continue; // comptime field
2532 if (try field_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, opt_sema)) return true;2537 if (try field_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat)) return true;
2533 }2538 }
2534 return false;2539 return false;
2535 },2540 },
...@@ -2665,11 +2670,11 @@ pub const Type = extern union {...@@ -2665,11 +2670,11 @@ pub const Type = extern union {
2665 }2670 }
26662671
2667 pub fn hasRuntimeBits(ty: Type) bool {2672 pub fn hasRuntimeBits(ty: Type) bool {
2668 return hasRuntimeBitsAdvanced(ty, false, null) catch unreachable;2673 return hasRuntimeBitsAdvanced(ty, false, .eager) catch unreachable;
2669 }2674 }
26702675
2671 pub fn hasRuntimeBitsIgnoreComptime(ty: Type) bool {2676 pub fn hasRuntimeBitsIgnoreComptime(ty: Type) bool {
2672 return hasRuntimeBitsAdvanced(ty, true, null) catch unreachable;2677 return hasRuntimeBitsAdvanced(ty, true, .eager) catch unreachable;
2673 }2678 }
26742679
2675 pub fn isFnOrHasRuntimeBits(ty: Type) bool {2680 pub fn isFnOrHasRuntimeBits(ty: Type) bool {
...@@ -2812,12 +2817,12 @@ pub const Type = extern union {...@@ -2812,12 +2817,12 @@ pub const Type = extern union {
2812 }2817 }
2813 }2818 }
28142819
2815 const AbiAlignmentAdvanced = union(enum) {2820 pub const AbiAlignmentAdvanced = union(enum) {
2816 scalar: u32,2821 scalar: u32,
2817 val: Value,2822 val: Value,
2818 };2823 };
28192824
2820 const AbiAlignmentAdvancedStrat = union(enum) {2825 pub const AbiAlignmentAdvancedStrat = union(enum) {
2821 eager,2826 eager,
2822 lazy: Allocator,2827 lazy: Allocator,
2823 sema: *Sema,2828 sema: *Sema,
...@@ -2971,7 +2976,10 @@ pub const Type = extern union {...@@ -2971,7 +2976,10 @@ pub const Type = extern union {
29712976
2972 switch (strat) {2977 switch (strat) {
2973 .eager, .sema => {2978 .eager, .sema => {
2974 if (!(try child_type.hasRuntimeBitsAdvanced(false, opt_sema))) {2979 if (!(child_type.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) {
2980 error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) },
2981 else => |e| return e,
2982 })) {
2975 return AbiAlignmentAdvanced{ .scalar = 1 };2983 return AbiAlignmentAdvanced{ .scalar = 1 };
2976 }2984 }
2977 return child_type.abiAlignmentAdvanced(target, strat);2985 return child_type.abiAlignmentAdvanced(target, strat);
...@@ -2990,7 +2998,10 @@ pub const Type = extern union {...@@ -2990,7 +2998,10 @@ pub const Type = extern union {
2990 const code_align = abiAlignment(Type.anyerror, target);2998 const code_align = abiAlignment(Type.anyerror, target);
2991 switch (strat) {2999 switch (strat) {
2992 .eager, .sema => {3000 .eager, .sema => {
2993 if (!(try data.payload.hasRuntimeBitsAdvanced(false, opt_sema))) {3001 if (!(data.payload.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) {
3002 error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) },
3003 else => |e| return e,
3004 })) {
2994 return AbiAlignmentAdvanced{ .scalar = code_align };3005 return AbiAlignmentAdvanced{ .scalar = code_align };
2995 }3006 }
2996 return AbiAlignmentAdvanced{ .scalar = @max(3007 return AbiAlignmentAdvanced{ .scalar = @max(
...@@ -3044,7 +3055,10 @@ pub const Type = extern union {...@@ -3044,7 +3055,10 @@ pub const Type = extern union {
3044 const fields = ty.structFields();3055 const fields = ty.structFields();
3045 var big_align: u32 = 0;3056 var big_align: u32 = 0;
3046 for (fields.values()) |field| {3057 for (fields.values()) |field| {
3047 if (!(try field.ty.hasRuntimeBitsAdvanced(false, opt_sema))) continue;3058 if (!(field.ty.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) {
3059 error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) },
3060 else => |e| return e,
3061 })) continue;
30483062
3049 const field_align = if (field.abi_align != 0)3063 const field_align = if (field.abi_align != 0)
3050 field.abi_align3064 field.abi_align
...@@ -3161,7 +3175,10 @@ pub const Type = extern union {...@@ -3161,7 +3175,10 @@ pub const Type = extern union {
3161 var max_align: u32 = 0;3175 var max_align: u32 = 0;
3162 if (have_tag) max_align = union_obj.tag_ty.abiAlignment(target);3176 if (have_tag) max_align = union_obj.tag_ty.abiAlignment(target);
3163 for (union_obj.fields.values()) |field| {3177 for (union_obj.fields.values()) |field| {
3164 if (!(try field.ty.hasRuntimeBitsAdvanced(false, opt_sema))) continue;3178 if (!(field.ty.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) {
3179 error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) },
3180 else => |e| return e,
3181 })) continue;
31653182
3166 const field_align = if (field.abi_align != 0)3183 const field_align = if (field.abi_align != 0)
3167 field.abi_align3184 field.abi_align
src/value.zig+10-2
...@@ -1911,7 +1911,11 @@ pub const Value = extern union {...@@ -1911,7 +1911,11 @@ pub const Value = extern union {
19111911
1912 .lazy_align => {1912 .lazy_align => {
1913 const ty = lhs.castTag(.lazy_align).?.data;1913 const ty = lhs.castTag(.lazy_align).?.data;
1914 if (try ty.hasRuntimeBitsAdvanced(false, opt_sema)) {1914 const strat: Type.AbiAlignmentAdvancedStrat = if (opt_sema) |sema| .{ .sema = sema } else .eager;
1915 if (ty.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) {
1916 error.NeedLazy => unreachable,
1917 else => |e| return e,
1918 }) {
1915 return .gt;1919 return .gt;
1916 } else {1920 } else {
1917 return .eq;1921 return .eq;
...@@ -1919,7 +1923,11 @@ pub const Value = extern union {...@@ -1919,7 +1923,11 @@ pub const Value = extern union {
1919 },1923 },
1920 .lazy_size => {1924 .lazy_size => {
1921 const ty = lhs.castTag(.lazy_size).?.data;1925 const ty = lhs.castTag(.lazy_size).?.data;
1922 if (try ty.hasRuntimeBitsAdvanced(false, opt_sema)) {1926 const strat: Type.AbiAlignmentAdvancedStrat = if (opt_sema) |sema| .{ .sema = sema } else .eager;
1927 if (ty.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) {
1928 error.NeedLazy => unreachable,
1929 else => |e| return e,
1930 }) {
1923 return .gt;1931 return .gt;
1924 } else {1932 } else {
1925 return .eq;1933 return .eq;