stage2: add owns_tv flag to Module.Decl

Decl objects need to know whether they are the owner of the Type/Value
associated with them, in order to decide whether to destroy the
associated Namespace, Fn, or Var when cleaning up.
This commit is contained in:
Andrew Kelley
2021-05-11 14:17:52 -07:00
parent dae22a0a1f
commit bcf15e39e2
6 changed files with 128 additions and 59 deletions

View File

@@ -30,6 +30,7 @@ pub const CValue = union(enum) {
arg: usize,
/// By-value
decl: *Decl,
decl_ref: *Decl,
};
pub const CValueMap = std.AutoHashMap(*Inst, CValue);
@@ -117,6 +118,7 @@ pub const Object = struct {
.constant => |inst| return o.dg.renderValue(w, inst.ty, inst.value().?),
.arg => |i| return w.print("a{d}", .{i}),
.decl => |decl| return w.writeAll(mem.span(decl.name)),
.decl_ref => |decl| return w.print("&{s}", .{decl.name}),
}
}
@@ -528,13 +530,17 @@ pub const DeclGen = struct {
}
}
fn functionIsGlobal(dg: *DeclGen, tv: TypedValue) bool {
fn declIsGlobal(dg: *DeclGen, tv: TypedValue) bool {
switch (tv.val.tag()) {
.extern_fn => return true,
.function => {
const func = tv.val.castTag(.function).?.data;
return dg.module.decl_exports.contains(func.owner_decl);
},
.variable => {
const variable = tv.val.castTag(.variable).?.data;
return dg.module.decl_exports.contains(variable.owner_decl);
},
else => unreachable,
}
}
@@ -549,7 +555,7 @@ pub fn genDecl(o: *Object) !void {
.val = o.dg.decl.val,
};
if (tv.val.castTag(.function)) |func_payload| {
const is_global = o.dg.functionIsGlobal(tv);
const is_global = o.dg.declIsGlobal(tv);
const fwd_decl_writer = o.dg.fwd_decl.writer();
if (is_global) {
try fwd_decl_writer.writeAll("ZIG_EXTERN_C ");
@@ -570,6 +576,30 @@ pub fn genDecl(o: *Object) !void {
try writer.writeAll("ZIG_EXTERN_C ");
try o.dg.renderFunctionSignature(writer, true);
try writer.writeAll(";\n");
} else if (tv.val.castTag(.variable)) |var_payload| {
const variable: *Module.Var = var_payload.data;
const is_global = o.dg.declIsGlobal(tv);
const fwd_decl_writer = o.dg.fwd_decl.writer();
if (is_global or variable.is_extern) {
try fwd_decl_writer.writeAll("ZIG_EXTERN_C ");
}
if (variable.is_threadlocal) {
try fwd_decl_writer.writeAll("zig_threadlocal ");
}
try o.dg.renderType(fwd_decl_writer, o.dg.decl.ty);
const decl_name = mem.span(o.dg.decl.name);
try fwd_decl_writer.print(" {s};\n", .{decl_name});
try o.indent_writer.insertNewline();
const w = o.writer();
try o.dg.renderType(w, o.dg.decl.ty);
try w.print(" {s} = ", .{decl_name});
if (variable.init.tag() != .unreachable_value) {
try o.dg.renderValue(w, tv.ty, variable.init);
}
try w.writeAll(";");
try o.indent_writer.insertNewline();
} else {
const writer = o.writer();
try writer.writeAll("static ");
@@ -598,7 +628,7 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
switch (tv.ty.zigTypeTag()) {
.Fn => {
const is_global = dg.functionIsGlobal(tv);
const is_global = dg.declIsGlobal(tv);
if (is_global) {
try writer.writeAll("ZIG_EXTERN_C ");
}
@@ -696,7 +726,7 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi
.wrap_errunion_err => try genWrapErrUnionErr(o, inst.castTag(.wrap_errunion_err).?),
.br_block_flat => return o.dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement codegen for br_block_flat", .{}),
.ptrtoint => return o.dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement codegen for ptrtoint", .{}),
.varptr => return o.dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement codegen for varptr", .{}),
.varptr => try genVarPtr(o, inst.castTag(.varptr).?),
.floatcast => return o.dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement codegen for floatcast", .{}),
};
switch (result_value) {
@@ -709,6 +739,10 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi
try writer.writeAll("}");
}
fn genVarPtr(o: *Object, inst: *Inst.VarPtr) !CValue {
return CValue{ .decl_ref = inst.variable.owner_decl };
}
fn genAlloc(o: *Object, alloc: *Inst.NoOp) !CValue {
const writer = o.writer();
@@ -743,6 +777,12 @@ fn genLoad(o: *Object, inst: *Inst.UnOp) !CValue {
try o.writeCValue(writer, wrapped);
try writer.writeAll(";\n");
},
.decl_ref => |decl| {
const wrapped: CValue = .{ .decl = decl };
try writer.writeAll(" = ");
try o.writeCValue(writer, wrapped);
try writer.writeAll(";\n");
},
else => {
try writer.writeAll(" = *");
try o.writeCValue(writer, operand);
@@ -791,6 +831,13 @@ fn genStore(o: *Object, inst: *Inst.BinOp) !CValue {
try o.writeCValue(writer, src_val);
try writer.writeAll(";\n");
},
.decl_ref => |decl| {
const dest: CValue = .{ .decl = decl };
try o.writeCValue(writer, dest);
try writer.writeAll(" = ");
try o.writeCValue(writer, src_val);
try writer.writeAll(";\n");
},
else => {
try writer.writeAll("*");
try o.writeCValue(writer, dest_ptr);