| ... | @@ -73,7 +73,7 @@ end_di_column: u32, | ... | @@ -73,7 +73,7 @@ end_di_column: u32, |
| 73 | /// The value is an offset into the `Function` `code` from the beginning. | 73 | /// The value is an offset into the `Function` `code` from the beginning. |
| 74 | /// To perform the reloc, write 32-bit signed little-endian integer | 74 | /// To perform the reloc, write 32-bit signed little-endian integer |
| 75 | /// which is a relative jump, based on the address following the reloc. | 75 | /// which is a relative jump, based on the address following the reloc. |
| 76 | exitlude_jump_relocs: std.ArrayListUnmanaged(Mir.Inst.Index) = .empty, | 76 | epilogue_relocs: std.ArrayListUnmanaged(Mir.Inst.Index) = .empty, |
| 77 | | 77 | |
| 78 | reused_operands: std.StaticBitSet(Liveness.bpi - 1) = undefined, | 78 | reused_operands: std.StaticBitSet(Liveness.bpi - 1) = undefined, |
| 79 | const_tracking: ConstTrackingMap = .empty, | 79 | const_tracking: ConstTrackingMap = .empty, |
| ... | @@ -928,7 +928,7 @@ pub fn generate( | ... | @@ -928,7 +928,7 @@ pub fn generate( |
| 928 | function.blocks.deinit(gpa); | 928 | function.blocks.deinit(gpa); |
| 929 | function.inst_tracking.deinit(gpa); | 929 | function.inst_tracking.deinit(gpa); |
| 930 | function.const_tracking.deinit(gpa); | 930 | function.const_tracking.deinit(gpa); |
| 931 | function.exitlude_jump_relocs.deinit(gpa); | 931 | function.epilogue_relocs.deinit(gpa); |
| 932 | function.mir_instructions.deinit(gpa); | 932 | function.mir_instructions.deinit(gpa); |
| 933 | function.mir_extra.deinit(gpa); | 933 | function.mir_extra.deinit(gpa); |
| 934 | function.mir_table.deinit(gpa); | 934 | function.mir_table.deinit(gpa); |
| ... | @@ -2193,24 +2193,24 @@ fn gen(self: *CodeGen) InnerError!void { | ... | @@ -2193,24 +2193,24 @@ fn gen(self: *CodeGen) InnerError!void { |
| 2193 | | 2193 | |
| 2194 | try self.genBody(self.air.getMainBody()); | 2194 | try self.genBody(self.air.getMainBody()); |
| 2195 | | 2195 | |
| 2196 | // TODO can single exitlude jump reloc be elided? What if it is not at the end of the code? | 2196 | const epilogue = if (self.epilogue_relocs.items.len > 0) epilogue: { |
| 2197 | // Example: | 2197 | const epilogue_relocs_last_index = self.epilogue_relocs.items.len - 1; |
| 2198 | // pub fn main() void { | 2198 | for (if (self.epilogue_relocs.items[epilogue_relocs_last_index] == self.mir_instructions.len - 1) epilogue_relocs: { |
| 2199 | // maybeErr() catch return; | 2199 | _ = self.mir_instructions.pop(); |
| 2200 | // unreachable; | 2200 | break :epilogue_relocs self.epilogue_relocs.items[0..epilogue_relocs_last_index]; |
| 2201 | // } | 2201 | } else self.epilogue_relocs.items) |epilogue_reloc| self.performReloc(epilogue_reloc); |
| 2202 | // Eliding the reloc will cause a miscompilation in this case. | 2202 | |
| 2203 | for (self.exitlude_jump_relocs.items) |jmp_reloc| { | 2203 | try self.asmPseudo(.pseudo_dbg_epilogue_begin_none); |
| 2204 | self.mir_instructions.items(.data)[jmp_reloc].inst.inst = | 2204 | const backpatch_stack_dealloc = try self.asmPlaceholder(); |
| 2205 | @intCast(self.mir_instructions.len); | 2205 | const backpatch_pop_callee_preserved_regs = try self.asmPlaceholder(); |
| 2206 | } | 2206 | try self.asmRegister(.{ ._, .pop }, .rbp); |
| 2207 | | 2207 | try self.asmPseudoRegisterImmediate(.pseudo_cfi_def_cfa_ri_s, .rsp, .s(8)); |
| 2208 | try self.asmPseudo(.pseudo_dbg_epilogue_begin_none); | 2208 | try self.asmOpOnly(.{ ._, .ret }); |
| 2209 | const backpatch_stack_dealloc = try self.asmPlaceholder(); | 2209 | break :epilogue .{ |
| 2210 | const backpatch_pop_callee_preserved_regs = try self.asmPlaceholder(); | 2210 | .backpatch_stack_dealloc = backpatch_stack_dealloc, |
| 2211 | try self.asmRegister(.{ ._, .pop }, .rbp); | 2211 | .backpatch_pop_callee_preserved_regs = backpatch_pop_callee_preserved_regs, |
| 2212 | try self.asmPseudoRegisterImmediate(.pseudo_cfi_def_cfa_ri_s, .rsp, .s(8)); | 2212 | }; |
| 2213 | try self.asmOpOnly(.{ ._, .ret }); | 2213 | } else null; |
| 2214 | | 2214 | |
| 2215 | const frame_layout = try self.computeFrameLayout(fn_info.cc); | 2215 | const frame_layout = try self.computeFrameLayout(fn_info.cc); |
| 2216 | const need_frame_align = frame_layout.stack_mask != std.math.maxInt(u32); | 2216 | const need_frame_align = frame_layout.stack_mask != std.math.maxInt(u32); |
| ... | @@ -2280,8 +2280,8 @@ fn gen(self: *CodeGen) InnerError!void { | ... | @@ -2280,8 +2280,8 @@ fn gen(self: *CodeGen) InnerError!void { |
| 2280 | }); | 2280 | }); |
| 2281 | } | 2281 | } |
| 2282 | } | 2282 | } |
| 2283 | if (need_frame_align or need_stack_adjust) { | 2283 | if (epilogue) |e| if (need_frame_align or need_stack_adjust) { |
| 2284 | self.mir_instructions.set(backpatch_stack_dealloc, switch (-frame_layout.save_reg_list.size(self.target)) { | 2284 | self.mir_instructions.set(e.backpatch_stack_dealloc, switch (-frame_layout.save_reg_list.size(self.target)) { |
| 2285 | 0 => .{ | 2285 | 0 => .{ |
| 2286 | .tag = .mov, | 2286 | .tag = .mov, |
| 2287 | .ops = .rr, | 2287 | .ops = .rr, |
| ... | @@ -2305,14 +2305,14 @@ fn gen(self: *CodeGen) InnerError!void { | ... | @@ -2305,14 +2305,14 @@ fn gen(self: *CodeGen) InnerError!void { |
| 2305 | } }, | 2305 | } }, |
| 2306 | }, | 2306 | }, |
| 2307 | }); | 2307 | }); |
| 2308 | } | 2308 | }; |
| 2309 | if (need_save_reg) { | 2309 | if (need_save_reg) { |
| 2310 | self.mir_instructions.set(backpatch_push_callee_preserved_regs, .{ | 2310 | self.mir_instructions.set(backpatch_push_callee_preserved_regs, .{ |
| 2311 | .tag = .pseudo, | 2311 | .tag = .pseudo, |
| 2312 | .ops = .pseudo_push_reg_list, | 2312 | .ops = .pseudo_push_reg_list, |
| 2313 | .data = .{ .reg_list = frame_layout.save_reg_list }, | 2313 | .data = .{ .reg_list = frame_layout.save_reg_list }, |
| 2314 | }); | 2314 | }); |
| 2315 | self.mir_instructions.set(backpatch_pop_callee_preserved_regs, .{ | 2315 | if (epilogue) |e| self.mir_instructions.set(e.backpatch_pop_callee_preserved_regs, .{ |
| 2316 | .tag = .pseudo, | 2316 | .tag = .pseudo, |
| 2317 | .ops = .pseudo_pop_reg_list, | 2317 | .ops = .pseudo_pop_reg_list, |
| 2318 | .data = .{ .reg_list = frame_layout.save_reg_list }, | 2318 | .data = .{ .reg_list = frame_layout.save_reg_list }, |
| ... | @@ -10007,8 +10007,8 @@ fn genLazy(self: *CodeGen, lazy_sym: link.File.LazySymbol) InnerError!void { | ... | @@ -10007,8 +10007,8 @@ fn genLazy(self: *CodeGen, lazy_sym: link.File.LazySymbol) InnerError!void { |
| 10007 | const ret_reg = param_regs[0]; | 10007 | const ret_reg = param_regs[0]; |
| 10008 | const enum_mcv = MCValue{ .register = param_regs[1] }; | 10008 | const enum_mcv = MCValue{ .register = param_regs[1] }; |
| 10009 | | 10009 | |
| 10010 | const exitlude_jump_relocs = try self.gpa.alloc(Mir.Inst.Index, enum_ty.enumFieldCount(zcu)); | 10010 | const epilogue_relocs = try self.gpa.alloc(Mir.Inst.Index, enum_ty.enumFieldCount(zcu)); |
| 10011 | defer self.gpa.free(exitlude_jump_relocs); | 10011 | defer self.gpa.free(epilogue_relocs); |
| 10012 | | 10012 | |
| 10013 | const data_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); | 10013 | const data_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); |
| 10014 | const data_lock = self.register_manager.lockRegAssumeUnused(data_reg); | 10014 | const data_lock = self.register_manager.lockRegAssumeUnused(data_reg); |
| ... | @@ -10017,7 +10017,7 @@ fn genLazy(self: *CodeGen, lazy_sym: link.File.LazySymbol) InnerError!void { | ... | @@ -10017,7 +10017,7 @@ fn genLazy(self: *CodeGen, lazy_sym: link.File.LazySymbol) InnerError!void { |
| 10017 | | 10017 | |
| 10018 | var data_off: i32 = 0; | 10018 | var data_off: i32 = 0; |
| 10019 | const tag_names = enum_ty.enumFields(zcu); | 10019 | const tag_names = enum_ty.enumFields(zcu); |
| 10020 | for (exitlude_jump_relocs, 0..) |*exitlude_jump_reloc, tag_index| { | 10020 | for (epilogue_relocs, 0..) |*epilogue_reloc, tag_index| { |
| 10021 | const tag_name_len = tag_names.get(ip)[tag_index].length(ip); | 10021 | const tag_name_len = tag_names.get(ip)[tag_index].length(ip); |
| 10022 | const tag_val = try pt.enumValueFieldIndex(enum_ty, @intCast(tag_index)); | 10022 | const tag_val = try pt.enumValueFieldIndex(enum_ty, @intCast(tag_index)); |
| 10023 | const tag_mcv = try self.genTypedValue(tag_val); | 10023 | const tag_mcv = try self.genTypedValue(tag_val); |
| ... | @@ -10033,7 +10033,7 @@ fn genLazy(self: *CodeGen, lazy_sym: link.File.LazySymbol) InnerError!void { | ... | @@ -10033,7 +10033,7 @@ fn genLazy(self: *CodeGen, lazy_sym: link.File.LazySymbol) InnerError!void { |
| 10033 | ); | 10033 | ); |
| 10034 | try self.genSetMem(.{ .reg = ret_reg }, 8, .usize, .{ .immediate = tag_name_len }, .{}); | 10034 | try self.genSetMem(.{ .reg = ret_reg }, 8, .usize, .{ .immediate = tag_name_len }, .{}); |
| 10035 | | 10035 | |
| 10036 | exitlude_jump_reloc.* = try self.asmJmpReloc(undefined); | 10036 | epilogue_reloc.* = try self.asmJmpReloc(undefined); |
| 10037 | self.performReloc(skip_reloc); | 10037 | self.performReloc(skip_reloc); |
| 10038 | | 10038 | |
| 10039 | data_off += @intCast(tag_name_len + 1); | 10039 | data_off += @intCast(tag_name_len + 1); |
| ... | @@ -10041,7 +10041,7 @@ fn genLazy(self: *CodeGen, lazy_sym: link.File.LazySymbol) InnerError!void { | ... | @@ -10041,7 +10041,7 @@ fn genLazy(self: *CodeGen, lazy_sym: link.File.LazySymbol) InnerError!void { |
| 10041 | | 10041 | |
| 10042 | try self.asmOpOnly(.{ ._, .ud2 }); | 10042 | try self.asmOpOnly(.{ ._, .ud2 }); |
| 10043 | | 10043 | |
| 10044 | for (exitlude_jump_relocs) |reloc| self.performReloc(reloc); | 10044 | for (epilogue_relocs) |reloc| self.performReloc(reloc); |
| 10045 | try self.asmOpOnly(.{ ._, .ret }); | 10045 | try self.asmOpOnly(.{ ._, .ret }); |
| 10046 | }, | 10046 | }, |
| 10047 | else => return self.fail( | 10047 | else => return self.fail( |
| ... | @@ -20114,7 +20114,7 @@ fn airRet(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void { | ... | @@ -20114,7 +20114,7 @@ fn airRet(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void { |
| 20114 | // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction | 20114 | // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction |
| 20115 | // which is available if the jump is 127 bytes or less forward. | 20115 | // which is available if the jump is 127 bytes or less forward. |
| 20116 | const jmp_reloc = try self.asmJmpReloc(undefined); | 20116 | const jmp_reloc = try self.asmJmpReloc(undefined); |
| 20117 | try self.exitlude_jump_relocs.append(self.gpa, jmp_reloc); | 20117 | try self.epilogue_relocs.append(self.gpa, jmp_reloc); |
| 20118 | } | 20118 | } |
| 20119 | | 20119 | |
| 20120 | fn airRetLoad(self: *CodeGen, inst: Air.Inst.Index) !void { | 20120 | fn airRetLoad(self: *CodeGen, inst: Air.Inst.Index) !void { |
| ... | @@ -20134,7 +20134,7 @@ fn airRetLoad(self: *CodeGen, inst: Air.Inst.Index) !void { | ... | @@ -20134,7 +20134,7 @@ fn airRetLoad(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 20134 | // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction | 20134 | // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction |
| 20135 | // which is available if the jump is 127 bytes or less forward. | 20135 | // which is available if the jump is 127 bytes or less forward. |
| 20136 | const jmp_reloc = try self.asmJmpReloc(undefined); | 20136 | const jmp_reloc = try self.asmJmpReloc(undefined); |
| 20137 | try self.exitlude_jump_relocs.append(self.gpa, jmp_reloc); | 20137 | try self.epilogue_relocs.append(self.gpa, jmp_reloc); |
| 20138 | } | 20138 | } |
| 20139 | | 20139 | |
| 20140 | fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !void { | 20140 | fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !void { |
| ... | @@ -24486,7 +24486,7 @@ fn airMemset(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void { | ... | @@ -24486,7 +24486,7 @@ fn airMemset(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void { |
| 24486 | self.register_manager.lockRegAssumeUnused(dst_regs[0]), | 24486 | self.register_manager.lockRegAssumeUnused(dst_regs[0]), |
| 24487 | self.register_manager.lockRegAssumeUnused(dst_regs[1]), | 24487 | self.register_manager.lockRegAssumeUnused(dst_regs[1]), |
| 24488 | }, | 24488 | }, |
| 24489 | else => .{ null, null }, | 24489 | else => @splat(null), |
| 24490 | }; | 24490 | }; |
| 24491 | for (dst_locks) |dst_lock| if (dst_lock) |lock| self.register_manager.unlockReg(lock); | 24491 | for (dst_locks) |dst_lock| if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 24492 | | 24492 | |
| ... | @@ -24625,7 +24625,7 @@ fn airMemcpy(self: *CodeGen, inst: Air.Inst.Index) !void { | ... | @@ -24625,7 +24625,7 @@ fn airMemcpy(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 24625 | self.register_manager.lockRegAssumeUnused(dst_regs[0]), | 24625 | self.register_manager.lockRegAssumeUnused(dst_regs[0]), |
| 24626 | self.register_manager.lockReg(dst_regs[1]), | 24626 | self.register_manager.lockReg(dst_regs[1]), |
| 24627 | }, | 24627 | }, |
| 24628 | else => .{ null, null }, | 24628 | else => @splat(null), |
| 24629 | }; | 24629 | }; |
| 24630 | for (dst_locks) |dst_lock| if (dst_lock) |lock| self.register_manager.unlockReg(lock); | 24630 | for (dst_locks) |dst_lock| if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 24631 | | 24631 | |
| ... | @@ -24636,7 +24636,7 @@ fn airMemcpy(self: *CodeGen, inst: Air.Inst.Index) !void { | ... | @@ -24636,7 +24636,7 @@ fn airMemcpy(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 24636 | self.register_manager.lockRegAssumeUnused(src_regs[0]), | 24636 | self.register_manager.lockRegAssumeUnused(src_regs[0]), |
| 24637 | self.register_manager.lockRegAssumeUnused(src_regs[1]), | 24637 | self.register_manager.lockRegAssumeUnused(src_regs[1]), |
| 24638 | }, | 24638 | }, |
| 24639 | else => .{ null, null }, | 24639 | else => @splat(null), |
| 24640 | }; | 24640 | }; |
| 24641 | for (src_locks) |src_lock| if (src_lock) |lock| self.register_manager.unlockReg(lock); | 24641 | for (src_locks) |src_lock| if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| 24642 | | 24642 | |