| ... | ... | @@ -154,9 +154,6 @@ pub fn analyzeBody( |
| 154 | 154 | // We use a while(true) loop here to avoid a redundant way of breaking out of |
| 155 | 155 | // the loop. The only way to break out of the loop is with a `noreturn` |
| 156 | 156 | // instruction. |
| 157 | | // TODO: As an optimization, make sure the codegen for these switch prongs |
| 158 | | // directly jump to the next one, rather than detouring through the loop |
| 159 | | // continue expression. Related: https://github.com/ziglang/zig/issues/8220 |
| 160 | 157 | var i: usize = 0; |
| 161 | 158 | while (true) { |
| 162 | 159 | const inst = body[i]; |
| ... | ... | @@ -391,7 +388,7 @@ pub fn analyzeBody( |
| 391 | 388 | .condbr => return sema.zirCondbr(block, inst), |
| 392 | 389 | .@"break" => return sema.zirBreak(block, inst), |
| 393 | 390 | .compile_error => return sema.zirCompileError(block, inst), |
| 394 | | .ret_coerce => return sema.zirRetCoerce(block, inst, true), |
| 391 | .ret_coerce => return sema.zirRetCoerce(block, inst), |
| 395 | 392 | .ret_node => return sema.zirRetNode(block, inst), |
| 396 | 393 | .ret_err_value => return sema.zirRetErrValue(block, inst), |
| 397 | 394 | .@"unreachable" => return sema.zirUnreachable(block, inst), |
| ... | ... | @@ -1396,14 +1393,19 @@ fn zirAllocComptime(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Comp |
| 1396 | 1393 | const var_type = try sema.resolveType(block, ty_src, inst_data.operand); |
| 1397 | 1394 | const ptr_type = try Module.simplePtrType(sema.arena, var_type, true, .One); |
| 1398 | 1395 | |
| 1399 | | const val_payload = try sema.arena.create(Value.Payload.ComptimeAlloc); |
| 1400 | | val_payload.* = .{ |
| 1401 | | .data = .{ |
| 1402 | | .runtime_index = block.runtime_index, |
| 1403 | | .val = undefined, // astgen guarantees there will be a store before the first load |
| 1404 | | }, |
| 1405 | | }; |
| 1406 | | return sema.addConstant(ptr_type, Value.initPayload(&val_payload.base)); |
| 1396 | var anon_decl = try block.startAnonDecl(); |
| 1397 | defer anon_decl.deinit(); |
| 1398 | const decl = try anon_decl.finish( |
| 1399 | try var_type.copy(anon_decl.arena()), |
| 1400 | // AstGen guarantees there will be a store before the first load, so we put a value |
| 1401 | // here indicating there is no valid value. |
| 1402 | Value.initTag(.unreachable_value), |
| 1403 | ); |
| 1404 | try sema.mod.declareDeclDependency(sema.owner_decl, decl); |
| 1405 | return sema.addConstant(ptr_type, try Value.Tag.decl_ref_mut.create(sema.arena, .{ |
| 1406 | .runtime_index = block.runtime_index, |
| 1407 | .decl = decl, |
| 1408 | })); |
| 1407 | 1409 | } |
| 1408 | 1410 | |
| 1409 | 1411 | fn zirAllocInferredComptime(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -1450,16 +1452,23 @@ fn zirAllocInferred( |
| 1450 | 1452 | |
| 1451 | 1453 | const src_node = sema.code.instructions.items(.data)[inst].node; |
| 1452 | 1454 | const src: LazySrcLoc = .{ .node_offset = src_node }; |
| 1455 | sema.src = src; |
| 1453 | 1456 | |
| 1454 | | const val_payload = try sema.arena.create(Value.Payload.InferredAlloc); |
| 1455 | | val_payload.* = .{ |
| 1456 | | .data = .{}, |
| 1457 | | }; |
| 1458 | | // `Module.constInst` does not add the instruction to the block because it is |
| 1457 | if (block.is_comptime) { |
| 1458 | return sema.addConstant( |
| 1459 | inferred_alloc_ty, |
| 1460 | try Value.Tag.inferred_alloc_comptime.create(sema.arena, undefined), |
| 1461 | ); |
| 1462 | } |
| 1463 | |
| 1464 | // `Sema.addConstant` does not add the instruction to the block because it is |
| 1459 | 1465 | // not needed in the case of constant values. However here, we plan to "downgrade" |
| 1460 | 1466 | // to a normal instruction when we hit `resolve_inferred_alloc`. So we append |
| 1461 | 1467 | // to the block even though it is currently a `.constant`. |
| 1462 | | const result = try sema.addConstant(inferred_alloc_ty, Value.initPayload(&val_payload.base)); |
| 1468 | const result = try sema.addConstant( |
| 1469 | inferred_alloc_ty, |
| 1470 | try Value.Tag.inferred_alloc.create(sema.arena, .{}), |
| 1471 | ); |
| 1463 | 1472 | try sema.requireFunctionBlock(block, src); |
| 1464 | 1473 | try block.instructions.append(sema.gpa, Air.refToIndex(result).?); |
| 1465 | 1474 | return result; |
| ... | ... | @@ -1475,25 +1484,47 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Inde |
| 1475 | 1484 | const ptr_inst = Air.refToIndex(ptr).?; |
| 1476 | 1485 | assert(sema.air_instructions.items(.tag)[ptr_inst] == .constant); |
| 1477 | 1486 | const air_datas = sema.air_instructions.items(.data); |
| 1478 | | const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload]; |
| 1479 | | const inferred_alloc = ptr_val.castTag(.inferred_alloc).?; |
| 1480 | | const peer_inst_list = inferred_alloc.data.stored_inst_list.items; |
| 1481 | | const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_inst_list); |
| 1487 | const value_index = air_datas[ptr_inst].ty_pl.payload; |
| 1488 | const ptr_val = sema.air_values.items[value_index]; |
| 1482 | 1489 | const var_is_mut = switch (sema.typeOf(ptr).tag()) { |
| 1483 | 1490 | .inferred_alloc_const => false, |
| 1484 | 1491 | .inferred_alloc_mut => true, |
| 1485 | 1492 | else => unreachable, |
| 1486 | 1493 | }; |
| 1487 | | if (var_is_mut) { |
| 1488 | | try sema.validateVarType(block, ty_src, final_elem_ty); |
| 1494 | |
| 1495 | if (ptr_val.castTag(.inferred_alloc_comptime)) |iac| { |
| 1496 | const decl = iac.data; |
| 1497 | try sema.mod.declareDeclDependency(sema.owner_decl, decl); |
| 1498 | |
| 1499 | const final_elem_ty = try decl.ty.copy(sema.arena); |
| 1500 | const final_ptr_ty = try Module.simplePtrType(sema.arena, final_elem_ty, true, .One); |
| 1501 | air_datas[ptr_inst].ty_pl.ty = try sema.addType(final_ptr_ty); |
| 1502 | |
| 1503 | if (var_is_mut) { |
| 1504 | sema.air_values.items[value_index] = try Value.Tag.decl_ref_mut.create(sema.arena, .{ |
| 1505 | .decl = decl, |
| 1506 | .runtime_index = block.runtime_index, |
| 1507 | }); |
| 1508 | } else { |
| 1509 | sema.air_values.items[value_index] = try Value.Tag.decl_ref.create(sema.arena, decl); |
| 1510 | } |
| 1511 | return; |
| 1489 | 1512 | } |
| 1490 | | const final_ptr_ty = try Module.simplePtrType(sema.arena, final_elem_ty, true, .One); |
| 1491 | 1513 | |
| 1492 | | // Change it to a normal alloc. |
| 1493 | | sema.air_instructions.set(ptr_inst, .{ |
| 1494 | | .tag = .alloc, |
| 1495 | | .data = .{ .ty = final_ptr_ty }, |
| 1496 | | }); |
| 1514 | if (ptr_val.castTag(.inferred_alloc)) |inferred_alloc| { |
| 1515 | const peer_inst_list = inferred_alloc.data.stored_inst_list.items; |
| 1516 | const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_inst_list); |
| 1517 | if (var_is_mut) { |
| 1518 | try sema.validateVarType(block, ty_src, final_elem_ty); |
| 1519 | } |
| 1520 | // Change it to a normal alloc. |
| 1521 | const final_ptr_ty = try Module.simplePtrType(sema.arena, final_elem_ty, true, .One); |
| 1522 | sema.air_instructions.set(ptr_inst, .{ |
| 1523 | .tag = .alloc, |
| 1524 | .data = .{ .ty = final_ptr_ty }, |
| 1525 | }); |
| 1526 | return; |
| 1527 | } |
| 1497 | 1528 | } |
| 1498 | 1529 | |
| 1499 | 1530 | fn zirValidateStructInitPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!void { |
| ... | ... | @@ -1654,23 +1685,45 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) |
| 1654 | 1685 | const tracy = trace(@src()); |
| 1655 | 1686 | defer tracy.end(); |
| 1656 | 1687 | |
| 1657 | | const src: LazySrcLoc = .unneeded; |
| 1688 | const src: LazySrcLoc = sema.src; |
| 1658 | 1689 | const bin_inst = sema.code.instructions.items(.data)[inst].bin; |
| 1659 | 1690 | const ptr = sema.resolveInst(bin_inst.lhs); |
| 1660 | | const value = sema.resolveInst(bin_inst.rhs); |
| 1691 | const operand = sema.resolveInst(bin_inst.rhs); |
| 1692 | const operand_ty = sema.typeOf(operand); |
| 1661 | 1693 | const ptr_inst = Air.refToIndex(ptr).?; |
| 1662 | 1694 | assert(sema.air_instructions.items(.tag)[ptr_inst] == .constant); |
| 1663 | 1695 | const air_datas = sema.air_instructions.items(.data); |
| 1664 | 1696 | const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload]; |
| 1665 | | const inferred_alloc = ptr_val.castTag(.inferred_alloc).?; |
| 1666 | | // Add the stored instruction to the set we will use to resolve peer types |
| 1667 | | // for the inferred allocation. |
| 1668 | | try inferred_alloc.data.stored_inst_list.append(sema.arena, value); |
| 1669 | | // Create a runtime bitcast instruction with exactly the type the pointer wants. |
| 1670 | | const ptr_ty = try Module.simplePtrType(sema.arena, sema.typeOf(value), true, .One); |
| 1671 | | try sema.requireRuntimeBlock(block, src); |
| 1672 | | const bitcasted_ptr = try block.addTyOp(.bitcast, ptr_ty, ptr); |
| 1673 | | return sema.storePtr(block, src, bitcasted_ptr, value); |
| 1697 | |
| 1698 | if (ptr_val.castTag(.inferred_alloc_comptime)) |iac| { |
| 1699 | // There will be only one store_to_inferred_ptr because we are running at comptime. |
| 1700 | // The alloc will turn into a Decl. |
| 1701 | if (try sema.resolveMaybeUndefValAllowVariables(block, src, operand)) |operand_val| { |
| 1702 | if (operand_val.tag() == .variable) { |
| 1703 | return sema.failWithNeededComptime(block, src); |
| 1704 | } |
| 1705 | var anon_decl = try block.startAnonDecl(); |
| 1706 | defer anon_decl.deinit(); |
| 1707 | iac.data = try anon_decl.finish( |
| 1708 | try operand_ty.copy(anon_decl.arena()), |
| 1709 | try operand_val.copy(anon_decl.arena()), |
| 1710 | ); |
| 1711 | return; |
| 1712 | } else { |
| 1713 | return sema.failWithNeededComptime(block, src); |
| 1714 | } |
| 1715 | } |
| 1716 | |
| 1717 | if (ptr_val.castTag(.inferred_alloc)) |inferred_alloc| { |
| 1718 | // Add the stored instruction to the set we will use to resolve peer types |
| 1719 | // for the inferred allocation. |
| 1720 | try inferred_alloc.data.stored_inst_list.append(sema.arena, operand); |
| 1721 | // Create a runtime bitcast instruction with exactly the type the pointer wants. |
| 1722 | const ptr_ty = try Module.simplePtrType(sema.arena, operand_ty, true, .One); |
| 1723 | const bitcasted_ptr = try block.addTyOp(.bitcast, ptr_ty, ptr); |
| 1724 | return sema.storePtr(block, src, bitcasted_ptr, operand); |
| 1725 | } |
| 1726 | unreachable; |
| 1674 | 1727 | } |
| 1675 | 1728 | |
| 1676 | 1729 | fn zirSetEvalBranchQuota(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!void { |
| ... | ... | @@ -5643,7 +5696,6 @@ fn zirRetCoerce( |
| 5643 | 5696 | sema: *Sema, |
| 5644 | 5697 | block: *Scope.Block, |
| 5645 | 5698 | inst: Zir.Inst.Index, |
| 5646 | | need_coercion: bool, |
| 5647 | 5699 | ) CompileError!Zir.Inst.Index { |
| 5648 | 5700 | const tracy = trace(@src()); |
| 5649 | 5701 | defer tracy.end(); |
| ... | ... | @@ -5652,7 +5704,7 @@ fn zirRetCoerce( |
| 5652 | 5704 | const operand = sema.resolveInst(inst_data.operand); |
| 5653 | 5705 | const src = inst_data.src(); |
| 5654 | 5706 | |
| 5655 | | return sema.analyzeRet(block, operand, src, need_coercion); |
| 5707 | return sema.analyzeRet(block, operand, src, true); |
| 5656 | 5708 | } |
| 5657 | 5709 | |
| 5658 | 5710 | fn zirRetNode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index { |
| ... | ... | @@ -5673,23 +5725,20 @@ fn analyzeRet( |
| 5673 | 5725 | src: LazySrcLoc, |
| 5674 | 5726 | need_coercion: bool, |
| 5675 | 5727 | ) CompileError!Zir.Inst.Index { |
| 5728 | const casted_operand = if (!need_coercion) operand else op: { |
| 5729 | const func = sema.func.?; |
| 5730 | const fn_ty = func.owner_decl.ty; |
| 5731 | const fn_ret_ty = fn_ty.fnReturnType(); |
| 5732 | break :op try sema.coerce(block, fn_ret_ty, operand, src); |
| 5733 | }; |
| 5676 | 5734 | if (block.inlining) |inlining| { |
| 5677 | 5735 | // We are inlining a function call; rewrite the `ret` as a `break`. |
| 5678 | | try inlining.merges.results.append(sema.gpa, operand); |
| 5679 | | _ = try block.addBr(inlining.merges.block_inst, operand); |
| 5736 | try inlining.merges.results.append(sema.gpa, casted_operand); |
| 5737 | _ = try block.addBr(inlining.merges.block_inst, casted_operand); |
| 5680 | 5738 | return always_noreturn; |
| 5681 | 5739 | } |
| 5682 | 5740 | |
| 5683 | | if (need_coercion) { |
| 5684 | | if (sema.func) |func| { |
| 5685 | | const fn_ty = func.owner_decl.ty; |
| 5686 | | const fn_ret_ty = fn_ty.fnReturnType(); |
| 5687 | | const casted_operand = try sema.coerce(block, fn_ret_ty, operand, src); |
| 5688 | | _ = try block.addUnOp(.ret, casted_operand); |
| 5689 | | return always_noreturn; |
| 5690 | | } |
| 5691 | | } |
| 5692 | | _ = try block.addUnOp(.ret, operand); |
| 5741 | _ = try block.addUnOp(.ret, casted_operand); |
| 5693 | 5742 | return always_noreturn; |
| 5694 | 5743 | } |
| 5695 | 5744 | |
| ... | ... | @@ -7603,37 +7652,45 @@ fn storePtr( |
| 7603 | 7652 | if ((try sema.typeHasOnePossibleValue(block, src, elem_ty)) != null) |
| 7604 | 7653 | return; |
| 7605 | 7654 | |
| 7606 | | if (try sema.resolveMaybeUndefVal(block, src, ptr)) |ptr_val| blk: { |
| 7607 | | const const_val = (try sema.resolveMaybeUndefVal(block, src, value)) orelse |
| 7608 | | return sema.mod.fail(&block.base, src, "cannot store runtime value in compile time variable", .{}); |
| 7609 | | |
| 7610 | | if (ptr_val.tag() == .int_u64) |
| 7611 | | break :blk; // propogate it down to runtime |
| 7612 | | |
| 7613 | | const comptime_alloc = ptr_val.castTag(.comptime_alloc).?; |
| 7614 | | if (comptime_alloc.data.runtime_index < block.runtime_index) { |
| 7615 | | if (block.runtime_cond) |cond_src| { |
| 7616 | | const msg = msg: { |
| 7617 | | const msg = try sema.mod.errMsg(&block.base, src, "store to comptime variable depends on runtime condition", .{}); |
| 7618 | | errdefer msg.destroy(sema.gpa); |
| 7619 | | try sema.mod.errNote(&block.base, cond_src, msg, "runtime condition here", .{}); |
| 7620 | | break :msg msg; |
| 7621 | | }; |
| 7622 | | return sema.mod.failWithOwnedErrorMsg(&block.base, msg); |
| 7623 | | } |
| 7624 | | if (block.runtime_loop) |loop_src| { |
| 7625 | | const msg = msg: { |
| 7626 | | const msg = try sema.mod.errMsg(&block.base, src, "cannot store to comptime variable in non-inline loop", .{}); |
| 7627 | | errdefer msg.destroy(sema.gpa); |
| 7628 | | try sema.mod.errNote(&block.base, loop_src, msg, "non-inline loop here", .{}); |
| 7629 | | break :msg msg; |
| 7630 | | }; |
| 7631 | | return sema.mod.failWithOwnedErrorMsg(&block.base, msg); |
| 7655 | if (try sema.resolveDefinedValue(block, src, ptr)) |ptr_val| { |
| 7656 | if (ptr_val.castTag(.decl_ref_mut)) |decl_ref_mut| { |
| 7657 | const const_val = (try sema.resolveMaybeUndefVal(block, src, value)) orelse |
| 7658 | return sema.mod.fail(&block.base, src, "cannot store runtime value in compile time variable", .{}); |
| 7659 | |
| 7660 | if (decl_ref_mut.data.runtime_index < block.runtime_index) { |
| 7661 | if (block.runtime_cond) |cond_src| { |
| 7662 | const msg = msg: { |
| 7663 | const msg = try sema.mod.errMsg(&block.base, src, "store to comptime variable depends on runtime condition", .{}); |
| 7664 | errdefer msg.destroy(sema.gpa); |
| 7665 | try sema.mod.errNote(&block.base, cond_src, msg, "runtime condition here", .{}); |
| 7666 | break :msg msg; |
| 7667 | }; |
| 7668 | return sema.mod.failWithOwnedErrorMsg(&block.base, msg); |
| 7669 | } |
| 7670 | if (block.runtime_loop) |loop_src| { |
| 7671 | const msg = msg: { |
| 7672 | const msg = try sema.mod.errMsg(&block.base, src, "cannot store to comptime variable in non-inline loop", .{}); |
| 7673 | errdefer msg.destroy(sema.gpa); |
| 7674 | try sema.mod.errNote(&block.base, loop_src, msg, "non-inline loop here", .{}); |
| 7675 | break :msg msg; |
| 7676 | }; |
| 7677 | return sema.mod.failWithOwnedErrorMsg(&block.base, msg); |
| 7678 | } |
| 7679 | unreachable; |
| 7632 | 7680 | } |
| 7633 | | unreachable; |
| 7681 | var new_arena = std.heap.ArenaAllocator.init(sema.gpa); |
| 7682 | errdefer new_arena.deinit(); |
| 7683 | const new_ty = try elem_ty.copy(&new_arena.allocator); |
| 7684 | const new_val = try const_val.copy(&new_arena.allocator); |
| 7685 | const decl = decl_ref_mut.data.decl; |
| 7686 | var old_arena = decl.value_arena.?.promote(sema.gpa); |
| 7687 | decl.value_arena = null; |
| 7688 | try decl.finalizeNewArena(&new_arena); |
| 7689 | decl.ty = new_ty; |
| 7690 | decl.val = new_val; |
| 7691 | old_arena.deinit(); |
| 7692 | return; |
| 7634 | 7693 | } |
| 7635 | | comptime_alloc.data.val = const_val; |
| 7636 | | return; |
| 7637 | 7694 | } |
| 7638 | 7695 | // TODO handle if the element type requires comptime |
| 7639 | 7696 | |