| ... | ... | @@ -2488,9 +2488,7 @@ pub fn genFunc(f: *Function) !void { |
| 2488 | 2488 | const local = f.locals.items[local_index]; |
| 2489 | 2489 | log.debug("inserting local {d} into free_locals", .{local_index}); |
| 2490 | 2490 | const gop = try f.free_locals.getOrPutContext(gpa, local.ty, f.tyHashCtx()); |
| 2491 | | if (!gop.found_existing) { |
| 2492 | | gop.value_ptr.* = .{}; |
| 2493 | | } |
| 2491 | if (!gop.found_existing) gop.value_ptr.* = .{}; |
| 2494 | 2492 | try gop.value_ptr.append(gpa, local_index); |
| 2495 | 2493 | } |
| 2496 | 2494 | |
| ... | ... | @@ -3819,14 +3817,16 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3819 | 3817 | const inst_ty = f.air.typeOfIndex(inst); |
| 3820 | 3818 | const local = try f.allocLocal(inst, inst_ty); |
| 3821 | 3819 | try f.writeCValue(writer, local, .Other); |
| 3822 | | try writer.writeAll(" = {("); |
| 3820 | try writer.writeAll(".ptr = ("); |
| 3823 | 3821 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 3824 | 3822 | try f.renderTypecast(writer, inst_ty.slicePtrFieldType(&buf)); |
| 3825 | 3823 | try writer.writeByte(')'); |
| 3826 | 3824 | try f.writeCValue(writer, ptr, .Other); |
| 3827 | | try writer.writeAll(", "); |
| 3825 | try writer.writeAll("; "); |
| 3826 | try f.writeCValue(writer, local, .Other); |
| 3827 | try writer.writeAll(".len = "); |
| 3828 | 3828 | try f.writeCValue(writer, len, .Initializer); |
| 3829 | | try writer.writeAll("};\n"); |
| 3829 | try writer.writeAll(";\n"); |
| 3830 | 3830 | |
| 3831 | 3831 | return local; |
| 3832 | 3832 | } |
| ... | ... | @@ -4292,6 +4292,11 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4292 | 4292 | try die(f, inst, Air.indexToRef(operand)); |
| 4293 | 4293 | } |
| 4294 | 4294 | |
| 4295 | // Remember how many locals there were before entering the then branch so |
| 4296 | // that we can notice and use them in the else branch. Any new locals must |
| 4297 | // necessarily be free already after the then branch is complete. |
| 4298 | const pre_locals_len = @intCast(LocalIndex, f.locals.items.len); |
| 4299 | |
| 4295 | 4300 | try writer.writeAll("if ("); |
| 4296 | 4301 | try f.writeCValue(writer, cond, .Other); |
| 4297 | 4302 | try writer.writeAll(") "); |
| ... | ... | @@ -4304,6 +4309,9 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4304 | 4309 | for (liveness_condbr.else_deaths) |operand| { |
| 4305 | 4310 | try die(f, inst, Air.indexToRef(operand)); |
| 4306 | 4311 | } |
| 4312 | |
| 4313 | try noticeBranchFrees(f, pre_locals_len); |
| 4314 | |
| 4307 | 4315 | try genBody(f, else_body); |
| 4308 | 4316 | try f.object.indent_writer.insertNewline(); |
| 4309 | 4317 | |
| ... | ... | @@ -4335,10 +4343,12 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4335 | 4343 | const gpa = f.object.dg.gpa; |
| 4336 | 4344 | const liveness = try f.liveness.getSwitchBr(gpa, inst, switch_br.data.cases_len + 1); |
| 4337 | 4345 | defer gpa.free(liveness.deaths); |
| 4346 | |
| 4338 | 4347 | // On the final iteration we do not clone the map. This ensures that |
| 4339 | 4348 | // lowering proceeds after the switch_br taking into account the |
| 4340 | 4349 | // mutations to the liveness information. |
| 4341 | 4350 | const last_case_i = switch_br.data.cases_len - @boolToInt(switch_br.data.else_body_len == 0); |
| 4351 | |
| 4342 | 4352 | var extra_index: usize = switch_br.end; |
| 4343 | 4353 | var case_i: u32 = 0; |
| 4344 | 4354 | while (case_i < switch_br.data.cases_len) : (case_i += 1) { |
| ... | ... | @@ -4358,31 +4368,43 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4358 | 4368 | try f.object.dg.renderValue(writer, condition_ty, f.air.value(item).?, .Other); |
| 4359 | 4369 | try writer.writeAll(": "); |
| 4360 | 4370 | } |
| 4371 | |
| 4361 | 4372 | if (case_i != last_case_i) { |
| 4362 | 4373 | const old_value_map = f.value_map; |
| 4363 | 4374 | f.value_map = try old_value_map.clone(); |
| 4364 | 4375 | const old_free_locals = f.free_locals; |
| 4365 | 4376 | f.free_locals = try cloneFreeLocalsMap(gpa, &f.free_locals); |
| 4366 | 4377 | |
| 4367 | | defer { |
| 4368 | | f.value_map.deinit(); |
| 4369 | | deinitFreeLocalsMap(gpa, &f.free_locals); |
| 4370 | | f.value_map = old_value_map; |
| 4371 | | f.free_locals = old_free_locals; |
| 4372 | | } |
| 4378 | // Remember how many locals there were before entering each branch so that |
| 4379 | // we can notice and use them in subsequent branches. Any new locals must |
| 4380 | // necessarily be free already after the previous branch is complete. |
| 4381 | const pre_locals_len = @intCast(LocalIndex, f.locals.items.len); |
| 4373 | 4382 | |
| 4374 | | for (liveness.deaths[case_i]) |operand| { |
| 4375 | | try die(f, inst, Air.indexToRef(operand)); |
| 4383 | { |
| 4384 | defer { |
| 4385 | f.value_map.deinit(); |
| 4386 | deinitFreeLocalsMap(gpa, &f.free_locals); |
| 4387 | f.value_map = old_value_map; |
| 4388 | f.free_locals = old_free_locals; |
| 4389 | } |
| 4390 | |
| 4391 | for (liveness.deaths[case_i]) |operand| { |
| 4392 | try die(f, inst, Air.indexToRef(operand)); |
| 4393 | } |
| 4394 | |
| 4395 | try genBody(f, case_body); |
| 4376 | 4396 | } |
| 4377 | 4397 | |
| 4378 | | try genBody(f, case_body); |
| 4398 | try noticeBranchFrees(f, pre_locals_len); |
| 4379 | 4399 | } else { |
| 4380 | 4400 | for (liveness.deaths[case_i]) |operand| { |
| 4381 | 4401 | try die(f, inst, Air.indexToRef(operand)); |
| 4382 | 4402 | } |
| 4383 | 4403 | try genBody(f, case_body); |
| 4384 | 4404 | } |
| 4405 | |
| 4385 | 4406 | // The case body must be noreturn so we don't need to insert a break. |
| 4407 | |
| 4386 | 4408 | } |
| 4387 | 4409 | |
| 4388 | 4410 | const else_body = f.air.extra[extra_index..][0..switch_br.data.else_body_len]; |
| ... | ... | @@ -5278,12 +5300,16 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5278 | 5300 | try reap(f, inst, &.{ty_op.operand}); |
| 5279 | 5301 | const writer = f.object.writer(); |
| 5280 | 5302 | const local = try f.allocLocal(inst, inst_ty); |
| 5303 | if (!is_array) { |
| 5304 | try f.writeCValue(writer, local, .Other); |
| 5305 | try writer.writeAll(".payload = "); |
| 5306 | try f.writeCValue(writer, payload, .Other); |
| 5307 | try writer.writeAll("; "); |
| 5308 | } |
| 5281 | 5309 | try f.writeCValue(writer, local, .Other); |
| 5282 | | try writer.writeAll(" = { .payload = "); |
| 5283 | | try f.writeCValue(writer, if (is_array) CValue{ .undef = payload_ty } else payload, .Initializer); |
| 5284 | | try writer.writeAll(", .is_null = "); |
| 5310 | try writer.writeAll(".is_null = "); |
| 5285 | 5311 | try f.object.dg.renderValue(writer, Type.bool, Value.false, .Initializer); |
| 5286 | | try writer.writeAll(" };\n"); |
| 5312 | try writer.writeAll(";\n"); |
| 5287 | 5313 | if (is_array) { |
| 5288 | 5314 | try writer.writeAll("memcpy("); |
| 5289 | 5315 | try f.writeCValueMember(writer, local, .{ .identifier = "payload" }); |
| ... | ... | @@ -5312,12 +5338,14 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5312 | 5338 | try reap(f, inst, &.{ty_op.operand}); |
| 5313 | 5339 | |
| 5314 | 5340 | const local = try f.allocLocal(inst, error_union_ty); |
| 5341 | { |
| 5342 | // TODO: set the payload to undefined |
| 5343 | //try f.writeCValue(writer, local, .Other); |
| 5344 | } |
| 5315 | 5345 | try f.writeCValue(writer, local, .Other); |
| 5316 | | try writer.writeAll(" = { .payload = "); |
| 5317 | | try f.writeCValue(writer, .{ .undef = payload_ty }, .Initializer); |
| 5318 | | try writer.writeAll(", .error = "); |
| 5319 | | try f.writeCValue(writer, operand, .Initializer); |
| 5320 | | try writer.writeAll(" };\n"); |
| 5346 | try writer.writeAll(".error = "); |
| 5347 | try f.writeCValue(writer, operand, .Other); |
| 5348 | try writer.writeAll(";\n"); |
| 5321 | 5349 | return local; |
| 5322 | 5350 | } |
| 5323 | 5351 | |
| ... | ... | @@ -5379,7 +5407,6 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5379 | 5407 | } |
| 5380 | 5408 | |
| 5381 | 5409 | const inst_ty = f.air.typeOfIndex(inst); |
| 5382 | | const error_ty = inst_ty.errorUnionSet(); |
| 5383 | 5410 | const payload_ty = inst_ty.errorUnionPayload(); |
| 5384 | 5411 | const payload = try f.resolveInst(ty_op.operand); |
| 5385 | 5412 | try reap(f, inst, &.{ty_op.operand}); |
| ... | ... | @@ -5389,12 +5416,14 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5389 | 5416 | |
| 5390 | 5417 | const writer = f.object.writer(); |
| 5391 | 5418 | const local = try f.allocLocal(inst, inst_ty); |
| 5419 | if (!is_array) { |
| 5420 | try f.writeCValue(writer, local, .Other); |
| 5421 | try writer.writeAll(".payload = "); |
| 5422 | try f.writeCValue(writer, payload, .Other); |
| 5423 | try writer.writeAll("; "); |
| 5424 | } |
| 5392 | 5425 | try f.writeCValue(writer, local, .Other); |
| 5393 | | try writer.writeAll(" = { .payload = "); |
| 5394 | | try f.writeCValue(writer, if (is_array) CValue{ .undef = payload_ty } else payload, .Initializer); |
| 5395 | | try writer.writeAll(", .error = "); |
| 5396 | | try f.object.dg.renderValue(writer, error_ty, Value.zero, .Initializer); |
| 5397 | | try writer.writeAll(" };\n"); |
| 5426 | try writer.writeAll(".error = 0;\n"); |
| 5398 | 5427 | if (is_array) { |
| 5399 | 5428 | try writer.writeAll("memcpy("); |
| 5400 | 5429 | try f.writeCValueMember(writer, local, .{ .identifier = "payload" }); |
| ... | ... | @@ -6911,6 +6940,8 @@ fn freeLocal(f: *Function, inst: Air.Inst.Index, local_index: LocalIndex, ref_in |
| 6911 | 6940 | // free_locals map while it already exists in the map, which is not |
| 6912 | 6941 | // allowed. |
| 6913 | 6942 | assert(mem.indexOfScalar(LocalIndex, gop.value_ptr.items, local_index) == null); |
| 6943 | // If this trips, an unfreeable allocation was attempted to be freed. |
| 6944 | assert(!f.allocs.contains(local_index)); |
| 6914 | 6945 | } |
| 6915 | 6946 | try gop.value_ptr.append(gpa, local_index); |
| 6916 | 6947 | } |
| ... | ... | @@ -6960,3 +6991,16 @@ fn deinitFreeLocalsMap(gpa: mem.Allocator, map: *LocalsMap) void { |
| 6960 | 6991 | } |
| 6961 | 6992 | map.deinit(gpa); |
| 6962 | 6993 | } |
| 6994 | |
| 6995 | fn noticeBranchFrees(f: *Function, pre_locals_len: LocalIndex) !void { |
| 6996 | const gpa = f.object.dg.gpa; |
| 6997 | var i = pre_locals_len; |
| 6998 | while (i < f.locals.items.len) : (i += 1) { |
| 6999 | const local = f.locals.items[i]; |
| 7000 | const unfreeable = f.allocs.contains(i); |
| 7001 | if (unfreeable) continue; |
| 7002 | const gop = try f.free_locals.getOrPutContext(gpa, local.ty, f.tyHashCtx()); |
| 7003 | if (!gop.found_existing) gop.value_ptr.* = .{}; |
| 7004 | try gop.value_ptr.append(gpa, i); |
| 7005 | } |
| 7006 | } |