| ... | @@ -108,6 +108,13 @@ frame_allocs: std.MultiArrayList(FrameAlloc) = .{}, | ... | @@ -108,6 +108,13 @@ 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 { |
| | 112 | /// The state to restore before branching. |
| | 113 | state: State, |
| | 114 | /// The branch target. |
| | 115 | jmp_target: Mir.Inst.Index, |
| | 116 | }) = .{}, |
| | 117 | |
| 111 | /// Debug field, used to find bugs in the compiler. | 118 | /// Debug field, used to find bugs in the compiler. |
| 112 | air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init, | 119 | air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init, |
| 113 | | 120 | |
| ... | @@ -797,6 +804,7 @@ pub fn generate( | ... | @@ -797,6 +804,7 @@ pub fn generate( |
| 797 | function.frame_allocs.deinit(gpa); | 804 | function.frame_allocs.deinit(gpa); |
| 798 | function.free_frame_indices.deinit(gpa); | 805 | function.free_frame_indices.deinit(gpa); |
| 799 | function.frame_locs.deinit(gpa); | 806 | function.frame_locs.deinit(gpa); |
| | 807 | function.loop_repeat_info.deinit(gpa); |
| 800 | var block_it = function.blocks.valueIterator(); | 808 | var block_it = function.blocks.valueIterator(); |
| 801 | while (block_it.next()) |block| block.deinit(gpa); | 809 | while (block_it.next()) |block| block.deinit(gpa); |
| 802 | function.blocks.deinit(gpa); | 810 | function.blocks.deinit(gpa); |
| ... | @@ -1579,7 +1587,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -1579,7 +1587,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { |
| 1579 | .bitcast => try func.airBitCast(inst), | 1587 | .bitcast => try func.airBitCast(inst), |
| 1580 | .block => try func.airBlock(inst), | 1588 | .block => try func.airBlock(inst), |
| 1581 | .br => try func.airBr(inst), | 1589 | .br => try func.airBr(inst), |
| 1582 | .repeat => return func.fail("TODO implement `repeat`", .{}), | 1590 | .repeat => try func.airRepeat(inst), |
| 1583 | .switch_dispatch => return func.fail("TODO implement `switch_dispatch`", .{}), | 1591 | .switch_dispatch => return func.fail("TODO implement `switch_dispatch`", .{}), |
| 1584 | .trap => try func.airTrap(), | 1592 | .trap => try func.airTrap(), |
| 1585 | .breakpoint => try func.airBreakpoint(), | 1593 | .breakpoint => try func.airBreakpoint(), |
| ... | @@ -5602,15 +5610,13 @@ fn airLoop(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -5602,15 +5610,13 @@ fn airLoop(func: *Func, inst: Air.Inst.Index) !void { |
| 5602 | func.scope_generation += 1; | 5610 | func.scope_generation += 1; |
| 5603 | const state = try func.saveState(); | 5611 | const state = try func.saveState(); |
| 5604 | | 5612 | |
| 5605 | const jmp_target: Mir.Inst.Index = @intCast(func.mir_instructions.len); | 5613 | try func.loop_repeat_info.putNoClobber(func.gpa, inst, .{ |
| 5606 | try func.genBody(body); | 5614 | .state = state, |
| 5607 | try func.restoreState(state, &.{}, .{ | 5615 | .jmp_target = @intCast(func.mir_instructions.len), |
| 5608 | .emit_instructions = true, | | |
| 5609 | .update_tracking = false, | | |
| 5610 | .resurrect = false, | | |
| 5611 | .close_scope = true, | | |
| 5612 | }); | 5616 | }); |
| 5613 | _ = try func.jump(jmp_target); | 5617 | defer assert(func.loop_repeat_info.remove(inst)); |
| | 5618 | |
| | 5619 | try func.genBody(body); |
| 5614 | | 5620 | |
| 5615 | func.finishAirBookkeeping(); | 5621 | func.finishAirBookkeeping(); |
| 5616 | } | 5622 | } |
| ... | @@ -5684,12 +5690,10 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -5684,12 +5690,10 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void { |
| 5684 | | 5690 | |
| 5685 | var it = switch_br.iterateCases(); | 5691 | var it = switch_br.iterateCases(); |
| 5686 | while (it.next()) |case| { | 5692 | while (it.next()) |case| { |
| 5687 | if (case.ranges.len > 0) return func.fail("TODO: switch with ranges", .{}); | 5693 | var relocs = try func.gpa.alloc(Mir.Inst.Index, case.items.len + case.ranges.len); |
| 5688 | | | |
| 5689 | var relocs = try func.gpa.alloc(Mir.Inst.Index, case.items.len); | | |
| 5690 | defer func.gpa.free(relocs); | 5694 | defer func.gpa.free(relocs); |
| 5691 | | 5695 | |
| 5692 | for (case.items, relocs, 0..) |item, *reloc, i| { | 5696 | for (case.items, relocs[0..case.items.len]) |item, *reloc| { |
| 5693 | const item_mcv = try func.resolveInst(item); | 5697 | const item_mcv = try func.resolveInst(item); |
| 5694 | | 5698 | |
| 5695 | const cond_lock = switch (condition) { | 5699 | const cond_lock = switch (condition) { |
| ... | @@ -5710,22 +5714,52 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -5710,22 +5714,52 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void { |
| 5710 | cmp_reg, | 5714 | cmp_reg, |
| 5711 | ); | 5715 | ); |
| 5712 | | 5716 | |
| 5713 | if (!(i < relocs.len - 1)) { | | |
| 5714 | _ = try func.addInst(.{ | | |
| 5715 | .tag = .pseudo_not, | | |
| 5716 | .data = .{ .rr = .{ | | |
| 5717 | .rd = cmp_reg, | | |
| 5718 | .rs = cmp_reg, | | |
| 5719 | } }, | | |
| 5720 | }); | | |
| 5721 | } | | |
| 5722 | | | |
| 5723 | reloc.* = try func.condBr(condition_ty, .{ .register = cmp_reg }); | 5717 | reloc.* = try func.condBr(condition_ty, .{ .register = cmp_reg }); |
| 5724 | } | 5718 | } |
| 5725 | | 5719 | |
| | 5720 | for (case.ranges, relocs[case.items.len..]) |range, *reloc| { |
| | 5721 | const min_mcv = try func.resolveInst(range[0]); |
| | 5722 | const max_mcv = try func.resolveInst(range[1]); |
| | 5723 | const cond_lock = switch (condition) { |
| | 5724 | .register => func.register_manager.lockRegAssumeUnused(condition.register), |
| | 5725 | else => null, |
| | 5726 | }; |
| | 5727 | defer if (cond_lock) |lock| func.register_manager.unlockReg(lock); |
| | 5728 | |
| | 5729 | const temp_cmp_reg, const temp_cmp_lock = try func.allocReg(.int); |
| | 5730 | defer func.register_manager.unlockReg(temp_cmp_lock); |
| | 5731 | |
| | 5732 | // is `condition` less than `min`? is "true", we've failed |
| | 5733 | try func.genBinOp( |
| | 5734 | .cmp_gte, |
| | 5735 | condition, |
| | 5736 | condition_ty, |
| | 5737 | min_mcv, |
| | 5738 | condition_ty, |
| | 5739 | temp_cmp_reg, |
| | 5740 | ); |
| | 5741 | |
| | 5742 | // if the compare was true, we will jump to the fail case and fall through |
| | 5743 | // to the next checks |
| | 5744 | const lt_fail_reloc = try func.condBr(condition_ty, .{ .register = temp_cmp_reg }); |
| | 5745 | try func.genBinOp( |
| | 5746 | .cmp_gt, |
| | 5747 | condition, |
| | 5748 | condition_ty, |
| | 5749 | max_mcv, |
| | 5750 | condition_ty, |
| | 5751 | temp_cmp_reg, |
| | 5752 | ); |
| | 5753 | |
| | 5754 | reloc.* = try func.condBr(condition_ty, .{ .register = temp_cmp_reg }); |
| | 5755 | func.performReloc(lt_fail_reloc); |
| | 5756 | } |
| | 5757 | |
| | 5758 | const skip_case_reloc = try func.jump(undefined); |
| | 5759 | |
| 5726 | for (liveness.deaths[case.idx]) |operand| try func.processDeath(operand); | 5760 | for (liveness.deaths[case.idx]) |operand| try func.processDeath(operand); |
| 5727 | | 5761 | |
| 5728 | for (relocs[0 .. relocs.len - 1]) |reloc| func.performReloc(reloc); | 5762 | for (relocs) |reloc| func.performReloc(reloc); |
| 5729 | try func.genBody(case.body); | 5763 | try func.genBody(case.body); |
| 5730 | try func.restoreState(state, &.{}, .{ | 5764 | try func.restoreState(state, &.{}, .{ |
| 5731 | .emit_instructions = false, | 5765 | .emit_instructions = false, |
| ... | @@ -5734,7 +5768,7 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -5734,7 +5768,7 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void { |
| 5734 | .close_scope = true, | 5768 | .close_scope = true, |
| 5735 | }); | 5769 | }); |
| 5736 | | 5770 | |
| 5737 | func.performReloc(relocs[relocs.len - 1]); | 5771 | func.performReloc(skip_case_reloc); |
| 5738 | } | 5772 | } |
| 5739 | | 5773 | |
| 5740 | if (switch_br.else_body_len > 0) { | 5774 | if (switch_br.else_body_len > 0) { |
| ... | @@ -5831,6 +5865,19 @@ fn airBr(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -5831,6 +5865,19 @@ fn airBr(func: *Func, inst: Air.Inst.Index) !void { |
| 5831 | func.finishAirBookkeeping(); | 5865 | func.finishAirBookkeeping(); |
| 5832 | } | 5866 | } |
| 5833 | | 5867 | |
| | 5868 | fn airRepeat(func: *Func, inst: Air.Inst.Index) !void { |
| | 5869 | const loop_inst = func.air.instructions.items(.data)[@intFromEnum(inst)].repeat.loop_inst; |
| | 5870 | const repeat_info = func.loop_repeat_info.get(loop_inst).?; |
| | 5871 | try func.restoreState(repeat_info.state, &.{}, .{ |
| | 5872 | .emit_instructions = true, |
| | 5873 | .update_tracking = false, |
| | 5874 | .resurrect = false, |
| | 5875 | .close_scope = true, |
| | 5876 | }); |
| | 5877 | _ = try func.jump(repeat_info.jmp_target); |
| | 5878 | func.finishAirBookkeeping(); |
| | 5879 | } |
| | 5880 | |
| 5834 | fn airBoolOp(func: *Func, inst: Air.Inst.Index) !void { | 5881 | fn airBoolOp(func: *Func, inst: Air.Inst.Index) !void { |
| 5835 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 5882 | const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 5836 | const tag: Air.Inst.Tag = func.air.instructions.items(.tag)[@intFromEnum(inst)]; | 5883 | const tag: Air.Inst.Tag = func.air.instructions.items(.tag)[@intFromEnum(inst)]; |