authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-05 17:41:03+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-06 08:42:14+01:00
log556f0ce5bfb962764bb68d9d9c16765cf9e1b9ba
treee3ddbc2240c99a089906a10c4c40dcc83a883f17
parent04f379dd414184a42412f4497b0573d7612d6730

stage2: add new Decl subtype, ExternFn

`ExternFn` will contain a maybe-lib-name if it was defined with the `extern` keyword like so ```zig extern "c" fn write(usize, usize, usize) usize; ``` `lib_name` will live as long as `ExternFn` decl does.

8 files changed, 90 insertions(+), 27 deletions(-)

src/Module.zig+32-4
......@@ -501,6 +501,10 @@ pub const Decl = struct {
501501 }
502502
503503 pub fn clearValues(decl: *Decl, gpa: Allocator) void {
504 if (decl.getExternFn()) |extern_fn| {
505 extern_fn.deinit(gpa);
506 gpa.destroy(extern_fn);
507 }
504508 if (decl.getFunction()) |func| {
505509 func.deinit(gpa);
506510 gpa.destroy(func);
......@@ -690,6 +694,13 @@ pub const Decl = struct {
690694 return func;
691695 }
692696
697 pub fn getExternFn(decl: *const Decl) ?*ExternFn {
698 if (!decl.owns_tv) return null;
699 const extern_fn = (decl.val.castTag(.extern_fn) orelse return null).data;
700 assert(extern_fn.owner_decl == decl);
701 return extern_fn;
702 }
703
693704 pub fn getVariable(decl: *Decl) ?*Var {
694705 if (!decl.owns_tv) return null;
695706 const variable = (decl.val.castTag(.variable) orelse return null).data;
......@@ -1320,9 +1331,26 @@ pub const Opaque = struct {
13201331 }
13211332};
13221333
1334/// Some extern function struct memory is owned by the Decl's TypedValue.Managed
1335/// arena allocator.
1336pub const ExternFn = struct {
1337 /// The Decl that corresponds to the function itself.
1338 owner_decl: *Decl,
1339 /// Library name if specified.
1340 /// For example `extern "c" fn write(...) usize` would have 'c' as library name.
1341 /// Allocated with Module's allocator; outlives the ZIR code.
1342 lib_name: ?[*:0]const u8,
1343
1344 pub fn deinit(extern_fn: *ExternFn, gpa: Allocator) void {
1345 if (extern_fn.lib_name) |lib_name| {
1346 gpa.free(mem.sliceTo(lib_name, 0));
1347 }
1348 }
1349};
1350
13231351/// Some Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.
1324/// Extern functions do not have this data structure; they are represented by
1325/// the `Decl` only, with a `Value` tag of `extern_fn`.
1352/// Extern functions do not have this data structure; they are represented by `ExternFn`
1353/// instead.
13261354pub const Fn = struct {
13271355 /// The Decl that corresponds to the function itself.
13281356 owner_decl: *Decl,
......@@ -3768,8 +3796,8 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
37683796 }
37693797 },
37703798 .extern_fn => {
3771 const owner_decl = decl_tv.val.castTag(.extern_fn).?.data;
3772 if (decl == owner_decl) {
3799 const extern_fn = decl_tv.val.castTag(.extern_fn).?.data;
3800 if (extern_fn.owner_decl == decl) {
37733801 decl.owns_tv = true;
37743802 queue_linker_work = true;
37753803 is_extern = true;
src/Sema.zig+18-4
......@@ -5614,10 +5614,24 @@ fn funcCommon(
56145614 }
56155615
56165616 if (is_extern) {
5617 return sema.addConstant(
5618 fn_ty,
5619 try Value.Tag.extern_fn.create(sema.arena, sema.owner_decl),
5620 );
5617 const new_extern_fn = try sema.gpa.create(Module.ExternFn);
5618 errdefer sema.gpa.destroy(new_extern_fn);
5619
5620 const lib_name: ?[*:0]const u8 = if (opt_lib_name) |lib_name| blk: {
5621 break :blk try sema.gpa.dupeZ(u8, lib_name);
5622 } else null;
5623
5624 new_extern_fn.* = Module.ExternFn{
5625 .owner_decl = sema.owner_decl,
5626 .lib_name = lib_name,
5627 };
5628
5629 const extern_fn_payload = try sema.arena.create(Value.Payload.ExternFn);
5630 extern_fn_payload.* = .{
5631 .base = .{ .tag = .extern_fn },
5632 .data = new_extern_fn,
5633 };
5634 return sema.addConstant(fn_ty, Value.initPayload(&extern_fn_payload.base));
56215635 }
56225636
56235637 if (!has_body) {
src/arch/aarch64/CodeGen.zig+9-2
......@@ -1574,8 +1574,15 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
15741574 .data = .{ .reg = .x30 },
15751575 });
15761576 } else if (func_value.castTag(.extern_fn)) |func_payload| {
1577 const decl = func_payload.data;
1578 const n_strx = try macho_file.addExternFn(mem.sliceTo(decl.name, 0));
1577 const extern_fn = func_payload.data;
1578 const decl_name = extern_fn.owner_decl.name;
1579 if (extern_fn.lib_name) |lib_name| {
1580 log.debug("TODO enforce that '{s}' is expected in '{s}' library", .{
1581 decl_name,
1582 lib_name,
1583 });
1584 }
1585 const n_strx = try macho_file.addExternFn(mem.sliceTo(decl_name, 0));
15791586
15801587 _ = try self.addInst(.{
15811588 .tag = .call_extern,
src/arch/wasm/CodeGen.zig+3-3
......@@ -952,7 +952,7 @@ pub const DeclGen = struct {
952952 _ = func_payload;
953953 return self.fail("TODO wasm backend genDecl function pointer", .{});
954954 } else if (decl.val.castTag(.extern_fn)) |extern_fn| {
955 const ext_decl = extern_fn.data;
955 const ext_decl = extern_fn.data.owner_decl;
956956 var func_type = try genFunctype(self.gpa, ext_decl.ty, self.target());
957957 func_type.deinit(self.gpa);
958958 ext_decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type);
......@@ -978,7 +978,7 @@ pub const DeclGen = struct {
978978 switch (ty.zigTypeTag()) {
979979 .Fn => {
980980 const fn_decl = switch (val.tag()) {
981 .extern_fn => val.castTag(.extern_fn).?.data,
981 .extern_fn => val.castTag(.extern_fn).?.data.owner_decl,
982982 .function => val.castTag(.function).?.data.owner_decl,
983983 else => unreachable,
984984 };
......@@ -1776,7 +1776,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
17761776 if (func_val.castTag(.function)) |func| {
17771777 break :blk func.data.owner_decl;
17781778 } else if (func_val.castTag(.extern_fn)) |ext_fn| {
1779 break :blk ext_fn.data;
1779 break :blk ext_fn.data.owner_decl;
17801780 } else if (func_val.castTag(.decl_ref)) |decl_ref| {
17811781 break :blk decl_ref.data;
17821782 }
src/arch/x86_64/CodeGen.zig+9-2
......@@ -2516,8 +2516,15 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
25162516 .data = undefined,
25172517 });
25182518 } else if (func_value.castTag(.extern_fn)) |func_payload| {
2519 const decl = func_payload.data;
2520 const n_strx = try macho_file.addExternFn(mem.sliceTo(decl.name, 0));
2519 const extern_fn = func_payload.data;
2520 const decl_name = extern_fn.owner_decl.name;
2521 if (extern_fn.lib_name) |lib_name| {
2522 log.debug("TODO enforce that '{s}' is expected in '{s}' library", .{
2523 decl_name,
2524 lib_name,
2525 });
2526 }
2527 const n_strx = try macho_file.addExternFn(mem.sliceTo(decl_name, 0));
25212528 _ = try self.addInst(.{
25222529 .tag = .call_extern,
25232530 .ops = undefined,
src/codegen/c.zig+4-4
......@@ -542,8 +542,8 @@ pub const DeclGen = struct {
542542 try dg.renderDeclName(func.owner_decl, writer);
543543 },
544544 .extern_fn => {
545 const decl = val.castTag(.extern_fn).?.data;
546 try dg.renderDeclName(decl, writer);
545 const extern_fn = val.castTag(.extern_fn).?.data;
546 try dg.renderDeclName(extern_fn.owner_decl, writer);
547547 },
548548 .int_u64, .one => {
549549 try writer.writeAll("((");
......@@ -681,7 +681,7 @@ pub const DeclGen = struct {
681681 return dg.renderDeclValue(writer, ty, val, decl);
682682 },
683683 .extern_fn => {
684 const decl = val.castTag(.extern_fn).?.data;
684 const decl = val.castTag(.extern_fn).?.data.owner_decl;
685685 return dg.renderDeclValue(writer, ty, val, decl);
686686 },
687687 else => unreachable,
......@@ -2442,7 +2442,7 @@ fn airCall(f: *Function, inst: Air.Inst.Index) !CValue {
24422442 const fn_decl = fn_decl: {
24432443 const callee_val = f.air.value(pl_op.operand) orelse break :known;
24442444 break :fn_decl switch (callee_val.tag()) {
2445 .extern_fn => callee_val.castTag(.extern_fn).?.data,
2445 .extern_fn => callee_val.castTag(.extern_fn).?.data.owner_decl,
24462446 .function => callee_val.castTag(.function).?.data.owner_decl,
24472447 .decl_ref => callee_val.castTag(.decl_ref).?.data,
24482448 else => break :known,
src/codegen/llvm.zig+2-2
......@@ -622,7 +622,7 @@ pub const DeclGen = struct {
622622 _ = func_payload;
623623 @panic("TODO llvm backend genDecl function pointer");
624624 } else if (decl.val.castTag(.extern_fn)) |extern_fn| {
625 _ = try dg.resolveLlvmFunction(extern_fn.data);
625 _ = try dg.resolveLlvmFunction(extern_fn.data.owner_decl);
626626 } else {
627627 const target = dg.module.getTarget();
628628 const global = try dg.resolveGlobalDecl(decl);
......@@ -1410,7 +1410,7 @@ pub const DeclGen = struct {
14101410 },
14111411 .Fn => {
14121412 const fn_decl = switch (tv.val.tag()) {
1413 .extern_fn => tv.val.castTag(.extern_fn).?.data,
1413 .extern_fn => tv.val.castTag(.extern_fn).?.data.owner_decl,
14141414 .function => tv.val.castTag(.function).?.data.owner_decl,
14151415 else => unreachable,
14161416 };
src/value.zig+13-6
......@@ -262,9 +262,9 @@ pub const Value = extern union {
262262 .int_big_negative,
263263 => Payload.BigInt,
264264
265 .extern_fn,
266 .decl_ref,
267 => Payload.Decl,
265 .extern_fn => Payload.ExternFn,
266
267 .decl_ref => Payload.Decl,
268268
269269 .repeated,
270270 .eu_payload,
......@@ -475,7 +475,7 @@ pub const Value = extern union {
475475 return Value{ .ptr_otherwise = &new_payload.base };
476476 },
477477 .function => return self.copyPayloadShallow(arena, Payload.Function),
478 .extern_fn => return self.copyPayloadShallow(arena, Payload.Decl),
478 .extern_fn => return self.copyPayloadShallow(arena, Payload.ExternFn),
479479 .variable => return self.copyPayloadShallow(arena, Payload.Variable),
480480 .decl_ref => return self.copyPayloadShallow(arena, Payload.Decl),
481481 .decl_ref_mut => return self.copyPayloadShallow(arena, Payload.DeclRefMut),
......@@ -1803,9 +1803,10 @@ pub const Value = extern union {
18031803 pub fn pointerDecl(val: Value) ?*Module.Decl {
18041804 return switch (val.tag()) {
18051805 .decl_ref_mut => val.castTag(.decl_ref_mut).?.data.decl,
1806 .extern_fn, .decl_ref => val.cast(Payload.Decl).?.data,
1806 .extern_fn => val.castTag(.extern_fn).?.data.owner_decl,
18071807 .function => val.castTag(.function).?.data.owner_decl,
18081808 .variable => val.castTag(.variable).?.data.owner_decl,
1809 .decl_ref => val.cast(Payload.Decl).?.data,
18091810 else => null,
18101811 };
18111812 }
......@@ -1872,9 +1873,10 @@ pub const Value = extern union {
18721873 pub fn markReferencedDeclsAlive(val: Value) void {
18731874 switch (val.tag()) {
18741875 .decl_ref_mut => return val.castTag(.decl_ref_mut).?.data.decl.markAlive(),
1875 .extern_fn, .decl_ref => return val.cast(Payload.Decl).?.data.markAlive(),
1876 .extern_fn => return val.castTag(.extern_fn).?.data.owner_decl.markAlive(),
18761877 .function => return val.castTag(.function).?.data.owner_decl.markAlive(),
18771878 .variable => return val.castTag(.variable).?.data.owner_decl.markAlive(),
1879 .decl_ref => return val.cast(Payload.Decl).?.data.markAlive(),
18781880
18791881 .repeated,
18801882 .eu_payload,
......@@ -3148,6 +3150,11 @@ pub const Value = extern union {
31483150 data: *Module.Fn,
31493151 };
31503152
3153 pub const ExternFn = struct {
3154 base: Payload,
3155 data: *Module.ExternFn,
3156 };
3157
31513158 pub const Decl = struct {
31523159 base: Payload,
31533160 data: *Module.Decl,