@@ -108,7 +108,7 @@ frame_allocs: std.MultiArrayList(FrameAlloc) = .{},
108
108
free_frame_indices : std .AutoArrayHashMapUnmanaged (FrameIndex , void ) = .{},
109
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
112
/// The state to restore before branching.
113
113
state : State ,
114
114
/// The branch target.
@@ -232,11 +232,12 @@ const MCValue = union(enum) {
232
232
.register ,
233
233
.register_pair ,
234
234
.register_offset ,
235
- .load_frame ,
236
235
.load_symbol ,
237
236
.load_tlv ,
238
237
.indirect ,
239
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
805
function .frame_allocs .deinit (gpa );
805
806
function .free_frame_indices .deinit (gpa );
806
807
function .frame_locs .deinit (gpa );
807
- function .loop_repeat_info .deinit (gpa );
808
+ function .loops .deinit (gpa );
808
809
var block_it = function .blocks .valueIterator ();
809
810
while (block_it .next ()) | block | block .deinit (gpa );
810
811
function .blocks .deinit (gpa );
@@ -1588,7 +1589,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
1588
1589
.block = > try func .airBlock (inst ),
1589
1590
.br = > try func .airBr (inst ),
1590
1591
.repeat = > try func .airRepeat (inst ),
1591
- .switch_dispatch = > return func .fail ( "TODO implement `switch_dispatch`" , .{} ),
1592
+ .switch_dispatch = > try func .airSwitchDispatch ( inst ),
1592
1593
.trap = > try func .airTrap (),
1593
1594
.breakpoint = > try func .airBreakpoint (),
1594
1595
.ret_addr = > try func .airRetAddr (inst ),
@@ -1678,7 +1679,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
1678
1679
.field_parent_ptr = > try func .airFieldParentPtr (inst ),
1679
1680
1680
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
1684
.ptr_slice_len_ptr = > try func .airPtrSliceLenPtr (inst ),
1684
1685
.ptr_slice_ptr_ptr = > try func .airPtrSlicePtrPtr (inst ),
@@ -5610,11 +5611,11 @@ fn airLoop(func: *Func, inst: Air.Inst.Index) !void {
5610
5611
func .scope_generation += 1 ;
5611
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
5615
.state = state ,
5615
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
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
5672
5672
5673
fn airSwitchBr (func : * Func , inst : Air.Inst.Index ) ! void {
5673
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
5675
const condition = try func .resolveInst (switch_br .operand );
5679
- const condition_ty = func .typeOf (switch_br .operand );
5680
5676
5681
5677
// If the condition dies here in this switch instruction, process
5682
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
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
5700
func .scope_generation += 1 ;
5689
5701
const state = try func .saveState ();
5690
5702
@@ -5785,8 +5797,92 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void {
5785
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
5886
func .finishAirBookkeeping ();
5791
5887
}
5792
5888
@@ -5867,7 +5963,7 @@ fn airBr(func: *Func, inst: Air.Inst.Index) !void {
5867
5963
5868
5964
fn airRepeat (func : * Func , inst : Air.Inst.Index ) ! void {
5869
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
5967
try func .restoreState (repeat_info .state , &.{}, .{
5872
5968
.emit_instructions = true ,
5873
5969
.update_tracking = false ,
@@ -8298,7 +8394,10 @@ fn typeOf(func: *Func, inst: Air.Inst.Ref) Type {
8298
8394
8299
8395
fn typeOfIndex (func : * Func , inst : Air.Inst.Index ) Type {
8300
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
8403
fn hasFeature (func : * Func , feature : Target.riscv.Feature ) bool {
0 commit comments