| ... | @@ -1974,8 +1974,6 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE | ... | @@ -1974,8 +1974,6 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 1974 | defer trash_block.instructions.deinit(sema.gpa); | 1974 | defer trash_block.instructions.deinit(sema.gpa); |
| 1975 | const operand = try trash_block.addBitCast(pointee_ty, .void_value); | 1975 | const operand = try trash_block.addBitCast(pointee_ty, .void_value); |
| 1976 | | 1976 | |
| 1977 | try inferred_alloc.stored_inst_list.append(sema.arena, operand); | | |
| 1978 | | | |
| 1979 | try sema.requireRuntimeBlock(block, src); | 1977 | try sema.requireRuntimeBlock(block, src); |
| 1980 | const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ | 1978 | const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| 1981 | .pointee_type = pointee_ty, | 1979 | .pointee_type = pointee_ty, |
| ... | @@ -1983,6 +1981,12 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE | ... | @@ -1983,6 +1981,12 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 1983 | .@"addrspace" = addr_space, | 1981 | .@"addrspace" = addr_space, |
| 1984 | }); | 1982 | }); |
| 1985 | const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr); | 1983 | const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr); |
| | 1984 | |
| | 1985 | try inferred_alloc.prongs.append(sema.arena, .{ |
| | 1986 | .stored_inst = operand, |
| | 1987 | .placeholder = Air.refToIndex(bitcasted_ptr).?, |
| | 1988 | }); |
| | 1989 | |
| 1986 | return bitcasted_ptr; | 1990 | return bitcasted_ptr; |
| 1987 | }, | 1991 | }, |
| 1988 | .inferred_alloc_comptime => { | 1992 | .inferred_alloc_comptime => { |
| ... | @@ -2027,7 +2031,24 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE | ... | @@ -2027,7 +2031,24 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 2027 | | 2031 | |
| 2028 | const dummy_ptr = try trash_block.addTy(.alloc, sema.typeOf(ptr)); | 2032 | const dummy_ptr = try trash_block.addTy(.alloc, sema.typeOf(ptr)); |
| 2029 | const dummy_operand = try trash_block.addBitCast(pointee_ty, .void_value); | 2033 | const dummy_operand = try trash_block.addBitCast(pointee_ty, .void_value); |
| 2030 | try sema.storePtr2(&trash_block, src, dummy_ptr, src, dummy_operand, src, .bitcast); | 2034 | return coerceResultPtr(sema, block, src, ptr, dummy_ptr, dummy_operand, &trash_block); |
| | 2035 | } |
| | 2036 | |
| | 2037 | fn coerceResultPtr( |
| | 2038 | sema: *Sema, |
| | 2039 | block: *Block, |
| | 2040 | src: LazySrcLoc, |
| | 2041 | ptr: Air.Inst.Ref, |
| | 2042 | dummy_ptr: Air.Inst.Ref, |
| | 2043 | dummy_operand: Air.Inst.Ref, |
| | 2044 | trash_block: *Block, |
| | 2045 | ) CompileError!Air.Inst.Ref { |
| | 2046 | const target = sema.mod.getTarget(); |
| | 2047 | const addr_space = target_util.defaultAddressSpace(target, .local); |
| | 2048 | const pointee_ty = sema.typeOf(dummy_operand); |
| | 2049 | const prev_trash_len = trash_block.instructions.items.len; |
| | 2050 | |
| | 2051 | try sema.storePtr2(trash_block, src, dummy_ptr, src, dummy_operand, src, .bitcast); |
| 2031 | | 2052 | |
| 2032 | { | 2053 | { |
| 2033 | const air_tags = sema.air_instructions.items(.tag); | 2054 | const air_tags = sema.air_instructions.items(.tag); |
| ... | @@ -2059,15 +2080,24 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE | ... | @@ -2059,15 +2080,24 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 2059 | while (true) { | 2080 | while (true) { |
| 2060 | const air_tags = sema.air_instructions.items(.tag); | 2081 | const air_tags = sema.air_instructions.items(.tag); |
| 2061 | const air_datas = sema.air_instructions.items(.data); | 2082 | const air_datas = sema.air_instructions.items(.data); |
| | 2083 | |
| | 2084 | if (trash_block.instructions.items.len == prev_trash_len) { |
| | 2085 | if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| { |
| | 2086 | return sema.addConstant(ptr_ty, ptr_val); |
| | 2087 | } |
| | 2088 | if (pointee_ty.eql(Type.@"null", sema.mod)) { |
| | 2089 | const opt_ty = sema.typeOf(new_ptr).childType(); |
| | 2090 | const null_inst = try sema.addConstant(opt_ty, Value.@"null"); |
| | 2091 | _ = try block.addBinOp(.store, new_ptr, null_inst); |
| | 2092 | return Air.Inst.Ref.void_value; |
| | 2093 | } |
| | 2094 | return sema.bitCast(block, ptr_ty, new_ptr, src); |
| | 2095 | } |
| | 2096 | |
| 2062 | const trash_inst = trash_block.instructions.pop(); | 2097 | const trash_inst = trash_block.instructions.pop(); |
| | 2098 | |
| 2063 | switch (air_tags[trash_inst]) { | 2099 | switch (air_tags[trash_inst]) { |
| 2064 | .bitcast => { | 2100 | .bitcast => { |
| 2065 | if (Air.indexToRef(trash_inst) == dummy_operand) { | | |
| 2066 | if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| { | | |
| 2067 | return sema.addConstant(ptr_ty, ptr_val); | | |
| 2068 | } | | |
| 2069 | return sema.bitCast(block, ptr_ty, new_ptr, src); | | |
| 2070 | } | | |
| 2071 | const ty_op = air_datas[trash_inst].ty_op; | 2101 | const ty_op = air_datas[trash_inst].ty_op; |
| 2072 | const operand_ty = sema.typeOf(ty_op.operand); | 2102 | const operand_ty = sema.typeOf(ty_op.operand); |
| 2073 | const ptr_operand_ty = try Type.ptr(sema.arena, sema.mod, .{ | 2103 | const ptr_operand_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| ... | @@ -3141,7 +3171,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com | ... | @@ -3141,7 +3171,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 3141 | }, | 3171 | }, |
| 3142 | .inferred_alloc => { | 3172 | .inferred_alloc => { |
| 3143 | const inferred_alloc = ptr_val.castTag(.inferred_alloc).?; | 3173 | const inferred_alloc = ptr_val.castTag(.inferred_alloc).?; |
| 3144 | const peer_inst_list = inferred_alloc.data.stored_inst_list.items; | 3174 | const peer_inst_list = inferred_alloc.data.prongs.items(.stored_inst); |
| 3145 | const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_inst_list, .none); | 3175 | const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_inst_list, .none); |
| 3146 | | 3176 | |
| 3147 | const final_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ | 3177 | const final_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| ... | @@ -3250,6 +3280,70 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com | ... | @@ -3250,6 +3280,70 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 3250 | .tag = .alloc, | 3280 | .tag = .alloc, |
| 3251 | .data = .{ .ty = final_ptr_ty }, | 3281 | .data = .{ .ty = final_ptr_ty }, |
| 3252 | }); | 3282 | }); |
| | 3283 | |
| | 3284 | // Now we need to go back over all the coerce_result_ptr instructions, which |
| | 3285 | // previously inserted a bitcast as a placeholder, and do the logic as if |
| | 3286 | // the new result ptr type was available. |
| | 3287 | const placeholders = inferred_alloc.data.prongs.items(.placeholder); |
| | 3288 | const gpa = sema.gpa; |
| | 3289 | |
| | 3290 | var trash_block = block.makeSubBlock(); |
| | 3291 | trash_block.is_comptime = false; |
| | 3292 | trash_block.is_coerce_result_ptr = true; |
| | 3293 | defer trash_block.instructions.deinit(gpa); |
| | 3294 | |
| | 3295 | const mut_final_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| | 3296 | .pointee_type = final_elem_ty, |
| | 3297 | .mutable = true, |
| | 3298 | .@"align" = inferred_alloc.data.alignment, |
| | 3299 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| | 3300 | }); |
| | 3301 | const dummy_ptr = try trash_block.addTy(.alloc, mut_final_ptr_ty); |
| | 3302 | const empty_trash_count = trash_block.instructions.items.len; |
| | 3303 | |
| | 3304 | for (placeholders) |bitcast_inst, i| { |
| | 3305 | const sub_ptr_ty = sema.typeOf(Air.indexToRef(bitcast_inst)); |
| | 3306 | |
| | 3307 | if (mut_final_ptr_ty.eql(sub_ptr_ty, sema.mod)) { |
| | 3308 | // New result location type is the same as the old one; nothing |
| | 3309 | // to do here. |
| | 3310 | continue; |
| | 3311 | } |
| | 3312 | |
| | 3313 | var bitcast_block = block.makeSubBlock(); |
| | 3314 | defer bitcast_block.instructions.deinit(gpa); |
| | 3315 | |
| | 3316 | trash_block.instructions.shrinkRetainingCapacity(empty_trash_count); |
| | 3317 | const sub_ptr = try coerceResultPtr(sema, &bitcast_block, src, ptr, dummy_ptr, peer_inst_list[i], &trash_block); |
| | 3318 | |
| | 3319 | assert(bitcast_block.instructions.items.len > 0); |
| | 3320 | // If only one instruction is produced then we can replace the bitcast |
| | 3321 | // placeholder instruction with this instruction; no need for an entire block. |
| | 3322 | if (bitcast_block.instructions.items.len == 1) { |
| | 3323 | const only_inst = bitcast_block.instructions.items[0]; |
| | 3324 | sema.air_instructions.set(bitcast_inst, sema.air_instructions.get(only_inst)); |
| | 3325 | continue; |
| | 3326 | } |
| | 3327 | |
| | 3328 | // Here we replace the placeholder bitcast instruction with a block |
| | 3329 | // that does the coerce_result_ptr logic. |
| | 3330 | _ = try bitcast_block.addBr(bitcast_inst, sub_ptr); |
| | 3331 | const ty_inst = sema.air_instructions.items(.data)[bitcast_inst].ty_op.ty; |
| | 3332 | try sema.air_extra.ensureUnusedCapacity( |
| | 3333 | gpa, |
| | 3334 | @typeInfo(Air.Block).Struct.fields.len + bitcast_block.instructions.items.len, |
| | 3335 | ); |
| | 3336 | sema.air_instructions.set(bitcast_inst, .{ |
| | 3337 | .tag = .block, |
| | 3338 | .data = .{ .ty_pl = .{ |
| | 3339 | .ty = ty_inst, |
| | 3340 | .payload = sema.addExtraAssumeCapacity(Air.Block{ |
| | 3341 | .body_len = @intCast(u32, bitcast_block.instructions.items.len), |
| | 3342 | }), |
| | 3343 | } }, |
| | 3344 | }); |
| | 3345 | sema.air_extra.appendSliceAssumeCapacity(bitcast_block.instructions.items); |
| | 3346 | } |
| 3253 | }, | 3347 | }, |
| 3254 | else => unreachable, | 3348 | else => unreachable, |
| 3255 | } | 3349 | } |
| ... | @@ -4086,9 +4180,6 @@ fn storeToInferredAlloc( | ... | @@ -4086,9 +4180,6 @@ fn storeToInferredAlloc( |
| 4086 | inferred_alloc: *Value.Payload.InferredAlloc, | 4180 | inferred_alloc: *Value.Payload.InferredAlloc, |
| 4087 | ) CompileError!void { | 4181 | ) CompileError!void { |
| 4088 | const operand_ty = sema.typeOf(operand); | 4182 | const operand_ty = sema.typeOf(operand); |
| 4089 | // Add the stored instruction to the set we will use to resolve peer types | | |
| 4090 | // for the inferred allocation. | | |
| 4091 | try inferred_alloc.data.stored_inst_list.append(sema.arena, operand); | | |
| 4092 | // Create a runtime bitcast instruction with exactly the type the pointer wants. | 4183 | // Create a runtime bitcast instruction with exactly the type the pointer wants. |
| 4093 | const target = sema.mod.getTarget(); | 4184 | const target = sema.mod.getTarget(); |
| 4094 | const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ | 4185 | const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| ... | @@ -4097,7 +4188,13 @@ fn storeToInferredAlloc( | ... | @@ -4097,7 +4188,13 @@ fn storeToInferredAlloc( |
| 4097 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), | 4188 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 4098 | }); | 4189 | }); |
| 4099 | const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr); | 4190 | const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr); |
| 4100 | return sema.storePtr(block, src, bitcasted_ptr, operand); | 4191 | // Add the stored instruction to the set we will use to resolve peer types |
| | 4192 | // for the inferred allocation. |
| | 4193 | try inferred_alloc.data.prongs.append(sema.arena, .{ |
| | 4194 | .stored_inst = operand, |
| | 4195 | .placeholder = Air.refToIndex(bitcasted_ptr).?, |
| | 4196 | }); |
| | 4197 | return sema.storePtr2(block, src, bitcasted_ptr, src, operand, src, .bitcast); |
| 4101 | } | 4198 | } |
| 4102 | | 4199 | |
| 4103 | fn storeToInferredAllocComptime( | 4200 | fn storeToInferredAllocComptime( |
| ... | @@ -21614,8 +21711,6 @@ fn storePtr2( | ... | @@ -21614,8 +21711,6 @@ fn storePtr2( |
| 21614 | if ((try sema.typeHasOnePossibleValue(block, src, elem_ty)) != null) | 21711 | if ((try sema.typeHasOnePossibleValue(block, src, elem_ty)) != null) |
| 21615 | return; | 21712 | return; |
| 21616 | | 21713 | |
| 21617 | // TODO handle if the element type requires comptime | | |
| 21618 | | | |
| 21619 | if (air_tag == .bitcast) { | 21714 | if (air_tag == .bitcast) { |
| 21620 | // `air_tag == .bitcast` is used as a special case for `zirCoerceResultPtr` | 21715 | // `air_tag == .bitcast` is used as a special case for `zirCoerceResultPtr` |
| 21621 | // to avoid calling `requireRuntimeBlock` for the dummy block. | 21716 | // to avoid calling `requireRuntimeBlock` for the dummy block. |