| ... | ... | @@ -2711,17 +2711,72 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr |
| 2711 | 2711 | |
| 2712 | 2712 | fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 2713 | 2713 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 2714 | | const ptr = try sema.resolveInst(inst_data.operand); |
| 2715 | | const ptr_ty = sema.typeOf(ptr); |
| 2716 | | var ptr_info = ptr_ty.ptrInfo().data; |
| 2714 | const src = inst_data.src(); |
| 2715 | const alloc = try sema.resolveInst(inst_data.operand); |
| 2716 | const alloc_ty = sema.typeOf(alloc); |
| 2717 | |
| 2718 | var ptr_info = alloc_ty.ptrInfo().data; |
| 2719 | const elem_ty = ptr_info.pointee_type; |
| 2720 | |
| 2721 | // Detect if all stores to an `.alloc` were comptime known. |
| 2722 | ct: { |
| 2723 | var search_index: usize = block.instructions.items.len; |
| 2724 | const air_tags = sema.air_instructions.items(.tag); |
| 2725 | const air_datas = sema.air_instructions.items(.data); |
| 2726 | |
| 2727 | const store_inst = while (true) { |
| 2728 | if (search_index == 0) break :ct; |
| 2729 | search_index -= 1; |
| 2730 | |
| 2731 | const candidate = block.instructions.items[search_index]; |
| 2732 | switch (air_tags[candidate]) { |
| 2733 | .dbg_stmt => continue, |
| 2734 | .store => break candidate, |
| 2735 | else => break :ct, |
| 2736 | } |
| 2737 | } else unreachable; // TODO shouldn't need this |
| 2738 | |
| 2739 | while (true) { |
| 2740 | if (search_index == 0) break :ct; |
| 2741 | search_index -= 1; |
| 2742 | |
| 2743 | const candidate = block.instructions.items[search_index]; |
| 2744 | switch (air_tags[candidate]) { |
| 2745 | .dbg_stmt => continue, |
| 2746 | .alloc => { |
| 2747 | if (Air.indexToRef(candidate) != alloc) break :ct; |
| 2748 | break; |
| 2749 | }, |
| 2750 | else => break :ct, |
| 2751 | } |
| 2752 | } |
| 2753 | |
| 2754 | const store_op = air_datas[store_inst].bin_op; |
| 2755 | const store_val = (try sema.resolveMaybeUndefVal(block, src, store_op.rhs)) orelse break :ct; |
| 2756 | if (store_op.lhs != alloc) break :ct; |
| 2757 | |
| 2758 | // Remove all the unnecessary runtime instructions. |
| 2759 | block.instructions.shrinkRetainingCapacity(search_index); |
| 2760 | |
| 2761 | var anon_decl = try block.startAnonDecl(src); |
| 2762 | defer anon_decl.deinit(); |
| 2763 | return sema.analyzeDeclRef(try anon_decl.finish( |
| 2764 | try elem_ty.copy(anon_decl.arena()), |
| 2765 | try store_val.copy(anon_decl.arena()), |
| 2766 | ptr_info.@"align", |
| 2767 | )); |
| 2768 | } |
| 2769 | |
| 2717 | 2770 | ptr_info.mutable = false; |
| 2718 | 2771 | const const_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_info); |
| 2719 | 2772 | |
| 2720 | | if (try sema.resolveMaybeUndefVal(block, inst_data.src(), ptr)) |val| { |
| 2773 | // Detect if a comptime value simply needs to have its type changed. |
| 2774 | if (try sema.resolveMaybeUndefVal(block, inst_data.src(), alloc)) |val| { |
| 2721 | 2775 | return sema.addConstant(const_ptr_ty, val); |
| 2722 | 2776 | } |
| 2723 | | try sema.requireRuntimeBlock(block, inst_data.src()); |
| 2724 | | return block.addBitCast(const_ptr_ty, ptr); |
| 2777 | |
| 2778 | try sema.requireRuntimeBlock(block, src); |
| 2779 | return block.addBitCast(const_ptr_ty, alloc); |
| 2725 | 2780 | } |
| 2726 | 2781 | |
| 2727 | 2782 | fn zirAllocInferredComptime( |
| ... | ... | @@ -3160,7 +3215,9 @@ fn validateUnionInit( |
| 3160 | 3215 | return sema.failWithOwnedErrorMsg(block, msg); |
| 3161 | 3216 | } |
| 3162 | 3217 | |
| 3163 | | if (is_comptime or block.is_comptime) { |
| 3218 | if ((is_comptime or block.is_comptime) and |
| 3219 | (try sema.resolveDefinedValue(block, init_src, union_ptr)) != null) |
| 3220 | { |
| 3164 | 3221 | // In this case, comptime machinery already did everything. No work to do here. |
| 3165 | 3222 | return; |
| 3166 | 3223 | } |
| ... | ... | @@ -3206,7 +3263,18 @@ fn validateUnionInit( |
| 3206 | 3263 | if (store_inst == field_ptr_air_inst) break; |
| 3207 | 3264 | if (air_tags[store_inst] != .store) continue; |
| 3208 | 3265 | const bin_op = air_datas[store_inst].bin_op; |
| 3209 | | if (bin_op.lhs != field_ptr_air_ref) continue; |
| 3266 | var lhs = bin_op.lhs; |
| 3267 | if (Air.refToIndex(lhs)) |lhs_index| { |
| 3268 | if (air_tags[lhs_index] == .bitcast) { |
| 3269 | lhs = air_datas[lhs_index].ty_op.operand; |
| 3270 | block_index -= 1; |
| 3271 | } |
| 3272 | } |
| 3273 | if (lhs != field_ptr_air_ref) continue; |
| 3274 | while (block_index > 0) : (block_index -= 1) { |
| 3275 | const block_inst = block.instructions.items[block_index - 1]; |
| 3276 | if (air_tags[block_inst] != .dbg_stmt) break; |
| 3277 | } |
| 3210 | 3278 | if (block_index > 0 and |
| 3211 | 3279 | field_ptr_air_inst == block.instructions.items[block_index - 1]) |
| 3212 | 3280 | { |
| ... | ... | @@ -3285,7 +3353,9 @@ fn validateStructInit( |
| 3285 | 3353 | const struct_ptr = try sema.resolveInst(struct_ptr_zir_ref); |
| 3286 | 3354 | const struct_ty = sema.typeOf(struct_ptr).childType(); |
| 3287 | 3355 | |
| 3288 | | if (is_comptime or block.is_comptime) { |
| 3356 | if ((is_comptime or block.is_comptime) and |
| 3357 | (try sema.resolveDefinedValue(block, init_src, struct_ptr)) != null) |
| 3358 | { |
| 3289 | 3359 | // In this case the only thing we need to do is evaluate the implicit |
| 3290 | 3360 | // store instructions for default field values, and report any missing fields. |
| 3291 | 3361 | // Avoid the cost of the extra machinery for detecting a comptime struct init value. |
| ... | ... | @@ -3387,7 +3457,19 @@ fn validateStructInit( |
| 3387 | 3457 | } |
| 3388 | 3458 | if (air_tags[store_inst] != .store) continue; |
| 3389 | 3459 | const bin_op = air_datas[store_inst].bin_op; |
| 3390 | | if (bin_op.lhs != field_ptr_air_ref) continue; |
| 3460 | var lhs = bin_op.lhs; |
| 3461 | { |
| 3462 | const lhs_index = Air.refToIndex(lhs) orelse continue; |
| 3463 | if (air_tags[lhs_index] == .bitcast) { |
| 3464 | lhs = air_datas[lhs_index].ty_op.operand; |
| 3465 | block_index -= 1; |
| 3466 | } |
| 3467 | } |
| 3468 | if (lhs != field_ptr_air_ref) continue; |
| 3469 | while (block_index > 0) : (block_index -= 1) { |
| 3470 | const block_inst = block.instructions.items[block_index - 1]; |
| 3471 | if (air_tags[block_inst] != .dbg_stmt) break; |
| 3472 | } |
| 3391 | 3473 | if (block_index > 0 and |
| 3392 | 3474 | field_ptr_air_inst == block.instructions.items[block_index - 1]) |
| 3393 | 3475 | { |
| ... | ... | @@ -3489,7 +3571,9 @@ fn zirValidateArrayInit( |
| 3489 | 3571 | }); |
| 3490 | 3572 | } |
| 3491 | 3573 | |
| 3492 | | if (is_comptime or block.is_comptime) { |
| 3574 | if ((is_comptime or block.is_comptime) and |
| 3575 | (try sema.resolveDefinedValue(block, init_src, array_ptr)) != null) |
| 3576 | { |
| 3493 | 3577 | // In this case the comptime machinery will have evaluated the store instructions |
| 3494 | 3578 | // at comptime so we have almost nothing to do here. However, in case of a |
| 3495 | 3579 | // sentinel-terminated array, the sentinel will not have been populated by |
| ... | ... | @@ -3544,7 +3628,14 @@ fn zirValidateArrayInit( |
| 3544 | 3628 | switch (air_tags[next_air_inst]) { |
| 3545 | 3629 | .store => { |
| 3546 | 3630 | const bin_op = air_datas[next_air_inst].bin_op; |
| 3547 | | if (bin_op.lhs != elem_ptr_air_ref) { |
| 3631 | var lhs = bin_op.lhs; |
| 3632 | if (Air.refToIndex(lhs)) |lhs_index| { |
| 3633 | if (air_tags[lhs_index] == .bitcast) { |
| 3634 | lhs = air_datas[lhs_index].ty_op.operand; |
| 3635 | block_index -= 1; |
| 3636 | } |
| 3637 | } |
| 3638 | if (lhs != elem_ptr_air_ref) { |
| 3548 | 3639 | array_is_comptime = false; |
| 3549 | 3640 | continue; |
| 3550 | 3641 | } |