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 {
5555 result: CValue,
5656};
5757
58pub const CValueMap = std.AutoHashMap(Air.Inst.Ref, CValue);
58pub const CValueMap = std.AutoHashMap(Air.Inst.Index, CValue);
5959
6060pub const LazyFnKey = union(enum) {
6161 tag_name: Decl.Index,
......@@ -289,29 +289,31 @@ pub const Function = struct {
289289 /// Needed for memory used by the keys of free_locals_map entries.
290290 arena: std.heap.ArenaAllocator,
291291
292 fn resolveInst(f: *Function, inst: Air.Inst.Ref) !CValue {
293 const gop = try f.value_map.getOrPut(inst);
294 if (gop.found_existing) return gop.value_ptr.*;
295
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 };
292 fn resolveInst(f: *Function, ref: Air.Inst.Ref) !CValue {
293 if (Air.refToIndex(ref)) |inst| {
294 const gop = try f.value_map.getOrPut(inst);
295 if (gop.found_existing) return gop.value_ptr.*;
312296
313 gop.value_ptr.* = result;
314 return result;
297 const val = f.air.value(ref).?;
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 };
315317 }
316318
317319 fn wantSafety(f: *Function) bool {
......@@ -2594,6 +2596,7 @@ pub fn genFunc(f: *Function) !void {
25942596 // missing. These are added now to complete the map. Then we can sort by
25952597 // alignment, descending.
25962598 const free_locals = &f.free_locals_map;
2599 assert(f.value_map.count() == 0); // there must not be any unfreed locals
25972600 for (f.allocs.keys(), f.allocs.values()) |local_index, value| {
25982601 if (value) continue; // static
25992602 const local = f.locals.items[local_index];
......@@ -2995,7 +2998,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
29952998 if (result_value == .new_local) {
29962999 log.debug("map %{d} to t{d}", .{ inst, result_value.new_local });
29973000 }
2998 try f.value_map.putNoClobber(Air.indexToRef(inst), switch (result_value) {
3001 try f.value_map.putNoClobber(inst, switch (result_value) {
29993002 .none => continue,
30003003 .new_local => |i| .{ .local = i },
30013004 else => result_value,
......@@ -3081,17 +3084,21 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
30813084 const child_ty = ptr_ty.childType();
30823085
30833086 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 }
30883087 const index = try f.resolveInst(bin_op.rhs);
30893088 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
30903089
30913090 const writer = f.object.writer();
30923091 const local = try f.allocLocal(inst, f.air.typeOfIndex(inst));
30933092 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('(');
30953102 try f.renderType(writer, inst_ty);
30963103 try writer.writeAll(")&(");
30973104 if (ptr_ty.ptrSize() == .One) {
......@@ -3217,12 +3224,11 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
32173224}
32183225
32193226fn 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);
32223230 const elem_type = inst_ty.elemType();
3223 if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) {
3224 return .{ .undef = inst_ty };
3225 }
3231 if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) return .{ .undef = inst_ty };
32263232
32273233 const target = f.object.dg.module.getTarget();
32283234 const local = try f.allocAlignedLocal(
......@@ -3237,12 +3243,11 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
32373243}
32383244
32393245fn 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);
32423249 const elem_ty = inst_ty.elemType();
3243 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {
3244 return .{ .undef = inst_ty };
3245 }
3250 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return .{ .undef = inst_ty };
32463251
32473252 const target = f.object.dg.module.getTarget();
32483253 const local = try f.allocAlignedLocal(
......@@ -3262,10 +3267,22 @@ fn airArg(f: *Function, inst: Air.Inst.Index) !CValue {
32623267
32633268 const i = f.next_arg_index;
32643269 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))
32663271 .{ .arg_array = i }
32673272 else
32683273 .{ .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;
32693286}
32703287
32713288fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -4179,21 +4196,23 @@ fn airCall(
41794196 var lowered_ret_buf: LowerFnRetTyBuffer = undefined;
41804197 const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target);
41814198
4182 const result_local = if (modifier == .always_tail) r: {
4183 try writer.writeAll("zig_always_tail return ");
4184 break :r .none;
4185 } else if (!lowered_ret_ty.hasRuntimeBitsIgnoreComptime())
4186 .none
4187 else if (f.liveness.isUnused(inst)) r: {
4188 try writer.writeByte('(');
4189 try f.renderType(writer, Type.void);
4190 try writer.writeByte(')');
4191 break :r .none;
4192 } else r: {
4193 const local = try f.allocLocal(inst, try lowered_ret_ty.copy(f.arena.allocator()));
4194 try f.writeCValue(writer, local, .Other);
4195 try writer.writeAll(" = ");
4196 break :r local;
4199 const result_local = result: {
4200 if (modifier == .always_tail) {
4201 try writer.writeAll("zig_always_tail return ");
4202 break :result .none;
4203 } else if (!lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) {
4204 break :result .none;
4205 } else if (f.liveness.isUnused(inst)) {
4206 try writer.writeByte('(');
4207 try f.renderType(writer, Type.void);
4208 try writer.writeByte(')');
4209 break :result .none;
4210 } else {
4211 const local = try f.allocLocal(inst, try lowered_ret_ty.copy(f.arena.allocator()));
4212 try f.writeCValue(writer, local, .Other);
4213 try writer.writeAll(" = ");
4214 break :result local;
4215 }
41974216 };
41984217
41994218 callee: {
......@@ -4238,9 +4257,9 @@ fn airCall(
42384257 }
42394258 try writer.writeAll(");\n");
42404259
4241 const result = r: {
4260 const result = result: {
42424261 if (result_local == .none or !lowersToArray(ret_ty, target))
4243 break :r result_local;
4262 break :result result_local;
42444263
42454264 const array_local = try f.allocLocal(inst, ret_ty);
42464265 try writer.writeAll("memcpy(");
......@@ -4251,7 +4270,7 @@ fn airCall(
42514270 try f.renderType(writer, ret_ty);
42524271 try writer.writeAll("));\n");
42534272 try freeLocal(f, inst, result_local.new_local, 0);
4254 break :r array_local;
4273 break :result array_local;
42554274 };
42564275
42574276 return result;
......@@ -4468,7 +4487,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
44684487 {
44694488 try f.writeCValue(writer, local, .Other);
44704489 try writer.writeAll(" = ");
4471 try f.writeCValue(writer, operand, .Other);
4490 try f.writeCValue(writer, operand, .Initializer);
44724491 try writer.writeAll(";\n");
44734492 return local;
44744493 }
......@@ -4835,8 +4854,8 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
48354854 const inputs = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra_i..][0..extra.data.inputs_len]);
48364855 extra_i += inputs.len;
48374856
4838 const result = r: {
4839 if (!is_volatile and f.liveness.isUnused(inst)) break :r .none;
4857 const result = result: {
4858 if (!is_volatile and f.liveness.isUnused(inst)) break :result .none;
48404859
48414860 const writer = f.object.writer();
48424861 const inst_ty = f.air.typeOfIndex(inst);
......@@ -5064,7 +5083,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
50645083 }
50655084 }
50665085
5067 break :r local;
5086 break :result if (f.liveness.isUnused(inst)) .none else local;
50685087 };
50695088
50705089 var bt = iterateBigTomb(f, inst);
......@@ -7036,21 +7055,22 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
70367055
70377056fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {
70387057 const prefetch = f.air.instructions.items(.data)[inst].prefetch;
7039 switch (prefetch.cache) {
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 }
7058
70467059 const ptr = try f.resolveInst(prefetch.ptr);
70477060 try reap(f, inst, &.{prefetch.ptr});
7061
70487062 const writer = f.object.writer();
7049 try writer.writeAll("zig_prefetch(");
7050 try f.writeCValue(writer, ptr, .FunctionArgument);
7051 try writer.print(", {d}, {d});\n", .{
7052 @enumToInt(prefetch.rw), prefetch.locality,
7053 });
7063 switch (prefetch.cache) {
7064 .data => {
7065 try writer.writeAll("zig_prefetch(");
7066 try f.writeCValue(writer, ptr, .FunctionArgument);
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
70547074 return .none;
70557075}
70567076
......@@ -7830,8 +7850,8 @@ fn reap(f: *Function, inst: Air.Inst.Index, operands: []const Air.Inst.Ref) !voi
78307850
78317851fn die(f: *Function, inst: Air.Inst.Index, ref: Air.Inst.Ref) !void {
78327852 const ref_inst = Air.refToIndex(ref) orelse return;
7853 const c_value = (f.value_map.fetchRemove(ref_inst) orelse return).value;
78337854 if (f.air.instructions.items(.tag)[ref_inst] == .constant) return;
7834 const c_value = (f.value_map.fetchRemove(ref) orelse return).value;
78357855 const local_index = switch (c_value) {
78367856 .local, .new_local => |l| l,
78377857 else => return,