authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-04-06 01:26:24-04:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-04-07 01:29:20+01:00
loga7f674d6c1ba3d72a324aa918929c5beb36a8306
treebe113ae7f9c57c48cac90da082f532f7c47a1e77
parent1059b57898ec929e9d6ebd8c35660acffe0bac99
signaturelock-open Commit is signed but in an unrecognized format.

cbe: assert there are no unfreed locals

Also fix the many revealed bugs.

1 files changed, 93 insertions(+), 73 deletions(-)

src/codegen/c.zig+93-73
...@@ -55,7 +55,7 @@ const BlockData = struct {...@@ -55,7 +55,7 @@ const BlockData = struct {
55 result: CValue,55 result: CValue,
56};56};
5757
58pub const CValueMap = std.AutoHashMap(Air.Inst.Ref, CValue);58pub const CValueMap = std.AutoHashMap(Air.Inst.Index, CValue);
5959
60pub const LazyFnKey = union(enum) {60pub const LazyFnKey = union(enum) {
61 tag_name: Decl.Index,61 tag_name: Decl.Index,
...@@ -289,29 +289,31 @@ pub const Function = struct {...@@ -289,29 +289,31 @@ pub const Function = struct {
289 /// Needed for memory used by the keys of free_locals_map entries.289 /// Needed for memory used by the keys of free_locals_map entries.
290 arena: std.heap.ArenaAllocator,290 arena: std.heap.ArenaAllocator,
291291
292 fn resolveInst(f: *Function, inst: Air.Inst.Ref) !CValue {292 fn resolveInst(f: *Function, ref: Air.Inst.Ref) !CValue {
293 const gop = try f.value_map.getOrPut(inst);293 if (Air.refToIndex(ref)) |inst| {
294 if (gop.found_existing) return gop.value_ptr.*;294 const gop = try f.value_map.getOrPut(inst);
295295 if (gop.found_existing) return gop.value_ptr.*;
296 const val = f.air.value(inst).?;
297 const ty = f.air.typeOf(inst);
298
299 const result: CValue = if (lowersToArray(ty, f.object.dg.module.getTarget())) result: {
300 const writer = f.object.code_header.writer();
301 const alignment = 0;
302 const decl_c_value = try f.allocLocalValue(ty, alignment);
303 const gpa = f.object.dg.gpa;
304 try f.allocs.put(gpa, decl_c_value.new_local, true);
305 try writer.writeAll("static ");
306 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, Const, alignment, .complete);
307 try writer.writeAll(" = ");
308 try f.object.dg.renderValue(writer, ty, val, .StaticInitializer);
309 try writer.writeAll(";\n ");
310 break :result decl_c_value;
311 } else .{ .constant = inst };
312296
313 gop.value_ptr.* = result;297 const val = f.air.value(ref).?;
314 return result;298 const ty = f.air.typeOf(ref);
299
300 const result: CValue = if (lowersToArray(ty, f.object.dg.module.getTarget())) result: {
301 const writer = f.object.code_header.writer();
302 const alignment = 0;
303 const decl_c_value = try f.allocLocalValue(ty, alignment);
304 const gpa = f.object.dg.gpa;
305 try f.allocs.put(gpa, decl_c_value.new_local, true);
306 try writer.writeAll("static ");
307 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, Const, alignment, .complete);
308 try writer.writeAll(" = ");
309 try f.object.dg.renderValue(writer, ty, val, .StaticInitializer);
310 try writer.writeAll(";\n ");
311 break :result decl_c_value;
312 } else .{ .constant = ref };
313
314 gop.value_ptr.* = result;
315 return result;
316 } else return .{ .constant = ref };
315 }317 }
316318
317 fn wantSafety(f: *Function) bool {319 fn wantSafety(f: *Function) bool {
...@@ -2594,6 +2596,7 @@ pub fn genFunc(f: *Function) !void {...@@ -2594,6 +2596,7 @@ pub fn genFunc(f: *Function) !void {
2594 // missing. These are added now to complete the map. Then we can sort by2596 // missing. These are added now to complete the map. Then we can sort by
2595 // alignment, descending.2597 // alignment, descending.
2596 const free_locals = &f.free_locals_map;2598 const free_locals = &f.free_locals_map;
2599 assert(f.value_map.count() == 0); // there must not be any unfreed locals
2597 for (f.allocs.keys(), f.allocs.values()) |local_index, value| {2600 for (f.allocs.keys(), f.allocs.values()) |local_index, value| {
2598 if (value) continue; // static2601 if (value) continue; // static
2599 const local = f.locals.items[local_index];2602 const local = f.locals.items[local_index];
...@@ -2995,7 +2998,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,...@@ -2995,7 +2998,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
2995 if (result_value == .new_local) {2998 if (result_value == .new_local) {
2996 log.debug("map %{d} to t{d}", .{ inst, result_value.new_local });2999 log.debug("map %{d} to t{d}", .{ inst, result_value.new_local });
2997 }3000 }
2998 try f.value_map.putNoClobber(Air.indexToRef(inst), switch (result_value) {3001 try f.value_map.putNoClobber(inst, switch (result_value) {
2999 .none => continue,3002 .none => continue,
3000 .new_local => |i| .{ .local = i },3003 .new_local => |i| .{ .local = i },
3001 else => result_value,3004 else => result_value,
...@@ -3081,17 +3084,21 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3081,17 +3084,21 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
3081 const child_ty = ptr_ty.childType();3084 const child_ty = ptr_ty.childType();
30823085
3083 const ptr = try f.resolveInst(bin_op.lhs);3086 const ptr = try f.resolveInst(bin_op.lhs);
3084 if (!child_ty.hasRuntimeBitsIgnoreComptime()) {
3085 if (f.liveness.operandDies(inst, 1)) try die(f, inst, bin_op.rhs);
3086 return ptr;
3087 }
3088 const index = try f.resolveInst(bin_op.rhs);3087 const index = try f.resolveInst(bin_op.rhs);
3089 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3088 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
30903089
3091 const writer = f.object.writer();3090 const writer = f.object.writer();
3092 const local = try f.allocLocal(inst, f.air.typeOfIndex(inst));3091 const local = try f.allocLocal(inst, f.air.typeOfIndex(inst));
3093 try f.writeCValue(writer, local, .Other);3092 try f.writeCValue(writer, local, .Other);
3094 try writer.writeAll(" = (");3093 try writer.writeAll(" = ");
3094
3095 if (!child_ty.hasRuntimeBitsIgnoreComptime()) {
3096 try f.writeCValue(writer, ptr, .Initializer);
3097 try writer.writeAll(";\n");
3098 return local;
3099 }
3100
3101 try writer.writeByte('(');
3095 try f.renderType(writer, inst_ty);3102 try f.renderType(writer, inst_ty);
3096 try writer.writeAll(")&(");3103 try writer.writeAll(")&(");
3097 if (ptr_ty.ptrSize() == .One) {3104 if (ptr_ty.ptrSize() == .One) {
...@@ -3217,12 +3224,11 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3217,12 +3224,11 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
3217}3224}
32183225
3219fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {3226fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
3220 const inst_ty = f.air.typeOfIndex(inst);3227 if (f.liveness.isUnused(inst)) return .none;
32213228
3229 const inst_ty = f.air.typeOfIndex(inst);
3222 const elem_type = inst_ty.elemType();3230 const elem_type = inst_ty.elemType();
3223 if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) {3231 if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) return .{ .undef = inst_ty };
3224 return .{ .undef = inst_ty };
3225 }
32263232
3227 const target = f.object.dg.module.getTarget();3233 const target = f.object.dg.module.getTarget();
3228 const local = try f.allocAlignedLocal(3234 const local = try f.allocAlignedLocal(
...@@ -3237,12 +3243,11 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3237,12 +3243,11 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
3237}3243}
32383244
3239fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {3245fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
3240 const inst_ty = f.air.typeOfIndex(inst);3246 if (f.liveness.isUnused(inst)) return .none;
32413247
3248 const inst_ty = f.air.typeOfIndex(inst);
3242 const elem_ty = inst_ty.elemType();3249 const elem_ty = inst_ty.elemType();
3243 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {3250 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return .{ .undef = inst_ty };
3244 return .{ .undef = inst_ty };
3245 }
32463251
3247 const target = f.object.dg.module.getTarget();3252 const target = f.object.dg.module.getTarget();
3248 const local = try f.allocAlignedLocal(3253 const local = try f.allocAlignedLocal(
...@@ -3262,10 +3267,22 @@ fn airArg(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3262,10 +3267,22 @@ fn airArg(f: *Function, inst: Air.Inst.Index) !CValue {
32623267
3263 const i = f.next_arg_index;3268 const i = f.next_arg_index;
3264 f.next_arg_index += 1;3269 f.next_arg_index += 1;
3265 return if (inst_cty != try f.typeToIndex(inst_ty, .complete))3270 const result: CValue = if (inst_cty != try f.typeToIndex(inst_ty, .complete))
3266 .{ .arg_array = i }3271 .{ .arg_array = i }
3267 else3272 else
3268 .{ .arg = i };3273 .{ .arg = i };
3274
3275 if (f.liveness.isUnused(inst)) {
3276 const writer = f.object.writer();
3277 try writer.writeByte('(');
3278 try f.renderType(writer, Type.void);
3279 try writer.writeByte(')');
3280 try f.writeCValue(writer, result, .Other);
3281 try writer.writeAll(";\n");
3282 return .none;
3283 }
3284
3285 return result;
3269}3286}
32703287
3271fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {3288fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -4179,21 +4196,23 @@ fn airCall(...@@ -4179,21 +4196,23 @@ fn airCall(
4179 var lowered_ret_buf: LowerFnRetTyBuffer = undefined;4196 var lowered_ret_buf: LowerFnRetTyBuffer = undefined;
4180 const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target);4197 const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target);
41814198
4182 const result_local = if (modifier == .always_tail) r: {4199 const result_local = result: {
4183 try writer.writeAll("zig_always_tail return ");4200 if (modifier == .always_tail) {
4184 break :r .none;4201 try writer.writeAll("zig_always_tail return ");
4185 } else if (!lowered_ret_ty.hasRuntimeBitsIgnoreComptime())4202 break :result .none;
4186 .none4203 } else if (!lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) {
4187 else if (f.liveness.isUnused(inst)) r: {4204 break :result .none;
4188 try writer.writeByte('(');4205 } else if (f.liveness.isUnused(inst)) {
4189 try f.renderType(writer, Type.void);4206 try writer.writeByte('(');
4190 try writer.writeByte(')');4207 try f.renderType(writer, Type.void);
4191 break :r .none;4208 try writer.writeByte(')');
4192 } else r: {4209 break :result .none;
4193 const local = try f.allocLocal(inst, try lowered_ret_ty.copy(f.arena.allocator()));4210 } else {
4194 try f.writeCValue(writer, local, .Other);4211 const local = try f.allocLocal(inst, try lowered_ret_ty.copy(f.arena.allocator()));
4195 try writer.writeAll(" = ");4212 try f.writeCValue(writer, local, .Other);
4196 break :r local;4213 try writer.writeAll(" = ");
4214 break :result local;
4215 }
4197 };4216 };
41984217
4199 callee: {4218 callee: {
...@@ -4238,9 +4257,9 @@ fn airCall(...@@ -4238,9 +4257,9 @@ fn airCall(
4238 }4257 }
4239 try writer.writeAll(");\n");4258 try writer.writeAll(");\n");
42404259
4241 const result = r: {4260 const result = result: {
4242 if (result_local == .none or !lowersToArray(ret_ty, target))4261 if (result_local == .none or !lowersToArray(ret_ty, target))
4243 break :r result_local;4262 break :result result_local;
42444263
4245 const array_local = try f.allocLocal(inst, ret_ty);4264 const array_local = try f.allocLocal(inst, ret_ty);
4246 try writer.writeAll("memcpy(");4265 try writer.writeAll("memcpy(");
...@@ -4251,7 +4270,7 @@ fn airCall(...@@ -4251,7 +4270,7 @@ fn airCall(
4251 try f.renderType(writer, ret_ty);4270 try f.renderType(writer, ret_ty);
4252 try writer.writeAll("));\n");4271 try writer.writeAll("));\n");
4253 try freeLocal(f, inst, result_local.new_local, 0);4272 try freeLocal(f, inst, result_local.new_local, 0);
4254 break :r array_local;4273 break :result array_local;
4255 };4274 };
42564275
4257 return result;4276 return result;
...@@ -4468,7 +4487,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4468,7 +4487,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
4468 {4487 {
4469 try f.writeCValue(writer, local, .Other);4488 try f.writeCValue(writer, local, .Other);
4470 try writer.writeAll(" = ");4489 try writer.writeAll(" = ");
4471 try f.writeCValue(writer, operand, .Other);4490 try f.writeCValue(writer, operand, .Initializer);
4472 try writer.writeAll(";\n");4491 try writer.writeAll(";\n");
4473 return local;4492 return local;
4474 }4493 }
...@@ -4835,8 +4854,8 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4835,8 +4854,8 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4835 const inputs = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra_i..][0..extra.data.inputs_len]);4854 const inputs = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra_i..][0..extra.data.inputs_len]);
4836 extra_i += inputs.len;4855 extra_i += inputs.len;
48374856
4838 const result = r: {4857 const result = result: {
4839 if (!is_volatile and f.liveness.isUnused(inst)) break :r .none;4858 if (!is_volatile and f.liveness.isUnused(inst)) break :result .none;
48404859
4841 const writer = f.object.writer();4860 const writer = f.object.writer();
4842 const inst_ty = f.air.typeOfIndex(inst);4861 const inst_ty = f.air.typeOfIndex(inst);
...@@ -5064,7 +5083,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5064,7 +5083,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
5064 }5083 }
5065 }5084 }
50665085
5067 break :r local;5086 break :result if (f.liveness.isUnused(inst)) .none else local;
5068 };5087 };
50695088
5070 var bt = iterateBigTomb(f, inst);5089 var bt = iterateBigTomb(f, inst);
...@@ -7036,21 +7055,22 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -7036,21 +7055,22 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
70367055
7037fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {7056fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {
7038 const prefetch = f.air.instructions.items(.data)[inst].prefetch;7057 const prefetch = f.air.instructions.items(.data)[inst].prefetch;
7039 switch (prefetch.cache) {7058
7040 .data => {},
7041 // The available prefetch intrinsics do not accept a cache argument; only
7042 // address, rw, and locality. So unless the cache is data, we do not lower
7043 // this instruction.
7044 .instruction => return .none,
7045 }
7046 const ptr = try f.resolveInst(prefetch.ptr);7059 const ptr = try f.resolveInst(prefetch.ptr);
7047 try reap(f, inst, &.{prefetch.ptr});7060 try reap(f, inst, &.{prefetch.ptr});
7061
7048 const writer = f.object.writer();7062 const writer = f.object.writer();
7049 try writer.writeAll("zig_prefetch(");7063 switch (prefetch.cache) {
7050 try f.writeCValue(writer, ptr, .FunctionArgument);7064 .data => {
7051 try writer.print(", {d}, {d});\n", .{7065 try writer.writeAll("zig_prefetch(");
7052 @enumToInt(prefetch.rw), prefetch.locality,7066 try f.writeCValue(writer, ptr, .FunctionArgument);
7053 });7067 try writer.print(", {d}, {d});\n", .{ @enumToInt(prefetch.rw), prefetch.locality });
7068 },
7069 // The available prefetch intrinsics do not accept a cache argument; only
7070 // address, rw, and locality.
7071 .instruction => {},
7072 }
7073
7054 return .none;7074 return .none;
7055}7075}
70567076
...@@ -7830,8 +7850,8 @@ fn reap(f: *Function, inst: Air.Inst.Index, operands: []const Air.Inst.Ref) !voi...@@ -7830,8 +7850,8 @@ fn reap(f: *Function, inst: Air.Inst.Index, operands: []const Air.Inst.Ref) !voi
78307850
7831fn die(f: *Function, inst: Air.Inst.Index, ref: Air.Inst.Ref) !void {7851fn die(f: *Function, inst: Air.Inst.Index, ref: Air.Inst.Ref) !void {
7832 const ref_inst = Air.refToIndex(ref) orelse return;7852 const ref_inst = Air.refToIndex(ref) orelse return;
7853 const c_value = (f.value_map.fetchRemove(ref_inst) orelse return).value;
7833 if (f.air.instructions.items(.tag)[ref_inst] == .constant) return;7854 if (f.air.instructions.items(.tag)[ref_inst] == .constant) return;
7834 const c_value = (f.value_map.fetchRemove(ref) orelse return).value;
7835 const local_index = switch (c_value) {7855 const local_index = switch (c_value) {
7836 .local, .new_local => |l| l,7856 .local, .new_local => |l| l,
7837 else => return,7857 else => return,