diff options
| author | Jacob Young <jacobly0@users.noreply.github.com> | 2023-03-31 16:23:01 -0400 |
|---|---|---|
| committer | Veikka Tuominen <git@vexu.eu> | 2023-04-02 18:05:44 +0300 |
| commit | f4b411314ccf8e852d3febddc8b31ce1f533938b (patch) | |
| tree | 41ff16cd4d9bec89e5f57be34e790017be93a4d0 /src/Sema.zig | |
| parent | 878163e58813aef968900aa7495dacc5220eb941 (diff) | |
| download | zig-f4b411314ccf8e852d3febddc8b31ce1f533938b.tar.gz zig-f4b411314ccf8e852d3febddc8b31ce1f533938b.zip | |
Sema: defer stores to inferred allocs
This lets us generate the store with knowledge of the type to be stored.
Therefore, we can avoid generating garbage Air with stores through
pointers to comptime-only types which backends cannot lower.
Closes #13410
Closes #15122
Diffstat (limited to 'src/Sema.zig')
| -rw-r--r-- | src/Sema.zig | 67 |
1 files changed, 37 insertions, 30 deletions
diff --git a/src/Sema.zig b/src/Sema.zig index da93a2906a..972efcff72 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -3866,8 +3866,8 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com const dummy_ptr = try trash_block.addTy(.alloc, mut_final_ptr_ty); const empty_trash_count = trash_block.instructions.items.len; - for (placeholders, 0..) |bitcast_inst, i| { - const sub_ptr_ty = sema.typeOf(Air.indexToRef(bitcast_inst)); + for (peer_inst_list, placeholders) |peer_inst, placeholder_inst| { + const sub_ptr_ty = sema.typeOf(Air.indexToRef(placeholder_inst)); if (mut_final_ptr_ty.eql(sub_ptr_ty, sema.mod)) { // New result location type is the same as the old one; nothing @@ -3875,39 +3875,54 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com continue; } - var bitcast_block = block.makeSubBlock(); - defer bitcast_block.instructions.deinit(gpa); + var replacement_block = block.makeSubBlock(); + defer replacement_block.instructions.deinit(gpa); - trash_block.instructions.shrinkRetainingCapacity(empty_trash_count); - const sub_ptr = try sema.coerceResultPtr(&bitcast_block, src, ptr, dummy_ptr, peer_inst_list[i], &trash_block); + const result = switch (sema.air_instructions.items(.tag)[placeholder_inst]) { + .bitcast => result: { + trash_block.instructions.shrinkRetainingCapacity(empty_trash_count); + const sub_ptr = try sema.coerceResultPtr(&replacement_block, src, ptr, dummy_ptr, peer_inst, &trash_block); + + assert(replacement_block.instructions.items.len > 0); + break :result sub_ptr; + }, + .store => result: { + const bin_op = sema.air_instructions.items(.data)[placeholder_inst].bin_op; + try sema.storePtr2(&replacement_block, src, bin_op.lhs, src, bin_op.rhs, src, .bitcast); + break :result .void_value; + }, + else => unreachable, + }; - assert(bitcast_block.instructions.items.len > 0); // If only one instruction is produced then we can replace the bitcast // placeholder instruction with this instruction; no need for an entire block. - if (bitcast_block.instructions.items.len == 1) { - const only_inst = bitcast_block.instructions.items[0]; - sema.air_instructions.set(bitcast_inst, sema.air_instructions.get(only_inst)); + if (replacement_block.instructions.items.len == 1) { + const only_inst = replacement_block.instructions.items[0]; + sema.air_instructions.set(placeholder_inst, sema.air_instructions.get(only_inst)); continue; } // Here we replace the placeholder bitcast instruction with a block // that does the coerce_result_ptr logic. - _ = try bitcast_block.addBr(bitcast_inst, sub_ptr); - const ty_inst = sema.air_instructions.items(.data)[bitcast_inst].ty_op.ty; + _ = try replacement_block.addBr(placeholder_inst, result); + const ty_inst = if (result == .void_value) + .void_type + else + sema.air_instructions.items(.data)[placeholder_inst].ty_op.ty; try sema.air_extra.ensureUnusedCapacity( gpa, - @typeInfo(Air.Block).Struct.fields.len + bitcast_block.instructions.items.len, + @typeInfo(Air.Block).Struct.fields.len + replacement_block.instructions.items.len, ); - sema.air_instructions.set(bitcast_inst, .{ + sema.air_instructions.set(placeholder_inst, .{ .tag = .block, .data = .{ .ty_pl = .{ .ty = ty_inst, .payload = sema.addExtraAssumeCapacity(Air.Block{ - .body_len = @intCast(u32, bitcast_block.instructions.items.len), + .body_len = @intCast(u32, replacement_block.instructions.items.len), }), } }, }); - sema.air_extra.appendSliceAssumeCapacity(bitcast_block.instructions.items); + sema.air_extra.appendSliceAssumeCapacity(replacement_block.instructions.items); } }, else => unreachable, @@ -4916,7 +4931,7 @@ fn zirStoreToBlockPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE }, .inferred_alloc => { const inferred_alloc = ptr_val.castTag(.inferred_alloc).?; - return sema.storeToInferredAlloc(block, src, ptr, operand, inferred_alloc); + return sema.storeToInferredAlloc(block, ptr, operand, inferred_alloc); }, else => break :blk, } @@ -4945,7 +4960,7 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi }, .inferred_alloc => { const inferred_alloc = ptr_val.castTag(.inferred_alloc).?; - return sema.storeToInferredAlloc(block, src, ptr, operand, inferred_alloc); + return sema.storeToInferredAlloc(block, ptr, operand, inferred_alloc); }, else => unreachable, } @@ -4954,27 +4969,19 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi fn storeToInferredAlloc( sema: *Sema, block: *Block, - src: LazySrcLoc, ptr: Air.Inst.Ref, operand: Air.Inst.Ref, inferred_alloc: *Value.Payload.InferredAlloc, ) CompileError!void { - const operand_ty = sema.typeOf(operand); - // Create a runtime bitcast instruction with exactly the type the pointer wants. - const target = sema.mod.getTarget(); - const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ - .pointee_type = operand_ty, - .@"align" = inferred_alloc.data.alignment, - .@"addrspace" = target_util.defaultAddressSpace(target, .local), - }); - const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr); + // Create a store instruction as a placeholder. This will be replaced by a + // proper store sequence once we know the stored type. + const dummy_store = try block.addBinOp(.store, ptr, operand); // Add the stored instruction to the set we will use to resolve peer types // for the inferred allocation. try inferred_alloc.data.prongs.append(sema.arena, .{ .stored_inst = operand, - .placeholder = Air.refToIndex(bitcasted_ptr).?, + .placeholder = Air.refToIndex(dummy_store).?, }); - return sema.storePtr2(block, src, bitcasted_ptr, src, operand, src, .bitcast); } fn storeToInferredAllocComptime( |
