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) = .{},
108108free_frame_indices: std.AutoArrayHashMapUnmanaged(FrameIndex, void) = .{},
109109frame_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
111118/// Debug field, used to find bugs in the compiler.
112119air_bookkeeping: @TypeOf(air_bookkeeping_init) = air_bookkeeping_init,
113120
......@@ -797,6 +804,7 @@ pub fn generate(
797804 function.frame_allocs.deinit(gpa);
798805 function.free_frame_indices.deinit(gpa);
799806 function.frame_locs.deinit(gpa);
807 function.loop_repeat_info.deinit(gpa);
800808 var block_it = function.blocks.valueIterator();
801809 while (block_it.next()) |block| block.deinit(gpa);
802810 function.blocks.deinit(gpa);
......@@ -1579,7 +1587,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
15791587 .bitcast => try func.airBitCast(inst),
15801588 .block => try func.airBlock(inst),
15811589 .br => try func.airBr(inst),
1582 .repeat => return func.fail("TODO implement `repeat`", .{}),
1590 .repeat => try func.airRepeat(inst),
15831591 .switch_dispatch => return func.fail("TODO implement `switch_dispatch`", .{}),
15841592 .trap => try func.airTrap(),
15851593 .breakpoint => try func.airBreakpoint(),
......@@ -5602,15 +5610,13 @@ fn airLoop(func: *Func, inst: Air.Inst.Index) !void {
56025610 func.scope_generation += 1;
56035611 const state = try func.saveState();
56045612
5605 const jmp_target: Mir.Inst.Index = @intCast(func.mir_instructions.len);
5606 try func.genBody(body);
5607 try func.restoreState(state, &.{}, .{
5608 .emit_instructions = true,
5609 .update_tracking = false,
5610 .resurrect = false,
5611 .close_scope = true,
5613 try func.loop_repeat_info.putNoClobber(func.gpa, inst, .{
5614 .state = state,
5615 .jmp_target = @intCast(func.mir_instructions.len),
56125616 });
5613 _ = try func.jump(jmp_target);
5617 defer assert(func.loop_repeat_info.remove(inst));
5618
5619 try func.genBody(body);
56145620
56155621 func.finishAirBookkeeping();
56165622}
......@@ -5684,12 +5690,10 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void {
56845690
56855691 var it = switch_br.iterateCases();
56865692 while (it.next()) |case| {
5687 if (case.ranges.len > 0) return func.fail("TODO: switch with ranges", .{});
5688
5689 var relocs = try func.gpa.alloc(Mir.Inst.Index, case.items.len);
5693 var relocs = try func.gpa.alloc(Mir.Inst.Index, case.items.len + case.ranges.len);
56905694 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| {
56935697 const item_mcv = try func.resolveInst(item);
56945698
56955699 const cond_lock = switch (condition) {
......@@ -5710,22 +5714,52 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void {
57105714 cmp_reg,
57115715 );
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
57235717 reloc.* = try func.condBr(condition_ty, .{ .register = cmp_reg });
57245718 }
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
57265760 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);
57295763 try func.genBody(case.body);
57305764 try func.restoreState(state, &.{}, .{
57315765 .emit_instructions = false,
......@@ -5734,7 +5768,7 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void {
57345768 .close_scope = true,
57355769 });
57365770
5737 func.performReloc(relocs[relocs.len - 1]);
5771 func.performReloc(skip_case_reloc);
57385772 }
57395773
57405774 if (switch_br.else_body_len > 0) {
......@@ -5831,6 +5865,19 @@ fn airBr(func: *Func, inst: Air.Inst.Index) !void {
58315865 func.finishAirBookkeeping();
58325866}
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
58345881fn airBoolOp(func: *Func, inst: Air.Inst.Index) !void {
58355882 const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
58365883 const tag: Air.Inst.Tag = func.air.instructions.items(.tag)[@intFromEnum(inst)];