aboutsummaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-05-11 14:17:52 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-05-11 14:17:52 -0700
commitbcf15e39e2d4e2243f475852aca7749e40a70fbd (patch)
tree367c697ea25a0649a263d13131ffaf0ec3f82ad4 /src/codegen
parentdae22a0a1f13cc963e96cd704941eed29b8dde27 (diff)
downloadzig-bcf15e39e2d4e2243f475852aca7749e40a70fbd.tar.gz
zig-bcf15e39e2d4e2243f475852aca7749e40a70fbd.zip
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.
Diffstat (limited to 'src/codegen')
-rw-r--r--src/codegen/c.zig55
1 files changed, 51 insertions, 4 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index 43b851019b..6f80ac6154 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -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);