| author | |
| committer | |
| log | 5487dd13ea23ad7e547995b9a088ba37bfe17737 |
| tree | d1bc46aed5d4db149d32cb4fca0406f86f1f1790 |
| parent | a021c7b1b2428ecda85e79e281d43fa1c92f8c94 |
This commit lays the groundwork in preparation for implementing
handling of extern functions in various backends.6 files changed, 74 insertions(+), 6 deletions(-)
src/Module.zig+43-2| ... | @@ -22,6 +22,7 @@ const ast = std.zig.ast; | ... | @@ -22,6 +22,7 @@ const ast = std.zig.ast; |
| 22 | const trace = @import("tracy.zig").trace; | 22 | const trace = @import("tracy.zig").trace; |
| 23 | const astgen = @import("astgen.zig"); | 23 | const astgen = @import("astgen.zig"); |
| 24 | const zir_sema = @import("zir_sema.zig"); | 24 | const zir_sema = @import("zir_sema.zig"); |
| 25 | const target_util = @import("target.zig"); | ||
| 25 | 26 | ||
| 26 | const default_eval_branch_quota = 1000; | 27 | const default_eval_branch_quota = 1000; |
| 27 | 28 | ||
| ... | @@ -1109,8 +1110,48 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { | ... | @@ -1109,8 +1110,48 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { |
| 1109 | if (fn_proto.getVarArgsToken()) |var_args_token| { | 1110 | if (fn_proto.getVarArgsToken()) |var_args_token| { |
| 1110 | return self.failTok(&fn_type_scope.base, var_args_token, "TODO implement var args", .{}); | 1111 | return self.failTok(&fn_type_scope.base, var_args_token, "TODO implement var args", .{}); |
| 1111 | } | 1112 | } |
| 1112 | if (fn_proto.getLibName()) |lib_name| { | 1113 | if (fn_proto.getLibName()) |lib_name| blk: { |
| 1113 | return self.failNode(&fn_type_scope.base, lib_name, "TODO implement function library name", .{}); | 1114 | const lib_name_str = mem.trim(u8, tree.tokenSlice(lib_name.firstToken()), "\""); // TODO: call identifierTokenString |
| 1115 | log.debug("extern fn symbol expected in lib '{s}'", .{lib_name_str}); | ||
| 1116 | const target = self.comp.getTarget(); | ||
| 1117 | if (target_util.is_libc_lib_name(target, lib_name_str)) { | ||
| 1118 | if (!self.comp.bin_file.options.link_libc) { | ||
| 1119 | return self.failNode( | ||
| 1120 | &fn_type_scope.base, | ||
| 1121 | lib_name, | ||
| 1122 | "dependency on libc must be explicitly specified in the build command", | ||
| 1123 | .{}, | ||
| 1124 | ); | ||
| 1125 | } | ||
| 1126 | break :blk; | ||
| 1127 | } | ||
| 1128 | if (target_util.is_libcpp_lib_name(target, lib_name_str)) { | ||
| 1129 | if (!self.comp.bin_file.options.link_libcpp) { | ||
| 1130 | return self.failNode( | ||
| 1131 | &fn_type_scope.base, | ||
| 1132 | lib_name, | ||
| 1133 | "dependency on libc++ must be explicitly specified in the build command", | ||
| 1134 | .{}, | ||
| 1135 | ); | ||
| 1136 | } | ||
| 1137 | break :blk; | ||
| 1138 | } | ||
| 1139 | if (!target.isWasm() and !self.comp.bin_file.options.pic) { | ||
| 1140 | return self.failNode( | ||
| 1141 | &fn_type_scope.base, | ||
| 1142 | lib_name, | ||
| 1143 | "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.", | ||
| 1144 | .{ lib_name, lib_name }, | ||
| 1145 | ); | ||
| 1146 | } | ||
| 1147 | self.comp.stage1AddLinkLib(lib_name_str) catch |err| { | ||
| 1148 | return self.failNode( | ||
| 1149 | &fn_type_scope.base, | ||
| 1150 | lib_name, | ||
| 1151 | "unable to add link lib '{s}': {s}", | ||
| 1152 | .{ lib_name, @errorName(err) }, | ||
| 1153 | ); | ||
| 1154 | }; | ||
| 1114 | } | 1155 | } |
| 1115 | if (fn_proto.getAlignExpr()) |align_expr| { | 1156 | if (fn_proto.getAlignExpr()) |align_expr| { |
| 1116 | return self.failNode(&fn_type_scope.base, align_expr, "TODO implement function align expression", .{}); | 1157 | return self.failNode(&fn_type_scope.base, align_expr, "TODO implement function align expression", .{}); |
src/codegen.zig+12| ... | @@ -1602,6 +1602,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1602,6 +1602,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1602 | try self.code.ensureCapacity(self.code.items.len + 7); | 1602 | try self.code.ensureCapacity(self.code.items.len + 7); |
| 1603 | self.code.appendSliceAssumeCapacity(&[3]u8{ 0xff, 0x14, 0x25 }); | 1603 | self.code.appendSliceAssumeCapacity(&[3]u8{ 0xff, 0x14, 0x25 }); |
| 1604 | mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), got_addr); | 1604 | mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), got_addr); |
| 1605 | } else if (func_value.castTag(.extern_fn)) |_| { | ||
| 1606 | return self.fail(inst.base.src, "TODO implement calling extern functions", .{}); | ||
| 1605 | } else { | 1607 | } else { |
| 1606 | return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); | 1608 | return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); |
| 1607 | } | 1609 | } |
| ... | @@ -1628,6 +1630,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1628,6 +1630,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1628 | 1630 | ||
| 1629 | try self.genSetReg(inst.base.src, .ra, .{ .memory = got_addr }); | 1631 | try self.genSetReg(inst.base.src, .ra, .{ .memory = got_addr }); |
| 1630 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.jalr(.ra, 0, .ra).toU32()); | 1632 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.jalr(.ra, 0, .ra).toU32()); |
| 1633 | } else if (func_value.castTag(.extern_fn)) |_| { | ||
| 1634 | return self.fail(inst.base.src, "TODO implement calling extern functions", .{}); | ||
| 1631 | } else { | 1635 | } else { |
| 1632 | return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); | 1636 | return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); |
| 1633 | } | 1637 | } |
| ... | @@ -1672,6 +1676,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1672,6 +1676,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1672 | else => return self.fail(inst.base.src, "TODO implement fn call with non-void return value", .{}), | 1676 | else => return self.fail(inst.base.src, "TODO implement fn call with non-void return value", .{}), |
| 1673 | } | 1677 | } |
| 1674 | } | 1678 | } |
| 1679 | } else if (func_value.castTag(.extern_fn)) |_| { | ||
| 1680 | return self.fail(inst.base.src, "TODO implement calling extern functions", .{}); | ||
| 1675 | } else { | 1681 | } else { |
| 1676 | return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); | 1682 | return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); |
| 1677 | } | 1683 | } |
| ... | @@ -1733,6 +1739,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1733,6 +1739,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1733 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, .lr, Instruction.Operand.reg(.pc, Instruction.Operand.Shift.none)).toU32()); | 1739 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, .lr, Instruction.Operand.reg(.pc, Instruction.Operand.Shift.none)).toU32()); |
| 1734 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.bx(.al, .lr).toU32()); | 1740 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.bx(.al, .lr).toU32()); |
| 1735 | } | 1741 | } |
| 1742 | } else if (func_value.castTag(.extern_fn)) |_| { | ||
| 1743 | return self.fail(inst.base.src, "TODO implement calling extern functions", .{}); | ||
| 1736 | } else { | 1744 | } else { |
| 1737 | return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); | 1745 | return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); |
| 1738 | } | 1746 | } |
| ... | @@ -1787,6 +1795,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1787,6 +1795,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1787 | try self.genSetReg(inst.base.src, .x30, .{ .memory = got_addr }); | 1795 | try self.genSetReg(inst.base.src, .x30, .{ .memory = got_addr }); |
| 1788 | 1796 | ||
| 1789 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.blr(.x30).toU32()); | 1797 | writeInt(u32, try self.code.addManyAsArray(4), Instruction.blr(.x30).toU32()); |
| 1798 | } else if (func_value.castTag(.extern_fn)) |_| { | ||
| 1799 | return self.fail(inst.base.src, "TODO implement calling extern functions", .{}); | ||
| 1790 | } else { | 1800 | } else { |
| 1791 | return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); | 1801 | return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); |
| 1792 | } | 1802 | } |
| ... | @@ -1849,6 +1859,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1849,6 +1859,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1849 | }, | 1859 | }, |
| 1850 | else => unreachable, // unsupported architecture on MachO | 1860 | else => unreachable, // unsupported architecture on MachO |
| 1851 | } | 1861 | } |
| 1862 | } else if (func_value.castTag(.extern_fn)) |_| { | ||
| 1863 | return self.fail(inst.base.src, "TODO implement calling extern functions", .{}); | ||
| 1852 | } else { | 1864 | } else { |
| 1853 | return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); | 1865 | return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{}); |
| 1854 | } | 1866 | } |
src/link/Coff.zig+5-1| ... | @@ -662,10 +662,14 @@ pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void { | ... | @@ -662,10 +662,14 @@ pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void { |
| 662 | if (build_options.have_llvm) | 662 | if (build_options.have_llvm) |
| 663 | if (self.llvm_ir_module) |llvm_ir_module| return try llvm_ir_module.updateDecl(module, decl); | 663 | if (self.llvm_ir_module) |llvm_ir_module| return try llvm_ir_module.updateDecl(module, decl); |
| 664 | 664 | ||
| 665 | const typed_value = decl.typed_value.most_recent.typed_value; | ||
| 666 | if (typed_value.val.tag() == .extern_fn) { | ||
| 667 | return; // TODO Should we do more when front-end analyzed extern decl? | ||
| 668 | } | ||
| 669 | |||
| 665 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); | 670 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 666 | defer code_buffer.deinit(); | 671 | defer code_buffer.deinit(); |
| 667 | 672 | ||
| 668 | const typed_value = decl.typed_value.most_recent.typed_value; | ||
| 669 | const res = try codegen.generateSymbol(&self.base, decl.src(), typed_value, &code_buffer, .none); | 673 | const res = try codegen.generateSymbol(&self.base, decl.src(), typed_value, &code_buffer, .none); |
| 670 | const code = switch (res) { | 674 | const code = switch (res) { |
| 671 | .externally_managed => |x| x, | 675 | .externally_managed => |x| x, |
src/link/Elf.zig+5-1| ... | @@ -2157,6 +2157,11 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { | ... | @@ -2157,6 +2157,11 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { |
| 2157 | if (build_options.have_llvm) | 2157 | if (build_options.have_llvm) |
| 2158 | if (self.llvm_ir_module) |llvm_ir_module| return try llvm_ir_module.updateDecl(module, decl); | 2158 | if (self.llvm_ir_module) |llvm_ir_module| return try llvm_ir_module.updateDecl(module, decl); |
| 2159 | 2159 | ||
| 2160 | const typed_value = decl.typed_value.most_recent.typed_value; | ||
| 2161 | if (typed_value.val.tag() == .extern_fn) { | ||
| 2162 | return; // TODO Should we do more when front-end analyzed extern decl? | ||
| 2163 | } | ||
| 2164 | |||
| 2160 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); | 2165 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 2161 | defer code_buffer.deinit(); | 2166 | defer code_buffer.deinit(); |
| 2162 | 2167 | ||
| ... | @@ -2175,7 +2180,6 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { | ... | @@ -2175,7 +2180,6 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { |
| 2175 | dbg_info_type_relocs.deinit(self.base.allocator); | 2180 | dbg_info_type_relocs.deinit(self.base.allocator); |
| 2176 | } | 2181 | } |
| 2177 | 2182 | ||
| 2178 | const typed_value = decl.typed_value.most_recent.typed_value; | ||
| 2179 | const is_fn: bool = switch (typed_value.ty.zigTypeTag()) { | 2183 | const is_fn: bool = switch (typed_value.ty.zigTypeTag()) { |
| 2180 | .Fn => true, | 2184 | .Fn => true, |
| 2181 | else => false, | 2185 | else => false, |
src/link/MachO.zig+5-1| ... | @@ -1118,6 +1118,11 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -1118,6 +1118,11 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1118 | const tracy = trace(@src()); | 1118 | const tracy = trace(@src()); |
| 1119 | defer tracy.end(); | 1119 | defer tracy.end(); |
| 1120 | 1120 | ||
| 1121 | const typed_value = decl.typed_value.most_recent.typed_value; | ||
| 1122 | if (typed_value.val.tag() == .extern_fn) { | ||
| 1123 | return; // TODO Should we do more when front-end analyzed extern decl? | ||
| 1124 | } | ||
| 1125 | |||
| 1121 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); | 1126 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 1122 | defer code_buffer.deinit(); | 1127 | defer code_buffer.deinit(); |
| 1123 | 1128 | ||
| ... | @@ -1134,7 +1139,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -1134,7 +1139,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1134 | } | 1139 | } |
| 1135 | } | 1140 | } |
| 1136 | 1141 | ||
| 1137 | const typed_value = decl.typed_value.most_recent.typed_value; | ||
| 1138 | const res = if (debug_buffers) |*dbg| | 1142 | const res = if (debug_buffers) |*dbg| |
| 1139 | try codegen.generateSymbol(&self.base, decl.src(), typed_value, &code_buffer, .{ | 1143 | try codegen.generateSymbol(&self.base, decl.src(), typed_value, &code_buffer, .{ |
| 1140 | .dwarf = .{ | 1144 | .dwarf = .{ |
src/link/Wasm.zig+4-1| ... | @@ -100,8 +100,11 @@ pub fn deinit(self: *Wasm) void { | ... | @@ -100,8 +100,11 @@ pub fn deinit(self: *Wasm) void { |
| 100 | // Generate code for the Decl, storing it in memory to be later written to | 100 | // Generate code for the Decl, storing it in memory to be later written to |
| 101 | // the file on flush(). | 101 | // the file on flush(). |
| 102 | pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void { | 102 | pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void { |
| 103 | if (decl.typed_value.most_recent.typed_value.ty.zigTypeTag() != .Fn) | 103 | const typed_value = decl.typed_value.most_recent.typed_value; |
| 104 | if (typed_value.ty.zigTypeTag() != .Fn) | ||
| 104 | return error.TODOImplementNonFnDeclsForWasm; | 105 | return error.TODOImplementNonFnDeclsForWasm; |
| 106 | if (typed_value.val.tag() == .extern_fn) | ||
| 107 | return error.TODOImplementExternFnDeclsForWasm; | ||
| 105 | 108 | ||
| 106 | if (decl.fn_link.wasm) |*fn_data| { | 109 | if (decl.fn_link.wasm) |*fn_data| { |
| 107 | fn_data.functype.items.len = 0; | 110 | fn_data.functype.items.len = 0; |