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 {...@@ -501,6 +501,10 @@ pub const Decl = struct {
501 }501 }
502502
503 pub fn clearValues(decl: *Decl, gpa: Allocator) void {503 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 }
504 if (decl.getFunction()) |func| {508 if (decl.getFunction()) |func| {
505 func.deinit(gpa);509 func.deinit(gpa);
506 gpa.destroy(func);510 gpa.destroy(func);
...@@ -690,6 +694,13 @@ pub const Decl = struct {...@@ -690,6 +694,13 @@ pub const Decl = struct {
690 return func;694 return func;
691 }695 }
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
693 pub fn getVariable(decl: *Decl) ?*Var {704 pub fn getVariable(decl: *Decl) ?*Var {
694 if (!decl.owns_tv) return null;705 if (!decl.owns_tv) return null;
695 const variable = (decl.val.castTag(.variable) orelse return null).data;706 const variable = (decl.val.castTag(.variable) orelse return null).data;
...@@ -1320,9 +1331,26 @@ pub const Opaque = struct {...@@ -1320,9 +1331,26 @@ pub const Opaque = struct {
1320 }1331 }
1321};1332};
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
1323/// Some Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.1351/// 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 by1352/// Extern functions do not have this data structure; they are represented by `ExternFn`
1325/// the `Decl` only, with a `Value` tag of `extern_fn`.1353/// instead.
1326pub const Fn = struct {1354pub const Fn = struct {
1327 /// The Decl that corresponds to the function itself.1355 /// The Decl that corresponds to the function itself.
1328 owner_decl: *Decl,1356 owner_decl: *Decl,
...@@ -3768,8 +3796,8 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -3768,8 +3796,8 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
3768 }3796 }
3769 },3797 },
3770 .extern_fn => {3798 .extern_fn => {
3771 const owner_decl = decl_tv.val.castTag(.extern_fn).?.data;3799 const extern_fn = decl_tv.val.castTag(.extern_fn).?.data;
3772 if (decl == owner_decl) {3800 if (extern_fn.owner_decl == decl) {
3773 decl.owns_tv = true;3801 decl.owns_tv = true;
3774 queue_linker_work = true;3802 queue_linker_work = true;
3775 is_extern = true;3803 is_extern = true;
src/Sema.zig+18-4
...@@ -5614,10 +5614,24 @@ fn funcCommon(...@@ -5614,10 +5614,24 @@ fn funcCommon(
5614 }5614 }
56155615
5616 if (is_extern) {5616 if (is_extern) {
5617 return sema.addConstant(5617 const new_extern_fn = try sema.gpa.create(Module.ExternFn);
5618 fn_ty,5618 errdefer sema.gpa.destroy(new_extern_fn);
5619 try Value.Tag.extern_fn.create(sema.arena, sema.owner_decl),5619
5620 );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));
5621 }5635 }
56225636
5623 if (!has_body) {5637 if (!has_body) {
src/arch/aarch64/CodeGen.zig+9-2
...@@ -1574,8 +1574,15 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {...@@ -1574,8 +1574,15 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
1574 .data = .{ .reg = .x30 },1574 .data = .{ .reg = .x30 },
1575 });1575 });
1576 } else if (func_value.castTag(.extern_fn)) |func_payload| {1576 } else if (func_value.castTag(.extern_fn)) |func_payload| {
1577 const decl = func_payload.data;1577 const extern_fn = func_payload.data;
1578 const n_strx = try macho_file.addExternFn(mem.sliceTo(decl.name, 0));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
1580 _ = try self.addInst(.{1587 _ = try self.addInst(.{
1581 .tag = .call_extern,1588 .tag = .call_extern,
src/arch/wasm/CodeGen.zig+3-3
...@@ -952,7 +952,7 @@ pub const DeclGen = struct {...@@ -952,7 +952,7 @@ pub const DeclGen = struct {
952 _ = func_payload;952 _ = func_payload;
953 return self.fail("TODO wasm backend genDecl function pointer", .{});953 return self.fail("TODO wasm backend genDecl function pointer", .{});
954 } else if (decl.val.castTag(.extern_fn)) |extern_fn| {954 } 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;
956 var func_type = try genFunctype(self.gpa, ext_decl.ty, self.target());956 var func_type = try genFunctype(self.gpa, ext_decl.ty, self.target());
957 func_type.deinit(self.gpa);957 func_type.deinit(self.gpa);
958 ext_decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type);958 ext_decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type);
...@@ -978,7 +978,7 @@ pub const DeclGen = struct {...@@ -978,7 +978,7 @@ pub const DeclGen = struct {
978 switch (ty.zigTypeTag()) {978 switch (ty.zigTypeTag()) {
979 .Fn => {979 .Fn => {
980 const fn_decl = switch (val.tag()) {980 const fn_decl = switch (val.tag()) {
981 .extern_fn => val.castTag(.extern_fn).?.data,981 .extern_fn => val.castTag(.extern_fn).?.data.owner_decl,
982 .function => val.castTag(.function).?.data.owner_decl,982 .function => val.castTag(.function).?.data.owner_decl,
983 else => unreachable,983 else => unreachable,
984 };984 };
...@@ -1776,7 +1776,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1776,7 +1776,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1776 if (func_val.castTag(.function)) |func| {1776 if (func_val.castTag(.function)) |func| {
1777 break :blk func.data.owner_decl;1777 break :blk func.data.owner_decl;
1778 } else if (func_val.castTag(.extern_fn)) |ext_fn| {1778 } else if (func_val.castTag(.extern_fn)) |ext_fn| {
1779 break :blk ext_fn.data;1779 break :blk ext_fn.data.owner_decl;
1780 } else if (func_val.castTag(.decl_ref)) |decl_ref| {1780 } else if (func_val.castTag(.decl_ref)) |decl_ref| {
1781 break :blk decl_ref.data;1781 break :blk decl_ref.data;
1782 }1782 }
src/arch/x86_64/CodeGen.zig+9-2
...@@ -2516,8 +2516,15 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {...@@ -2516,8 +2516,15 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
2516 .data = undefined,2516 .data = undefined,
2517 });2517 });
2518 } else if (func_value.castTag(.extern_fn)) |func_payload| {2518 } else if (func_value.castTag(.extern_fn)) |func_payload| {
2519 const decl = func_payload.data;2519 const extern_fn = func_payload.data;
2520 const n_strx = try macho_file.addExternFn(mem.sliceTo(decl.name, 0));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));
2521 _ = try self.addInst(.{2528 _ = try self.addInst(.{
2522 .tag = .call_extern,2529 .tag = .call_extern,
2523 .ops = undefined,2530 .ops = undefined,
src/codegen/c.zig+4-4
...@@ -542,8 +542,8 @@ pub const DeclGen = struct {...@@ -542,8 +542,8 @@ pub const DeclGen = struct {
542 try dg.renderDeclName(func.owner_decl, writer);542 try dg.renderDeclName(func.owner_decl, writer);
543 },543 },
544 .extern_fn => {544 .extern_fn => {
545 const decl = val.castTag(.extern_fn).?.data;545 const extern_fn = val.castTag(.extern_fn).?.data;
546 try dg.renderDeclName(decl, writer);546 try dg.renderDeclName(extern_fn.owner_decl, writer);
547 },547 },
548 .int_u64, .one => {548 .int_u64, .one => {
549 try writer.writeAll("((");549 try writer.writeAll("((");
...@@ -681,7 +681,7 @@ pub const DeclGen = struct {...@@ -681,7 +681,7 @@ pub const DeclGen = struct {
681 return dg.renderDeclValue(writer, ty, val, decl);681 return dg.renderDeclValue(writer, ty, val, decl);
682 },682 },
683 .extern_fn => {683 .extern_fn => {
684 const decl = val.castTag(.extern_fn).?.data;684 const decl = val.castTag(.extern_fn).?.data.owner_decl;
685 return dg.renderDeclValue(writer, ty, val, decl);685 return dg.renderDeclValue(writer, ty, val, decl);
686 },686 },
687 else => unreachable,687 else => unreachable,
...@@ -2442,7 +2442,7 @@ fn airCall(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2442,7 +2442,7 @@ fn airCall(f: *Function, inst: Air.Inst.Index) !CValue {
2442 const fn_decl = fn_decl: {2442 const fn_decl = fn_decl: {
2443 const callee_val = f.air.value(pl_op.operand) orelse break :known;2443 const callee_val = f.air.value(pl_op.operand) orelse break :known;
2444 break :fn_decl switch (callee_val.tag()) {2444 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,
2446 .function => callee_val.castTag(.function).?.data.owner_decl,2446 .function => callee_val.castTag(.function).?.data.owner_decl,
2447 .decl_ref => callee_val.castTag(.decl_ref).?.data,2447 .decl_ref => callee_val.castTag(.decl_ref).?.data,
2448 else => break :known,2448 else => break :known,
src/codegen/llvm.zig+2-2
...@@ -622,7 +622,7 @@ pub const DeclGen = struct {...@@ -622,7 +622,7 @@ pub const DeclGen = struct {
622 _ = func_payload;622 _ = func_payload;
623 @panic("TODO llvm backend genDecl function pointer");623 @panic("TODO llvm backend genDecl function pointer");
624 } else if (decl.val.castTag(.extern_fn)) |extern_fn| {624 } 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);
626 } else {626 } else {
627 const target = dg.module.getTarget();627 const target = dg.module.getTarget();
628 const global = try dg.resolveGlobalDecl(decl);628 const global = try dg.resolveGlobalDecl(decl);
...@@ -1410,7 +1410,7 @@ pub const DeclGen = struct {...@@ -1410,7 +1410,7 @@ pub const DeclGen = struct {
1410 },1410 },
1411 .Fn => {1411 .Fn => {
1412 const fn_decl = switch (tv.val.tag()) {1412 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,
1414 .function => tv.val.castTag(.function).?.data.owner_decl,1414 .function => tv.val.castTag(.function).?.data.owner_decl,
1415 else => unreachable,1415 else => unreachable,
1416 };1416 };
src/value.zig+13-6
...@@ -262,9 +262,9 @@ pub const Value = extern union {...@@ -262,9 +262,9 @@ pub const Value = extern union {
262 .int_big_negative,262 .int_big_negative,
263 => Payload.BigInt,263 => Payload.BigInt,
264264
265 .extern_fn,265 .extern_fn => Payload.ExternFn,
266 .decl_ref,266
267 => Payload.Decl,267 .decl_ref => Payload.Decl,
268268
269 .repeated,269 .repeated,
270 .eu_payload,270 .eu_payload,
...@@ -475,7 +475,7 @@ pub const Value = extern union {...@@ -475,7 +475,7 @@ pub const Value = extern union {
475 return Value{ .ptr_otherwise = &new_payload.base };475 return Value{ .ptr_otherwise = &new_payload.base };
476 },476 },
477 .function => return self.copyPayloadShallow(arena, Payload.Function),477 .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),
479 .variable => return self.copyPayloadShallow(arena, Payload.Variable),479 .variable => return self.copyPayloadShallow(arena, Payload.Variable),
480 .decl_ref => return self.copyPayloadShallow(arena, Payload.Decl),480 .decl_ref => return self.copyPayloadShallow(arena, Payload.Decl),
481 .decl_ref_mut => return self.copyPayloadShallow(arena, Payload.DeclRefMut),481 .decl_ref_mut => return self.copyPayloadShallow(arena, Payload.DeclRefMut),
...@@ -1803,9 +1803,10 @@ pub const Value = extern union {...@@ -1803,9 +1803,10 @@ pub const Value = extern union {
1803 pub fn pointerDecl(val: Value) ?*Module.Decl {1803 pub fn pointerDecl(val: Value) ?*Module.Decl {
1804 return switch (val.tag()) {1804 return switch (val.tag()) {
1805 .decl_ref_mut => val.castTag(.decl_ref_mut).?.data.decl,1805 .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,
1807 .function => val.castTag(.function).?.data.owner_decl,1807 .function => val.castTag(.function).?.data.owner_decl,
1808 .variable => val.castTag(.variable).?.data.owner_decl,1808 .variable => val.castTag(.variable).?.data.owner_decl,
1809 .decl_ref => val.cast(Payload.Decl).?.data,
1809 else => null,1810 else => null,
1810 };1811 };
1811 }1812 }
...@@ -1872,9 +1873,10 @@ pub const Value = extern union {...@@ -1872,9 +1873,10 @@ pub const Value = extern union {
1872 pub fn markReferencedDeclsAlive(val: Value) void {1873 pub fn markReferencedDeclsAlive(val: Value) void {
1873 switch (val.tag()) {1874 switch (val.tag()) {
1874 .decl_ref_mut => return val.castTag(.decl_ref_mut).?.data.decl.markAlive(),1875 .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(),
1876 .function => return val.castTag(.function).?.data.owner_decl.markAlive(),1877 .function => return val.castTag(.function).?.data.owner_decl.markAlive(),
1877 .variable => return val.castTag(.variable).?.data.owner_decl.markAlive(),1878 .variable => return val.castTag(.variable).?.data.owner_decl.markAlive(),
1879 .decl_ref => return val.cast(Payload.Decl).?.data.markAlive(),
18781880
1879 .repeated,1881 .repeated,
1880 .eu_payload,1882 .eu_payload,
...@@ -3148,6 +3150,11 @@ pub const Value = extern union {...@@ -3148,6 +3150,11 @@ pub const Value = extern union {
3148 data: *Module.Fn,3150 data: *Module.Fn,
3149 };3151 };
31503152
3153 pub const ExternFn = struct {
3154 base: Payload,
3155 data: *Module.ExternFn,
3156 };
3157
3151 pub const Decl = struct {3158 pub const Decl = struct {
3152 base: Payload,3159 base: Payload,
3153 data: *Module.Decl,3160 data: *Module.Decl,