| author | |
| committer | |
| log | 556f0ce5bfb962764bb68d9d9c16765cf9e1b9ba |
| tree | e3ddbc2240c99a089906a10c4c40dcc83a883f17 |
| parent | 04f379dd414184a42412f4497b0573d7612d6730 |
`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 | } |
| 502 | 502 | ||
| 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 | } |
| 692 | 696 | ||
| 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 | }; |
| 1322 | 1333 | ||
| 1334 | /// Some extern function struct memory is owned by the Decl's TypedValue.Managed | ||
| 1335 | /// arena allocator. | ||
| 1336 | pub 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 by | 1352 | /// 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. |
| 1326 | pub const Fn = struct { | 1354 | pub 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 | } |
| 5615 | 5615 | ||
| 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 | } |
| 5622 | 5636 | ||
| 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)); | ||
| 1579 | 1586 | ||
| 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, |
| 264 | 264 | ||
| 265 | .extern_fn, | 265 | .extern_fn => Payload.ExternFn, |
| 266 | .decl_ref, | 266 | |
| 267 | => Payload.Decl, | 267 | .decl_ref => Payload.Decl, |
| 268 | 268 | ||
| 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(), | ||
| 1878 | 1880 | ||
| 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 | }; |
| 3150 | 3152 | ||
| 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, |