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