| ... | @@ -105,7 +105,7 @@ frame_allocs: std.MultiArrayList(FrameAlloc) = .{}, | ... | @@ -105,7 +105,7 @@ frame_allocs: std.MultiArrayList(FrameAlloc) = .{}, |
| 105 | free_frame_indices: std.AutoArrayHashMapUnmanaged(FrameIndex, void) = .{}, | 105 | free_frame_indices: std.AutoArrayHashMapUnmanaged(FrameIndex, void) = .{}, |
| 106 | frame_locs: std.MultiArrayList(Mir.FrameLoc) = .{}, | 106 | frame_locs: std.MultiArrayList(Mir.FrameLoc) = .{}, |
| 107 | | 107 | |
| 108 | loop_repeat_info: std.AutoHashMapUnmanaged(Air.Inst.Index, struct { | 108 | loops: std.AutoHashMapUnmanaged(Air.Inst.Index, struct { |
| 109 | /// The state to restore before branching. | 109 | /// The state to restore before branching. |
| 110 | state: State, | 110 | state: State, |
| 111 | /// The branch target. | 111 | /// The branch target. |
| ... | @@ -219,6 +219,38 @@ pub const MCValue = union(enum) { | ... | @@ -219,6 +219,38 @@ pub const MCValue = union(enum) { |
| 219 | reserved_frame: FrameIndex, | 219 | reserved_frame: FrameIndex, |
| 220 | air_ref: Air.Inst.Ref, | 220 | air_ref: Air.Inst.Ref, |
| 221 | | 221 | |
| | 222 | fn isModifiable(mcv: MCValue) bool { |
| | 223 | return switch (mcv) { |
| | 224 | .none, |
| | 225 | .unreach, |
| | 226 | .dead, |
| | 227 | .undef, |
| | 228 | .immediate, |
| | 229 | .register_offset, |
| | 230 | .eflags, |
| | 231 | .register_overflow, |
| | 232 | .lea_symbol, |
| | 233 | .lea_direct, |
| | 234 | .lea_got, |
| | 235 | .lea_tlv, |
| | 236 | .lea_frame, |
| | 237 | .elementwise_regs_then_frame, |
| | 238 | .reserved_frame, |
| | 239 | .air_ref, |
| | 240 | => false, |
| | 241 | .register, |
| | 242 | .register_pair, |
| | 243 | .memory, |
| | 244 | .load_symbol, |
| | 245 | .load_got, |
| | 246 | .load_direct, |
| | 247 | .load_tlv, |
| | 248 | .indirect, |
| | 249 | => true, |
| | 250 | .load_frame => |frame_addr| !frame_addr.index.isNamed(), |
| | 251 | }; |
| | 252 | } |
| | 253 | |
| 222 | fn isMemory(mcv: MCValue) bool { | 254 | fn isMemory(mcv: MCValue) bool { |
| 223 | return switch (mcv) { | 255 | return switch (mcv) { |
| 224 | .memory, .indirect, .load_frame => true, | 256 | .memory, .indirect, .load_frame => true, |
| ... | @@ -822,7 +854,7 @@ pub fn generate( | ... | @@ -822,7 +854,7 @@ pub fn generate( |
| 822 | function.frame_allocs.deinit(gpa); | 854 | function.frame_allocs.deinit(gpa); |
| 823 | function.free_frame_indices.deinit(gpa); | 855 | function.free_frame_indices.deinit(gpa); |
| 824 | function.frame_locs.deinit(gpa); | 856 | function.frame_locs.deinit(gpa); |
| 825 | function.loop_repeat_info.deinit(gpa); | 857 | function.loops.deinit(gpa); |
| 826 | var block_it = function.blocks.valueIterator(); | 858 | var block_it = function.blocks.valueIterator(); |
| 827 | while (block_it.next()) |block| block.deinit(gpa); | 859 | while (block_it.next()) |block| block.deinit(gpa); |
| 828 | function.blocks.deinit(gpa); | 860 | function.blocks.deinit(gpa); |
| ... | @@ -2156,18 +2188,20 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -2156,18 +2188,20 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 2156 | const air_tags = self.air.instructions.items(.tag); | 2188 | const air_tags = self.air.instructions.items(.tag); |
| 2157 | | 2189 | |
| 2158 | self.arg_index = 0; | 2190 | self.arg_index = 0; |
| 2159 | for (body) |inst| { | 2191 | for (body) |inst| switch (air_tags[@intFromEnum(inst)]) { |
| 2160 | wip_mir_log.debug("{}", .{self.fmtAir(inst)}); | 2192 | .arg => { |
| 2161 | verbose_tracking_log.debug("{}", .{self.fmtTracking()}); | 2193 | wip_mir_log.debug("{}", .{self.fmtAir(inst)}); |
| | 2194 | verbose_tracking_log.debug("{}", .{self.fmtTracking()}); |
| 2162 | | 2195 | |
| 2163 | const old_air_bookkeeping = self.air_bookkeeping; | 2196 | const old_air_bookkeeping = self.air_bookkeeping; |
| 2164 | try self.inst_tracking.ensureUnusedCapacity(self.gpa, 1); | 2197 | try self.inst_tracking.ensureUnusedCapacity(self.gpa, 1); |
| 2165 | switch (air_tags[@intFromEnum(inst)]) { | 2198 | |
| 2166 | .arg => try self.airArg(inst), | 2199 | try self.airArg(inst); |
| 2167 | else => break, | 2200 | |
| 2168 | } | 2201 | self.checkInvariantsAfterAirInst(inst, old_air_bookkeeping); |
| 2169 | self.checkInvariantsAfterAirInst(inst, old_air_bookkeeping); | 2202 | }, |
| 2170 | } | 2203 | else => break, |
| | 2204 | }; |
| 2171 | | 2205 | |
| 2172 | if (self.arg_index == 0) try self.airDbgVarArgs(); | 2206 | if (self.arg_index == 0) try self.airDbgVarArgs(); |
| 2173 | self.arg_index = 0; | 2207 | self.arg_index = 0; |
| ... | @@ -2256,7 +2290,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -2256,7 +2290,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 2256 | .block => try self.airBlock(inst), | 2290 | .block => try self.airBlock(inst), |
| 2257 | .br => try self.airBr(inst), | 2291 | .br => try self.airBr(inst), |
| 2258 | .repeat => try self.airRepeat(inst), | 2292 | .repeat => try self.airRepeat(inst), |
| 2259 | .switch_dispatch => return self.fail("TODO implement `switch_dispatch`", .{}), | 2293 | .switch_dispatch => try self.airSwitchDispatch(inst), |
| 2260 | .trap => try self.airTrap(), | 2294 | .trap => try self.airTrap(), |
| 2261 | .breakpoint => try self.airBreakpoint(), | 2295 | .breakpoint => try self.airBreakpoint(), |
| 2262 | .ret_addr => try self.airRetAddr(inst), | 2296 | .ret_addr => try self.airRetAddr(inst), |
| ... | @@ -2345,7 +2379,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -2345,7 +2379,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 2345 | .field_parent_ptr => try self.airFieldParentPtr(inst), | 2379 | .field_parent_ptr => try self.airFieldParentPtr(inst), |
| 2346 | | 2380 | |
| 2347 | .switch_br => try self.airSwitchBr(inst), | 2381 | .switch_br => try self.airSwitchBr(inst), |
| 2348 | .loop_switch_br => return self.fail("TODO implement `loop_switch_br`", .{}), | 2382 | .loop_switch_br => try self.airLoopSwitchBr(inst), |
| 2349 | .slice_ptr => try self.airSlicePtr(inst), | 2383 | .slice_ptr => try self.airSlicePtr(inst), |
| 2350 | .slice_len => try self.airSliceLen(inst), | 2384 | .slice_len => try self.airSliceLen(inst), |
| 2351 | | 2385 | |
| ... | @@ -13637,14 +13671,13 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -13637,14 +13671,13 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void { |
| 13637 | self.scope_generation += 1; | 13671 | self.scope_generation += 1; |
| 13638 | const state = try self.saveState(); | 13672 | const state = try self.saveState(); |
| 13639 | | 13673 | |
| 13640 | try self.loop_repeat_info.putNoClobber(self.gpa, inst, .{ | 13674 | try self.loops.putNoClobber(self.gpa, inst, .{ |
| 13641 | .state = state, | 13675 | .state = state, |
| 13642 | .jmp_target = @intCast(self.mir_instructions.len), | 13676 | .jmp_target = @intCast(self.mir_instructions.len), |
| 13643 | }); | 13677 | }); |
| 13644 | defer assert(self.loop_repeat_info.remove(inst)); | 13678 | defer assert(self.loops.remove(inst)); |
| 13645 | | 13679 | |
| 13646 | try self.genBody(body); | 13680 | try self.genBody(body); |
| 13647 | | | |
| 13648 | self.finishAirBookkeeping(); | 13681 | self.finishAirBookkeeping(); |
| 13649 | } | 13682 | } |
| 13650 | | 13683 | |
| ... | @@ -13685,10 +13718,8 @@ fn lowerBlock(self: *Self, inst: Air.Inst.Index, body: []const Air.Inst.Index) ! | ... | @@ -13685,10 +13718,8 @@ fn lowerBlock(self: *Self, inst: Air.Inst.Index, body: []const Air.Inst.Index) ! |
| 13685 | self.finishAirBookkeeping(); | 13718 | self.finishAirBookkeeping(); |
| 13686 | } | 13719 | } |
| 13687 | | 13720 | |
| 13688 | fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void { | 13721 | fn lowerSwitchBr(self: *Self, inst: Air.Inst.Index, switch_br: Air.UnwrappedSwitch, condition: MCValue) !void { |
| 13689 | const zcu = self.pt.zcu; | 13722 | const zcu = self.pt.zcu; |
| 13690 | const switch_br = self.air.unwrapSwitch(inst); | | |
| 13691 | const condition = try self.resolveInst(switch_br.operand); | | |
| 13692 | const condition_ty = self.typeOf(switch_br.operand); | 13723 | const condition_ty = self.typeOf(switch_br.operand); |
| 13693 | const liveness = try self.liveness.getSwitchBr(self.gpa, inst, switch_br.cases_len + 1); | 13724 | const liveness = try self.liveness.getSwitchBr(self.gpa, inst, switch_br.cases_len + 1); |
| 13694 | defer self.gpa.free(liveness.deaths); | 13725 | defer self.gpa.free(liveness.deaths); |
| ... | @@ -13699,13 +13730,6 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -13699,13 +13730,6 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void { |
| 13699 | else => unreachable, | 13730 | else => unreachable, |
| 13700 | }; | 13731 | }; |
| 13701 | | 13732 | |
| 13702 | // If the condition dies here in this switch instruction, process | | |
| 13703 | // that death now instead of later as this has an effect on | | |
| 13704 | // whether it needs to be spilled in the branches | | |
| 13705 | if (self.liveness.operandDies(inst, 0)) { | | |
| 13706 | if (switch_br.operand.toIndex()) |op_inst| try self.processDeath(op_inst); | | |
| 13707 | } | | |
| 13708 | | | |
| 13709 | self.scope_generation += 1; | 13733 | self.scope_generation += 1; |
| 13710 | const state = try self.saveState(); | 13734 | const state = try self.saveState(); |
| 13711 | | 13735 | |
| ... | @@ -13810,11 +13834,111 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -13810,11 +13834,111 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void { |
| 13810 | .close_scope = true, | 13834 | .close_scope = true, |
| 13811 | }); | 13835 | }); |
| 13812 | } | 13836 | } |
| | 13837 | } |
| | 13838 | |
| | 13839 | fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void { |
| | 13840 | const switch_br = self.air.unwrapSwitch(inst); |
| | 13841 | const condition = try self.resolveInst(switch_br.operand); |
| | 13842 | |
| | 13843 | // If the condition dies here in this switch instruction, process |
| | 13844 | // that death now instead of later as this has an effect on |
| | 13845 | // whether it needs to be spilled in the branches |
| | 13846 | if (self.liveness.operandDies(inst, 0)) { |
| | 13847 | if (switch_br.operand.toIndex()) |op_inst| try self.processDeath(op_inst); |
| | 13848 | } |
| | 13849 | |
| | 13850 | try self.lowerSwitchBr(inst, switch_br, condition); |
| 13813 | | 13851 | |
| 13814 | // We already took care of pl_op.operand earlier, so there's nothing left to do | 13852 | // We already took care of pl_op.operand earlier, so there's nothing left to do |
| 13815 | self.finishAirBookkeeping(); | 13853 | self.finishAirBookkeeping(); |
| 13816 | } | 13854 | } |
| 13817 | | 13855 | |
| | 13856 | fn airLoopSwitchBr(self: *Self, inst: Air.Inst.Index) !void { |
| | 13857 | const switch_br = self.air.unwrapSwitch(inst); |
| | 13858 | const condition = try self.resolveInst(switch_br.operand); |
| | 13859 | |
| | 13860 | const mat_cond = if (condition.isModifiable() and |
| | 13861 | self.reuseOperand(inst, switch_br.operand, 0, condition)) |
| | 13862 | condition |
| | 13863 | else mat_cond: { |
| | 13864 | const mat_cond = try self.allocRegOrMem(inst, true); |
| | 13865 | try self.genCopy(self.typeOf(switch_br.operand), mat_cond, condition, .{}); |
| | 13866 | break :mat_cond mat_cond; |
| | 13867 | }; |
| | 13868 | self.inst_tracking.putAssumeCapacityNoClobber(inst, InstTracking.init(mat_cond)); |
| | 13869 | |
| | 13870 | // If the condition dies here in this switch instruction, process |
| | 13871 | // that death now instead of later as this has an effect on |
| | 13872 | // whether it needs to be spilled in the branches |
| | 13873 | if (self.liveness.operandDies(inst, 0)) { |
| | 13874 | if (switch_br.operand.toIndex()) |op_inst| try self.processDeath(op_inst); |
| | 13875 | } |
| | 13876 | |
| | 13877 | self.scope_generation += 1; |
| | 13878 | const state = try self.saveState(); |
| | 13879 | |
| | 13880 | try self.loops.putNoClobber(self.gpa, inst, .{ |
| | 13881 | .state = state, |
| | 13882 | .jmp_target = @intCast(self.mir_instructions.len), |
| | 13883 | }); |
| | 13884 | defer assert(self.loops.remove(inst)); |
| | 13885 | |
| | 13886 | // Stop tracking block result without forgetting tracking info |
| | 13887 | try self.freeValue(mat_cond); |
| | 13888 | |
| | 13889 | try self.lowerSwitchBr(inst, switch_br, mat_cond); |
| | 13890 | |
| | 13891 | try self.processDeath(inst); |
| | 13892 | self.finishAirBookkeeping(); |
| | 13893 | } |
| | 13894 | |
| | 13895 | fn airSwitchDispatch(self: *Self, inst: Air.Inst.Index) !void { |
| | 13896 | const br = self.air.instructions.items(.data)[@intFromEnum(inst)].br; |
| | 13897 | |
| | 13898 | const block_ty = self.typeOfIndex(br.block_inst); |
| | 13899 | const block_tracking = self.inst_tracking.getPtr(br.block_inst).?; |
| | 13900 | const loop_data = self.loops.getPtr(br.block_inst).?; |
| | 13901 | done: { |
| | 13902 | try self.getValue(block_tracking.short, null); |
| | 13903 | const src_mcv = try self.resolveInst(br.operand); |
| | 13904 | |
| | 13905 | if (self.reuseOperandAdvanced(inst, br.operand, 0, src_mcv, br.block_inst)) { |
| | 13906 | try self.getValue(block_tracking.short, br.block_inst); |
| | 13907 | // .long = .none to avoid merging operand and block result stack frames. |
| | 13908 | const current_tracking: InstTracking = .{ .long = .none, .short = src_mcv }; |
| | 13909 | try current_tracking.materializeUnsafe(self, br.block_inst, block_tracking.*); |
| | 13910 | for (current_tracking.getRegs()) |src_reg| self.register_manager.freeReg(src_reg); |
| | 13911 | break :done; |
| | 13912 | } |
| | 13913 | |
| | 13914 | try self.getValue(block_tracking.short, br.block_inst); |
| | 13915 | const dst_mcv = block_tracking.short; |
| | 13916 | try self.genCopy(block_ty, dst_mcv, try self.resolveInst(br.operand), .{}); |
| | 13917 | break :done; |
| | 13918 | } |
| | 13919 | |
| | 13920 | // Process operand death so that it is properly accounted for in the State below. |
| | 13921 | if (self.liveness.operandDies(inst, 0)) { |
| | 13922 | if (br.operand.toIndex()) |op_inst| try self.processDeath(op_inst); |
| | 13923 | } |
| | 13924 | |
| | 13925 | try self.restoreState(loop_data.state, &.{}, .{ |
| | 13926 | .emit_instructions = true, |
| | 13927 | .update_tracking = false, |
| | 13928 | .resurrect = false, |
| | 13929 | .close_scope = false, |
| | 13930 | }); |
| | 13931 | |
| | 13932 | // Emit a jump with a relocation. It will be patched up after the block ends. |
| | 13933 | // Leave the jump offset undefined |
| | 13934 | _ = try self.asmJmpReloc(loop_data.jmp_target); |
| | 13935 | |
| | 13936 | // Stop tracking block result without forgetting tracking info |
| | 13937 | try self.freeValue(block_tracking.short); |
| | 13938 | |
| | 13939 | self.finishAirBookkeeping(); |
| | 13940 | } |
| | 13941 | |
| 13818 | fn performReloc(self: *Self, reloc: Mir.Inst.Index) void { | 13942 | fn performReloc(self: *Self, reloc: Mir.Inst.Index) void { |
| 13819 | const next_inst: u32 = @intCast(self.mir_instructions.len); | 13943 | const next_inst: u32 = @intCast(self.mir_instructions.len); |
| 13820 | switch (self.mir_instructions.items(.tag)[reloc]) { | 13944 | switch (self.mir_instructions.items(.tag)[reloc]) { |
| ... | @@ -13891,7 +14015,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -13891,7 +14015,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void { |
| 13891 | | 14015 | |
| 13892 | fn airRepeat(self: *Self, inst: Air.Inst.Index) !void { | 14016 | fn airRepeat(self: *Self, inst: Air.Inst.Index) !void { |
| 13893 | const loop_inst = self.air.instructions.items(.data)[@intFromEnum(inst)].repeat.loop_inst; | 14017 | const loop_inst = self.air.instructions.items(.data)[@intFromEnum(inst)].repeat.loop_inst; |
| 13894 | const repeat_info = self.loop_repeat_info.get(loop_inst).?; | 14018 | const repeat_info = self.loops.get(loop_inst).?; |
| 13895 | try self.restoreState(repeat_info.state, &.{}, .{ | 14019 | try self.restoreState(repeat_info.state, &.{}, .{ |
| 13896 | .emit_instructions = true, | 14020 | .emit_instructions = true, |
| 13897 | .update_tracking = false, | 14021 | .update_tracking = false, |
| ... | @@ -19578,7 +19702,10 @@ fn typeOf(self: *Self, inst: Air.Inst.Ref) Type { | ... | @@ -19578,7 +19702,10 @@ fn typeOf(self: *Self, inst: Air.Inst.Ref) Type { |
| 19578 | fn typeOfIndex(self: *Self, inst: Air.Inst.Index) Type { | 19702 | fn typeOfIndex(self: *Self, inst: Air.Inst.Index) Type { |
| 19579 | const pt = self.pt; | 19703 | const pt = self.pt; |
| 19580 | const zcu = pt.zcu; | 19704 | const zcu = pt.zcu; |
| 19581 | return self.air.typeOfIndex(inst, &zcu.intern_pool); | 19705 | return switch (self.air.instructions.items(.tag)[@intFromEnum(inst)]) { |
| | 19706 | .loop_switch_br => self.typeOf(self.air.unwrapSwitch(inst).operand), |
| | 19707 | else => self.air.typeOfIndex(inst, &zcu.intern_pool), |
| | 19708 | }; |
| 19582 | } | 19709 | } |
| 19583 | | 19710 | |
| 19584 | fn intCompilerRtAbiName(int_bits: u32) u8 { | 19711 | fn intCompilerRtAbiName(int_bits: u32) u8 { |