| author | |
| committer | |
| log | ed137d25ef0fb94f2ea0db4f993a0adfcaf63b58 |
| tree | 089289335a3e6374c88ccb54c5879806132503a6 |
| parent | 1cde0edff469fbe5ee62cb10a44161b4c9910f98 |
| parent | 8d3cca7fc2e7b34486cc56951bb0dadb75e498a0 |
4 files changed, 77 insertions(+), 10 deletions(-)
src-self-hosted/Module.zig+8-9| ... | @@ -231,6 +231,7 @@ pub const Fn = struct { | ... | @@ -231,6 +231,7 @@ pub const Fn = struct { |
| 231 | dependency_failure, | 231 | dependency_failure, |
| 232 | success: Body, | 232 | success: Body, |
| 233 | }, | 233 | }, |
| 234 | owner_decl: *Decl, | ||
| 234 | 235 | ||
| 235 | /// This memory is temporary and points to stack memory for the duration | 236 | /// This memory is temporary and points to stack memory for the duration |
| 236 | /// of Fn analysis. | 237 | /// of Fn analysis. |
| ... | @@ -883,14 +884,6 @@ fn resolveDecl( | ... | @@ -883,14 +884,6 @@ fn resolveDecl( |
| 883 | }; | 884 | }; |
| 884 | const arena_state = try decl_scope.arena.allocator.create(std.heap.ArenaAllocator.State); | 885 | const arena_state = try decl_scope.arena.allocator.create(std.heap.ArenaAllocator.State); |
| 885 | 886 | ||
| 886 | const has_codegen_bits = typed_value.ty.hasCodeGenBits(); | ||
| 887 | if (has_codegen_bits) { | ||
| 888 | // We don't fully codegen the decl until later, but we do need to reserve a global | ||
| 889 | // offset table index for it. This allows us to codegen decls out of dependency order, | ||
| 890 | // increasing how many computations can be done in parallel. | ||
| 891 | try self.bin_file.allocateDeclIndexes(new_decl); | ||
| 892 | } | ||
| 893 | |||
| 894 | arena_state.* = decl_scope.arena.state; | 887 | arena_state.* = decl_scope.arena.state; |
| 895 | 888 | ||
| 896 | new_decl.typed_value = .{ | 889 | new_decl.typed_value = .{ |
| ... | @@ -900,7 +893,12 @@ fn resolveDecl( | ... | @@ -900,7 +893,12 @@ fn resolveDecl( |
| 900 | }, | 893 | }, |
| 901 | }; | 894 | }; |
| 902 | new_decl.analysis = .complete; | 895 | new_decl.analysis = .complete; |
| 903 | if (has_codegen_bits) { | 896 | if (typed_value.ty.hasCodeGenBits()) { |
| 897 | // We don't fully codegen the decl until later, but we do need to reserve a global | ||
| 898 | // offset table index for it. This allows us to codegen decls out of dependency order, | ||
| 899 | // increasing how many computations can be done in parallel. | ||
| 900 | try self.bin_file.allocateDeclIndexes(new_decl); | ||
| 901 | |||
| 904 | // We ensureCapacity when scanning for decls. | 902 | // We ensureCapacity when scanning for decls. |
| 905 | self.work_queue.writeItemAssumeCapacity(.{ .codegen_decl = new_decl }); | 903 | self.work_queue.writeItemAssumeCapacity(.{ .codegen_decl = new_decl }); |
| 906 | } | 904 | } |
| ... | @@ -1329,6 +1327,7 @@ fn analyzeInstFn(self: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError | ... | @@ -1329,6 +1327,7 @@ fn analyzeInstFn(self: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError |
| 1329 | new_func.* = .{ | 1327 | new_func.* = .{ |
| 1330 | .fn_type = fn_type, | 1328 | .fn_type = fn_type, |
| 1331 | .analysis = .{ .queued = fn_inst }, | 1329 | .analysis = .{ .queued = fn_inst }, |
| 1330 | .owner_decl = scope.decl(), | ||
| 1332 | }; | 1331 | }; |
| 1333 | const fn_payload = try scope.arena().create(Value.Payload.Function); | 1332 | const fn_payload = try scope.arena().create(Value.Payload.Function); |
| 1334 | fn_payload.* = .{ .func = new_func }; | 1333 | fn_payload.* = .{ .func = new_func }; |
src-self-hosted/codegen.zig+14-1| ... | @@ -203,7 +203,20 @@ const Function = struct { | ... | @@ -203,7 +203,20 @@ const Function = struct { |
| 203 | 203 | ||
| 204 | if (func_inst.val.cast(Value.Payload.Function)) |func_val| { | 204 | if (func_inst.val.cast(Value.Payload.Function)) |func_val| { |
| 205 | const func = func_val.func; | 205 | const func = func_val.func; |
| 206 | return self.fail(inst.base.src, "TODO implement calling function", .{}); | 206 | const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?]; |
| 207 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | ||
| 208 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | ||
| 209 | const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.offset_table_index * ptr_bytes); | ||
| 210 | // ff 14 25 xx xx xx xx call [addr] | ||
| 211 | try self.code.resize(self.code.items.len + 7); | ||
| 212 | self.code.items[self.code.items.len - 7 ..][0..3].* = [3]u8{ 0xff, 0x14, 0x25 }; | ||
| 213 | mem.writeIntLittle(u32, self.code.items[self.code.items.len - 4 ..][0..4], got_addr); | ||
| 214 | const return_type = func.fn_type.fnReturnType(); | ||
| 215 | switch (return_type.zigTypeTag()) { | ||
| 216 | .Void => return MCValue{ .none = {} }, | ||
| 217 | .NoReturn => return MCValue{ .unreach = {} }, | ||
| 218 | else => return self.fail(inst.base.src, "TODO implement fn call with non-void return value", .{}), | ||
| 219 | } | ||
| 207 | } else { | 220 | } else { |
| 208 | return self.fail(inst.base.src, "TODO implement calling weird function values", .{}); | 221 | return self.fail(inst.base.src, "TODO implement calling weird function values", .{}); |
| 209 | } | 222 | } |
src-self-hosted/link.zig+2| ... | @@ -740,6 +740,7 @@ pub const ElfFile = struct { | ... | @@ -740,6 +740,7 @@ pub const ElfFile = struct { |
| 740 | const amt = try self.file.?.copyRangeAll(shdr.sh_offset, self.file.?, new_offset, text_size); | 740 | const amt = try self.file.?.copyRangeAll(shdr.sh_offset, self.file.?, new_offset, text_size); |
| 741 | if (amt != text_size) return error.InputOutput; | 741 | if (amt != text_size) return error.InputOutput; |
| 742 | shdr.sh_offset = new_offset; | 742 | shdr.sh_offset = new_offset; |
| 743 | phdr.p_offset = new_offset; | ||
| 743 | } | 744 | } |
| 744 | // Now that we know the code size, we need to update the program header for executable code | 745 | // Now that we know the code size, we need to update the program header for executable code |
| 745 | shdr.sh_size = needed_size; | 746 | shdr.sh_size = needed_size; |
| ... | @@ -1034,6 +1035,7 @@ pub const ElfFile = struct { | ... | @@ -1034,6 +1035,7 @@ pub const ElfFile = struct { |
| 1034 | const amt = try self.file.?.copyRangeAll(shdr.sh_offset, self.file.?, new_offset, shdr.sh_size); | 1035 | const amt = try self.file.?.copyRangeAll(shdr.sh_offset, self.file.?, new_offset, shdr.sh_size); |
| 1035 | if (amt != shdr.sh_size) return error.InputOutput; | 1036 | if (amt != shdr.sh_size) return error.InputOutput; |
| 1036 | shdr.sh_offset = new_offset; | 1037 | shdr.sh_offset = new_offset; |
| 1038 | phdr.p_offset = new_offset; | ||
| 1037 | } | 1039 | } |
| 1038 | shdr.sh_size = needed_size; | 1040 | shdr.sh_size = needed_size; |
| 1039 | phdr.p_memsz = needed_size; | 1041 | phdr.p_memsz = needed_size; |
test/stage2/zir.zig+53| ... | @@ -209,4 +209,57 @@ pub fn addCases(ctx: *TestContext) void { | ... | @@ -209,4 +209,57 @@ pub fn addCases(ctx: *TestContext) void { |
| 209 | \\ | 209 | \\ |
| 210 | }, | 210 | }, |
| 211 | ); | 211 | ); |
| 212 | |||
| 213 | ctx.addZIRCompareOutput( | ||
| 214 | "function call with no args no return value", | ||
| 215 | &[_][]const u8{ | ||
| 216 | \\@noreturn = primitive(noreturn) | ||
| 217 | \\@void = primitive(void) | ||
| 218 | \\@usize = primitive(usize) | ||
| 219 | \\@0 = int(0) | ||
| 220 | \\@1 = int(1) | ||
| 221 | \\@2 = int(2) | ||
| 222 | \\@3 = int(3) | ||
| 223 | \\ | ||
| 224 | \\@syscall_array = str("syscall") | ||
| 225 | \\@sysoutreg_array = str("={rax}") | ||
| 226 | \\@rax_array = str("{rax}") | ||
| 227 | \\@rdi_array = str("{rdi}") | ||
| 228 | \\@rcx_array = str("rcx") | ||
| 229 | \\@r11_array = str("r11") | ||
| 230 | \\@memory_array = str("memory") | ||
| 231 | \\ | ||
| 232 | \\@exit0_fnty = fntype([], @noreturn) | ||
| 233 | \\@exit0 = fn(@exit0_fnty, { | ||
| 234 | \\ %SYS_exit_group = int(231) | ||
| 235 | \\ %exit_code = as(@usize, @0) | ||
| 236 | \\ | ||
| 237 | \\ %syscall = ref(@syscall_array) | ||
| 238 | \\ %sysoutreg = ref(@sysoutreg_array) | ||
| 239 | \\ %rax = ref(@rax_array) | ||
| 240 | \\ %rdi = ref(@rdi_array) | ||
| 241 | \\ %rcx = ref(@rcx_array) | ||
| 242 | \\ %r11 = ref(@r11_array) | ||
| 243 | \\ %memory = ref(@memory_array) | ||
| 244 | \\ | ||
| 245 | \\ %rc = asm(%syscall, @usize, | ||
| 246 | \\ volatile=1, | ||
| 247 | \\ output=%sysoutreg, | ||
| 248 | \\ inputs=[%rax, %rdi], | ||
| 249 | \\ clobbers=[%rcx, %r11, %memory], | ||
| 250 | \\ args=[%SYS_exit_group, %exit_code]) | ||
| 251 | \\ | ||
| 252 | \\ %99 = unreachable() | ||
| 253 | \\}); | ||
| 254 | \\ | ||
| 255 | \\@start_fnty = fntype([], @noreturn, cc=Naked) | ||
| 256 | \\@start = fn(@start_fnty, { | ||
| 257 | \\ %0 = call(@exit0, []) | ||
| 258 | \\}) | ||
| 259 | \\@9 = str("_start") | ||
| 260 | \\@10 = ref(@9) | ||
| 261 | \\@11 = export(@10, @start) | ||
| 262 | }, | ||
| 263 | &[_][]const u8{""}, | ||
| 264 | ); | ||
| 212 | } | 265 | } |