| ... | @@ -3797,12 +3797,150 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3797,12 +3797,150 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void { |
| 3797 | return self.finishAir(inst, result, .{ .none, .none, .none }); | 3797 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 3798 | } | 3798 | } |
| 3799 | | 3799 | |
| | 3800 | fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u32 { |
| | 3801 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); |
| | 3802 | switch (condition) { |
| | 3803 | .none => unreachable, |
| | 3804 | .undef => unreachable, |
| | 3805 | .dead, .unreach => unreachable, |
| | 3806 | .compare_flags_signed => unreachable, |
| | 3807 | .compare_flags_unsigned => unreachable, |
| | 3808 | .register => |cond_reg| { |
| | 3809 | switch (case) { |
| | 3810 | .none => unreachable, |
| | 3811 | .undef => unreachable, |
| | 3812 | .dead, .unreach => unreachable, |
| | 3813 | .immediate => |imm| { |
| | 3814 | _ = try self.addInst(.{ |
| | 3815 | .tag = .@"test", |
| | 3816 | .ops = (Mir.Ops{ |
| | 3817 | .reg1 = registerAlias(cond_reg, abi_size), |
| | 3818 | }).encode(), |
| | 3819 | .data = .{ .imm = @intCast(u32, imm) }, |
| | 3820 | }); |
| | 3821 | return self.addInst(.{ |
| | 3822 | .tag = .cond_jmp_eq_ne, |
| | 3823 | .ops = (Mir.Ops{ |
| | 3824 | .flags = 0b00, |
| | 3825 | }).encode(), |
| | 3826 | .data = .{ .inst = undefined }, |
| | 3827 | }); |
| | 3828 | }, |
| | 3829 | .register => |reg| { |
| | 3830 | _ = try self.addInst(.{ |
| | 3831 | .tag = .@"test", |
| | 3832 | .ops = (Mir.Ops{ |
| | 3833 | .reg1 = registerAlias(cond_reg, abi_size), |
| | 3834 | .reg2 = registerAlias(reg, abi_size), |
| | 3835 | }).encode(), |
| | 3836 | .data = undefined, |
| | 3837 | }); |
| | 3838 | return self.addInst(.{ |
| | 3839 | .tag = .cond_jmp_eq_ne, |
| | 3840 | .ops = (Mir.Ops{ |
| | 3841 | .flags = 0b00, |
| | 3842 | }).encode(), |
| | 3843 | .data = .{ .inst = undefined }, |
| | 3844 | }); |
| | 3845 | }, |
| | 3846 | .stack_offset => { |
| | 3847 | if (abi_size <= 8) { |
| | 3848 | const reg = try self.copyToTmpRegister(ty, case); |
| | 3849 | return self.genCondSwitchMir(ty, condition, .{ .register = reg }); |
| | 3850 | } |
| | 3851 | |
| | 3852 | return self.fail("TODO implement switch mir when case is stack offset with abi larger than 8 bytes", .{}); |
| | 3853 | }, |
| | 3854 | else => { |
| | 3855 | return self.fail("TODO implement switch mir when case is {}", .{case}); |
| | 3856 | }, |
| | 3857 | } |
| | 3858 | }, |
| | 3859 | else => { |
| | 3860 | return self.fail("TODO implemenent switch mir when condition is {}", .{condition}); |
| | 3861 | }, |
| | 3862 | } |
| | 3863 | } |
| | 3864 | |
| 3800 | fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { | 3865 | fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 3801 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 3866 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 3802 | const condition = pl_op.operand; | 3867 | const condition = try self.resolveInst(pl_op.operand); |
| 3803 | _ = condition; | 3868 | const condition_ty = self.air.typeOf(pl_op.operand); |
| 3804 | return self.fail("TODO airSwitch for {}", .{self.target.cpu.arch}); | 3869 | const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload); |
| 3805 | // return self.finishAir(inst, .dead, .{ condition, .none, .none }); | 3870 | var extra_index: usize = switch_br.end; |
| | 3871 | var case_i: u32 = 0; |
| | 3872 | const liveness = try self.liveness.getSwitchBr( |
| | 3873 | self.gpa, |
| | 3874 | inst, |
| | 3875 | switch_br.data.cases_len + 1, |
| | 3876 | ); |
| | 3877 | defer self.gpa.free(liveness.deaths); |
| | 3878 | |
| | 3879 | while (case_i < switch_br.data.cases_len) : (case_i += 1) { |
| | 3880 | const case = self.air.extraData(Air.SwitchBr.Case, extra_index); |
| | 3881 | const items = @bitCast([]const Air.Inst.Ref, self.air.extra[case.end..][0..case.data.items_len]); |
| | 3882 | const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len]; |
| | 3883 | extra_index = case.end + items.len + case_body.len; |
| | 3884 | |
| | 3885 | var relocs = try self.gpa.alloc(u32, items.len); |
| | 3886 | defer self.gpa.free(relocs); |
| | 3887 | |
| | 3888 | for (items) |item, item_i| { |
| | 3889 | const item_mcv = try self.resolveInst(item); |
| | 3890 | relocs[item_i] = try self.genCondSwitchMir(condition_ty, condition, item_mcv); |
| | 3891 | } |
| | 3892 | |
| | 3893 | // Capture the state of register and stack allocation state so that we can revert to it. |
| | 3894 | const parent_next_stack_offset = self.next_stack_offset; |
| | 3895 | const parent_free_registers = self.register_manager.free_registers; |
| | 3896 | var parent_stack = try self.stack.clone(self.gpa); |
| | 3897 | defer parent_stack.deinit(self.gpa); |
| | 3898 | const parent_registers = self.register_manager.registers; |
| | 3899 | |
| | 3900 | try self.branch_stack.append(.{}); |
| | 3901 | errdefer { |
| | 3902 | _ = self.branch_stack.pop(); |
| | 3903 | } |
| | 3904 | |
| | 3905 | try self.ensureProcessDeathCapacity(liveness.deaths[case_i].len); |
| | 3906 | for (liveness.deaths[case_i]) |operand| { |
| | 3907 | self.processDeath(operand); |
| | 3908 | } |
| | 3909 | |
| | 3910 | try self.genBody(case_body); |
| | 3911 | |
| | 3912 | // Revert to the previous register and stack allocation state. |
| | 3913 | var saved_case_branch = self.branch_stack.pop(); |
| | 3914 | defer saved_case_branch.deinit(self.gpa); |
| | 3915 | |
| | 3916 | self.register_manager.registers = parent_registers; |
| | 3917 | self.stack.deinit(self.gpa); |
| | 3918 | self.stack = parent_stack; |
| | 3919 | parent_stack = .{}; |
| | 3920 | |
| | 3921 | self.next_stack_offset = parent_next_stack_offset; |
| | 3922 | self.register_manager.free_registers = parent_free_registers; |
| | 3923 | |
| | 3924 | for (relocs) |reloc| { |
| | 3925 | try self.performReloc(reloc); |
| | 3926 | } |
| | 3927 | } |
| | 3928 | |
| | 3929 | if (switch_br.data.else_body_len > 0) { |
| | 3930 | return self.fail("TODO handle else branch in switch", .{}); |
| | 3931 | } |
| | 3932 | |
| | 3933 | // const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len]; |
| | 3934 | // const else_branch = self.branch_stack.addOneAssumeCapacity(); |
| | 3935 | // else_branch.* = .{}; |
| | 3936 | |
| | 3937 | // if (else_body.len != 0) { |
| | 3938 | // try self.genBody(else_body); |
| | 3939 | // } else { |
| | 3940 | |
| | 3941 | // } |
| | 3942 | |
| | 3943 | return self.finishAir(inst, .unreach, .{ pl_op.operand, .none, .none }); |
| 3806 | } | 3944 | } |
| 3807 | | 3945 | |
| 3808 | fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void { | 3946 | fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void { |