| ... | @@ -108,7 +108,7 @@ frame_allocs: std.MultiArrayList(FrameAlloc) = .{}, | ... | @@ -108,7 +108,7 @@ frame_allocs: std.MultiArrayList(FrameAlloc) = .{}, |
| 108 | free_frame_indices: std.AutoArrayHashMapUnmanaged(FrameIndex, void) = .{}, | 108 | free_frame_indices: std.AutoArrayHashMapUnmanaged(FrameIndex, void) = .{}, |
| 109 | frame_locs: std.MultiArrayList(Mir.FrameLoc) = .{}, | 109 | frame_locs: std.MultiArrayList(Mir.FrameLoc) = .{}, |
| 110 | | 110 | |
| 111 | loop_repeat_info: std.AutoHashMapUnmanaged(Air.Inst.Index, struct { | 111 | loops: std.AutoHashMapUnmanaged(Air.Inst.Index, struct { |
| 112 | /// The state to restore before branching. | 112 | /// The state to restore before branching. |
| 113 | state: State, | 113 | state: State, |
| 114 | /// The branch target. | 114 | /// The branch target. |
| ... | @@ -232,11 +232,12 @@ const MCValue = union(enum) { | ... | @@ -232,11 +232,12 @@ const MCValue = union(enum) { |
| 232 | .register, | 232 | .register, |
| 233 | .register_pair, | 233 | .register_pair, |
| 234 | .register_offset, | 234 | .register_offset, |
| 235 | .load_frame, | | |
| 236 | .load_symbol, | 235 | .load_symbol, |
| 237 | .load_tlv, | 236 | .load_tlv, |
| 238 | .indirect, | 237 | .indirect, |
| 239 | => true, | 238 | => true, |
| | 239 | |
| | 240 | .load_frame => |frame_addr| !frame_addr.index.isNamed(), |
| 240 | }; | 241 | }; |
| 241 | } | 242 | } |
| 242 | | 243 | |
| ... | @@ -804,7 +805,7 @@ pub fn generate( | ... | @@ -804,7 +805,7 @@ pub fn generate( |
| 804 | function.frame_allocs.deinit(gpa); | 805 | function.frame_allocs.deinit(gpa); |
| 805 | function.free_frame_indices.deinit(gpa); | 806 | function.free_frame_indices.deinit(gpa); |
| 806 | function.frame_locs.deinit(gpa); | 807 | function.frame_locs.deinit(gpa); |
| 807 | function.loop_repeat_info.deinit(gpa); | 808 | function.loops.deinit(gpa); |
| 808 | var block_it = function.blocks.valueIterator(); | 809 | var block_it = function.blocks.valueIterator(); |
| 809 | while (block_it.next()) |block| block.deinit(gpa); | 810 | while (block_it.next()) |block| block.deinit(gpa); |
| 810 | function.blocks.deinit(gpa); | 811 | function.blocks.deinit(gpa); |
| ... | @@ -1588,7 +1589,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -1588,7 +1589,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { |
| 1588 | .block => try func.airBlock(inst), | 1589 | .block => try func.airBlock(inst), |
| 1589 | .br => try func.airBr(inst), | 1590 | .br => try func.airBr(inst), |
| 1590 | .repeat => try func.airRepeat(inst), | 1591 | .repeat => try func.airRepeat(inst), |
| 1591 | .switch_dispatch => return func.fail("TODO implement `switch_dispatch`", .{}), | 1592 | .switch_dispatch => try func.airSwitchDispatch(inst), |
| 1592 | .trap => try func.airTrap(), | 1593 | .trap => try func.airTrap(), |
| 1593 | .breakpoint => try func.airBreakpoint(), | 1594 | .breakpoint => try func.airBreakpoint(), |
| 1594 | .ret_addr => try func.airRetAddr(inst), | 1595 | .ret_addr => try func.airRetAddr(inst), |
| ... | @@ -1678,7 +1679,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -1678,7 +1679,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { |
| 1678 | .field_parent_ptr => try func.airFieldParentPtr(inst), | 1679 | .field_parent_ptr => try func.airFieldParentPtr(inst), |
| 1679 | | 1680 | |
| 1680 | .switch_br => try func.airSwitchBr(inst), | 1681 | .switch_br => try func.airSwitchBr(inst), |
| 1681 | .loop_switch_br => return func.fail("TODO implement `loop_switch_br`", .{}), | 1682 | .loop_switch_br => try func.airLoopSwitchBr(inst), |
| 1682 | | 1683 | |
| 1683 | .ptr_slice_len_ptr => try func.airPtrSliceLenPtr(inst), | 1684 | .ptr_slice_len_ptr => try func.airPtrSliceLenPtr(inst), |
| 1684 | .ptr_slice_ptr_ptr => try func.airPtrSlicePtrPtr(inst), | 1685 | .ptr_slice_ptr_ptr => try func.airPtrSlicePtrPtr(inst), |
| ... | @@ -5610,11 +5611,11 @@ fn airLoop(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -5610,11 +5611,11 @@ fn airLoop(func: *Func, inst: Air.Inst.Index) !void { |
| 5610 | func.scope_generation += 1; | 5611 | func.scope_generation += 1; |
| 5611 | const state = try func.saveState(); | 5612 | const state = try func.saveState(); |
| 5612 | | 5613 | |
| 5613 | try func.loop_repeat_info.putNoClobber(func.gpa, inst, .{ | 5614 | try func.loops.putNoClobber(func.gpa, inst, .{ |
| 5614 | .state = state, | 5615 | .state = state, |
| 5615 | .jmp_target = @intCast(func.mir_instructions.len), | 5616 | .jmp_target = @intCast(func.mir_instructions.len), |
| 5616 | }); | 5617 | }); |
| 5617 | defer assert(func.loop_repeat_info.remove(inst)); | 5618 | defer assert(func.loops.remove(inst)); |
| 5618 | | 5619 | |
| 5619 | try func.genBody(body); | 5620 | try func.genBody(body); |
| 5620 | | 5621 | |
| ... | @@ -5671,12 +5672,7 @@ fn lowerBlock(func: *Func, inst: Air.Inst.Index, body: []const Air.Inst.Index) ! | ... | @@ -5671,12 +5672,7 @@ fn lowerBlock(func: *Func, inst: Air.Inst.Index, body: []const Air.Inst.Index) ! |
| 5671 | | 5672 | |
| 5672 | fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void { | 5673 | fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void { |
| 5673 | const switch_br = func.air.unwrapSwitch(inst); | 5674 | const switch_br = func.air.unwrapSwitch(inst); |
| 5674 | | | |
| 5675 | const liveness = try func.liveness.getSwitchBr(func.gpa, inst, switch_br.cases_len + 1); | | |
| 5676 | defer func.gpa.free(liveness.deaths); | | |
| 5677 | | | |
| 5678 | const condition = try func.resolveInst(switch_br.operand); | 5675 | const condition = try func.resolveInst(switch_br.operand); |
| 5679 | const condition_ty = func.typeOf(switch_br.operand); | | |
| 5680 | | 5676 | |
| 5681 | // If the condition dies here in this switch instruction, process | 5677 | // If the condition dies here in this switch instruction, process |
| 5682 | // that death now instead of later as this has an effect on | 5678 | // that death now instead of later as this has an effect on |
| ... | @@ -5685,6 +5681,22 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -5685,6 +5681,22 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void { |
| 5685 | if (switch_br.operand.toIndex()) |op_inst| try func.processDeath(op_inst); | 5681 | if (switch_br.operand.toIndex()) |op_inst| try func.processDeath(op_inst); |
| 5686 | } | 5682 | } |
| 5687 | | 5683 | |
| | 5684 | try func.lowerSwitchBr(inst, switch_br, condition); |
| | 5685 | |
| | 5686 | // We already took care of pl_op.operand earlier, so there's nothing left to do |
| | 5687 | func.finishAirBookkeeping(); |
| | 5688 | } |
| | 5689 | |
| | 5690 | fn lowerSwitchBr( |
| | 5691 | func: *Func, |
| | 5692 | inst: Air.Inst.Index, |
| | 5693 | switch_br: Air.UnwrappedSwitch, |
| | 5694 | condition: MCValue, |
| | 5695 | ) !void { |
| | 5696 | const condition_ty = func.typeOf(switch_br.operand); |
| | 5697 | const liveness = try func.liveness.getSwitchBr(func.gpa, inst, switch_br.cases_len + 1); |
| | 5698 | defer func.gpa.free(liveness.deaths); |
| | 5699 | |
| 5688 | func.scope_generation += 1; | 5700 | func.scope_generation += 1; |
| 5689 | const state = try func.saveState(); | 5701 | const state = try func.saveState(); |
| 5690 | | 5702 | |
| ... | @@ -5785,8 +5797,92 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -5785,8 +5797,92 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void { |
| 5785 | .close_scope = true, | 5797 | .close_scope = true, |
| 5786 | }); | 5798 | }); |
| 5787 | } | 5799 | } |
| | 5800 | } |
| | 5801 | |
| | 5802 | fn airLoopSwitchBr(func: *Func, inst: Air.Inst.Index) !void { |
| | 5803 | const switch_br = func.air.unwrapSwitch(inst); |
| | 5804 | const condition = try func.resolveInst(switch_br.operand); |
| | 5805 | |
| | 5806 | const mat_cond = if (condition.isMutable() and |
| | 5807 | func.reuseOperand(inst, switch_br.operand, 0, condition)) |
| | 5808 | condition |
| | 5809 | else mat_cond: { |
| | 5810 | const ty = func.typeOf(switch_br.operand); |
| | 5811 | const mat_cond = try func.allocRegOrMem(ty, inst, true); |
| | 5812 | try func.genCopy(ty, mat_cond, condition); |
| | 5813 | break :mat_cond mat_cond; |
| | 5814 | }; |
| | 5815 | func.inst_tracking.putAssumeCapacityNoClobber(inst, InstTracking.init(mat_cond)); |
| | 5816 | |
| | 5817 | // If the condition dies here in this switch instruction, process |
| | 5818 | // that death now instead of later as this has an effect on |
| | 5819 | // whether it needs to be spilled in the branches |
| | 5820 | if (func.liveness.operandDies(inst, 0)) { |
| | 5821 | if (switch_br.operand.toIndex()) |op_inst| try func.processDeath(op_inst); |
| | 5822 | } |
| | 5823 | |
| | 5824 | func.scope_generation += 1; |
| | 5825 | const state = try func.saveState(); |
| | 5826 | |
| | 5827 | try func.loops.putNoClobber(func.gpa, inst, .{ |
| | 5828 | .state = state, |
| | 5829 | .jmp_target = @intCast(func.mir_instructions.len), |
| | 5830 | }); |
| | 5831 | defer assert(func.loops.remove(inst)); |
| | 5832 | |
| | 5833 | // Stop tracking block result without forgetting tracking info |
| | 5834 | try func.freeValue(mat_cond); |
| | 5835 | |
| | 5836 | try func.lowerSwitchBr(inst, switch_br, mat_cond); |
| | 5837 | |
| | 5838 | try func.processDeath(inst); |
| | 5839 | func.finishAirBookkeeping(); |
| | 5840 | } |
| | 5841 | |
| | 5842 | fn airSwitchDispatch(func: *Func, inst: Air.Inst.Index) !void { |
| | 5843 | const br = func.air.instructions.items(.data)[@intFromEnum(inst)].br; |
| | 5844 | |
| | 5845 | const block_ty = func.typeOfIndex(br.block_inst); |
| | 5846 | const block_tracking = func.inst_tracking.getPtr(br.block_inst).?; |
| | 5847 | const loop_data = func.loops.getPtr(br.block_inst).?; |
| | 5848 | done: { |
| | 5849 | try func.getValue(block_tracking.short, null); |
| | 5850 | const src_mcv = try func.resolveInst(br.operand); |
| | 5851 | |
| | 5852 | if (func.reuseOperandAdvanced(inst, br.operand, 0, src_mcv, br.block_inst)) { |
| | 5853 | try func.getValue(block_tracking.short, br.block_inst); |
| | 5854 | // .long = .none to avoid merging operand and block result stack frames. |
| | 5855 | const current_tracking: InstTracking = .{ .long = .none, .short = src_mcv }; |
| | 5856 | try current_tracking.materializeUnsafe(func, br.block_inst, block_tracking.*); |
| | 5857 | for (current_tracking.getRegs()) |src_reg| func.register_manager.freeReg(src_reg); |
| | 5858 | break :done; |
| | 5859 | } |
| | 5860 | |
| | 5861 | try func.getValue(block_tracking.short, br.block_inst); |
| | 5862 | const dst_mcv = block_tracking.short; |
| | 5863 | try func.genCopy(block_ty, dst_mcv, try func.resolveInst(br.operand)); |
| | 5864 | break :done; |
| | 5865 | } |
| | 5866 | |
| | 5867 | // Process operand death so that it is properly accounted for in the State below. |
| | 5868 | if (func.liveness.operandDies(inst, 0)) { |
| | 5869 | if (br.operand.toIndex()) |op_inst| try func.processDeath(op_inst); |
| | 5870 | } |
| | 5871 | |
| | 5872 | try func.restoreState(loop_data.state, &.{}, .{ |
| | 5873 | .emit_instructions = true, |
| | 5874 | .update_tracking = false, |
| | 5875 | .resurrect = false, |
| | 5876 | .close_scope = false, |
| | 5877 | }); |
| | 5878 | |
| | 5879 | // Emit a jump with a relocation. It will be patched up after the block ends. |
| | 5880 | // Leave the jump offset undefined |
| | 5881 | _ = try func.jump(loop_data.jmp_target); |
| | 5882 | |
| | 5883 | // Stop tracking block result without forgetting tracking info |
| | 5884 | try func.freeValue(block_tracking.short); |
| 5788 | | 5885 | |
| 5789 | // We already took care of pl_op.operand earlier, so there's nothing left to do | | |
| 5790 | func.finishAirBookkeeping(); | 5886 | func.finishAirBookkeeping(); |
| 5791 | } | 5887 | } |
| 5792 | | 5888 | |
| ... | @@ -5867,7 +5963,7 @@ fn airBr(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -5867,7 +5963,7 @@ fn airBr(func: *Func, inst: Air.Inst.Index) !void { |
| 5867 | | 5963 | |
| 5868 | fn airRepeat(func: *Func, inst: Air.Inst.Index) !void { | 5964 | fn airRepeat(func: *Func, inst: Air.Inst.Index) !void { |
| 5869 | const loop_inst = func.air.instructions.items(.data)[@intFromEnum(inst)].repeat.loop_inst; | 5965 | const loop_inst = func.air.instructions.items(.data)[@intFromEnum(inst)].repeat.loop_inst; |
| 5870 | const repeat_info = func.loop_repeat_info.get(loop_inst).?; | 5966 | const repeat_info = func.loops.get(loop_inst).?; |
| 5871 | try func.restoreState(repeat_info.state, &.{}, .{ | 5967 | try func.restoreState(repeat_info.state, &.{}, .{ |
| 5872 | .emit_instructions = true, | 5968 | .emit_instructions = true, |
| 5873 | .update_tracking = false, | 5969 | .update_tracking = false, |
| ... | @@ -8298,7 +8394,10 @@ fn typeOf(func: *Func, inst: Air.Inst.Ref) Type { | ... | @@ -8298,7 +8394,10 @@ fn typeOf(func: *Func, inst: Air.Inst.Ref) Type { |
| 8298 | | 8394 | |
| 8299 | fn typeOfIndex(func: *Func, inst: Air.Inst.Index) Type { | 8395 | fn typeOfIndex(func: *Func, inst: Air.Inst.Index) Type { |
| 8300 | const zcu = func.pt.zcu; | 8396 | const zcu = func.pt.zcu; |
| 8301 | return func.air.typeOfIndex(inst, &zcu.intern_pool); | 8397 | return switch (func.air.instructions.items(.tag)[@intFromEnum(inst)]) { |
| | 8398 | .loop_switch_br => func.typeOf(func.air.unwrapSwitch(inst).operand), |
| | 8399 | else => func.air.typeOfIndex(inst, &zcu.intern_pool), |
| | 8400 | }; |
| 8302 | } | 8401 | } |
| 8303 | | 8402 | |
| 8304 | fn hasFeature(func: *Func, feature: Target.riscv.Feature) bool { | 8403 | fn hasFeature(func: *Func, feature: Target.riscv.Feature) bool { |