| ... | @@ -2711,17 +2711,72 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr | ... | @@ -2711,17 +2711,72 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr |
| 2711 | | 2711 | |
| 2712 | fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 2712 | fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 2713 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 2713 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 2714 | const ptr = try sema.resolveInst(inst_data.operand); | 2714 | const src = inst_data.src(); |
| 2715 | const ptr_ty = sema.typeOf(ptr); | 2715 | const alloc = try sema.resolveInst(inst_data.operand); |
| 2716 | var ptr_info = ptr_ty.ptrInfo().data; | 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 | ptr_info.mutable = false; | 2770 | ptr_info.mutable = false; |
| 2718 | const const_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_info); | 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 | return sema.addConstant(const_ptr_ty, val); | 2775 | return sema.addConstant(const_ptr_ty, val); |
| 2722 | } | 2776 | } |
| 2723 | try sema.requireRuntimeBlock(block, inst_data.src()); | 2777 | |
| 2724 | return block.addBitCast(const_ptr_ty, ptr); | 2778 | try sema.requireRuntimeBlock(block, src); |
| | 2779 | return block.addBitCast(const_ptr_ty, alloc); |
| 2725 | } | 2780 | } |
| 2726 | | 2781 | |
| 2727 | fn zirAllocInferredComptime( | 2782 | fn zirAllocInferredComptime( |
| ... | @@ -3160,7 +3215,9 @@ fn validateUnionInit( | ... | @@ -3160,7 +3215,9 @@ fn validateUnionInit( |
| 3160 | return sema.failWithOwnedErrorMsg(block, msg); | 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 | // In this case, comptime machinery already did everything. No work to do here. | 3221 | // In this case, comptime machinery already did everything. No work to do here. |
| 3165 | return; | 3222 | return; |
| 3166 | } | 3223 | } |
| ... | @@ -3206,7 +3263,18 @@ fn validateUnionInit( | ... | @@ -3206,7 +3263,18 @@ fn validateUnionInit( |
| 3206 | if (store_inst == field_ptr_air_inst) break; | 3263 | if (store_inst == field_ptr_air_inst) break; |
| 3207 | if (air_tags[store_inst] != .store) continue; | 3264 | if (air_tags[store_inst] != .store) continue; |
| 3208 | const bin_op = air_datas[store_inst].bin_op; | 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 | if (block_index > 0 and | 3278 | if (block_index > 0 and |
| 3211 | field_ptr_air_inst == block.instructions.items[block_index - 1]) | 3279 | field_ptr_air_inst == block.instructions.items[block_index - 1]) |
| 3212 | { | 3280 | { |
| ... | @@ -3285,7 +3353,9 @@ fn validateStructInit( | ... | @@ -3285,7 +3353,9 @@ fn validateStructInit( |
| 3285 | const struct_ptr = try sema.resolveInst(struct_ptr_zir_ref); | 3353 | const struct_ptr = try sema.resolveInst(struct_ptr_zir_ref); |
| 3286 | const struct_ty = sema.typeOf(struct_ptr).childType(); | 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 | // In this case the only thing we need to do is evaluate the implicit | 3359 | // In this case the only thing we need to do is evaluate the implicit |
| 3290 | // store instructions for default field values, and report any missing fields. | 3360 | // store instructions for default field values, and report any missing fields. |
| 3291 | // Avoid the cost of the extra machinery for detecting a comptime struct init value. | 3361 | // Avoid the cost of the extra machinery for detecting a comptime struct init value. |
| ... | @@ -3387,7 +3457,19 @@ fn validateStructInit( | ... | @@ -3387,7 +3457,19 @@ fn validateStructInit( |
| 3387 | } | 3457 | } |
| 3388 | if (air_tags[store_inst] != .store) continue; | 3458 | if (air_tags[store_inst] != .store) continue; |
| 3389 | const bin_op = air_datas[store_inst].bin_op; | 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 | if (block_index > 0 and | 3473 | if (block_index > 0 and |
| 3392 | field_ptr_air_inst == block.instructions.items[block_index - 1]) | 3474 | field_ptr_air_inst == block.instructions.items[block_index - 1]) |
| 3393 | { | 3475 | { |
| ... | @@ -3489,7 +3571,9 @@ fn zirValidateArrayInit( | ... | @@ -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 | // In this case the comptime machinery will have evaluated the store instructions | 3577 | // In this case the comptime machinery will have evaluated the store instructions |
| 3494 | // at comptime so we have almost nothing to do here. However, in case of a | 3578 | // at comptime so we have almost nothing to do here. However, in case of a |
| 3495 | // sentinel-terminated array, the sentinel will not have been populated by | 3579 | // sentinel-terminated array, the sentinel will not have been populated by |
| ... | @@ -3544,7 +3628,14 @@ fn zirValidateArrayInit( | ... | @@ -3544,7 +3628,14 @@ fn zirValidateArrayInit( |
| 3544 | switch (air_tags[next_air_inst]) { | 3628 | switch (air_tags[next_air_inst]) { |
| 3545 | .store => { | 3629 | .store => { |
| 3546 | const bin_op = air_datas[next_air_inst].bin_op; | 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 | array_is_comptime = false; | 3639 | array_is_comptime = false; |
| 3549 | continue; | 3640 | continue; |
| 3550 | } | 3641 | } |