authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-09-01 01:42:17-07:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-09-01 18:31:01+01:00
log97ed2392033ba1713b6ab16d88d84dd019d6bb2e
tree0100fa5c452f6f5082e77a025cb7902d554a3861
parentd5b01df3c8f87621eaf32ef4b647a867b54628b2
signaturelock-open Commit is signed but in an unrecognized format.

riscv: implement `repeat` and the new `switch_br`


1 files changed, 72 insertions(+), 25 deletions(-)

src/arch/riscv64/CodeGen.zig+72-25
...@@ -108,6 +108,13 @@ frame_allocs: std.MultiArrayList(FrameAlloc) = .{},...@@ -108,6 +108,13 @@ frame_allocs: std.MultiArrayList(FrameAlloc) = .{},
108free_frame_indices: std.AutoArrayHashMapUnmanaged(FrameIndex, void) = .{},108free_frame_indices: std.AutoArrayHashMapUnmanaged(FrameIndex, void) = .{},
109frame_locs: std.MultiArrayList(Mir.FrameLoc) = .{},109frame_locs: std.MultiArrayList(Mir.FrameLoc) = .{},
110110
111loop_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.
112air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init,119air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init,
113120
...@@ -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();
56045612
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);
56145620
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 {
56845690
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);
56915695
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);
56945698
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 );
57125716
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 }
57255719
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);
57275761
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 });
57365770
5737 func.performReloc(relocs[relocs.len - 1]);5771 func.performReloc(skip_case_reloc);
5738 }5772 }
57395773
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}
58335867
5868fn 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
5834fn airBoolOp(func: *Func, inst: Air.Inst.Index) !void {5881fn 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)];