Skip to content

Commit 8b15572

Browse files
committed
Block link missing thumb branching
1 parent e0d4cea commit 8b15572

File tree

4 files changed

+33
-29
lines changed

4 files changed

+33
-29
lines changed

src/jit/emitter/emit_branch.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ impl<'a, const CPU: CpuType> JitAsm<'a, CPU> {
4141
}
4242

4343
pub fn analyze_branch_label<const THUMB: bool>(insts: &[InstInfo], branch_index: usize, cond: Cond, pc: u32, target_pc: u32) -> JitBranchInfo {
44+
let target_pc = target_pc & !1;
4445
if (THUMB || insts[branch_index].op != Op::Bl) && (cond as u8) < (Cond::AL as u8) && target_pc < pc {
4546
let diff = (pc - target_pc) >> if THUMB { 1 } else { 2 };
4647
if diff as usize <= branch_index {
@@ -87,14 +88,13 @@ impl<'a, const CPU: CpuType> JitAsm<'a, CPU> {
8788
if has_lr_return {
8889
asm.emit_return_stack_write(block_asm, runtime_data_addr_reg);
8990
}
90-
9191
block_asm.msr_cpsr(backed_up_cpsr_reg);
92-
block_asm.guest_branch(Cond::AL, target_pc);
92+
block_asm.guest_branch(Cond::AL, target_pc & !1);
9393
},
9494
|asm, block_asm| {
9595
block_asm.msr_cpsr(backed_up_cpsr_reg);
9696

97-
block_asm.mov(Reg::PC, target_pc | THUMB as u32);
97+
block_asm.mov(Reg::PC, target_pc);
9898
block_asm.save_context();
9999
asm.emit_branch_out_metadata(block_asm);
100100
block_asm.epilogue();
@@ -104,14 +104,14 @@ impl<'a, const CPU: CpuType> JitAsm<'a, CPU> {
104104
block_asm.free_reg(backed_up_cpsr_reg);
105105
}
106106
JitBranchInfo::Idle => {
107-
block_asm.mov(Reg::PC, target_pc | THUMB as u32);
107+
block_asm.mov(Reg::PC, target_pc);
108108
block_asm.save_context();
109109
self.emit_branch_out_metadata_with_idle_loop(block_asm);
110110
block_asm.epilogue();
111111
}
112112
JitBranchInfo::None => {
113113
let target_pc_reg = block_asm.new_reg();
114-
block_asm.mov(target_pc_reg, target_pc | THUMB as u32);
114+
block_asm.mov(target_pc_reg, target_pc);
115115
self.emit_branch_reg_common(block_asm, target_pc_reg, has_lr_return);
116116
block_asm.free_reg(target_pc_reg);
117117
}

src/jit/emitter/thumb/emit_branch_thumb.rs

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -32,51 +32,54 @@ impl<'a, const CPU: CpuType> JitAsm<'a, CPU> {
3232
};
3333

3434
block_asm.start_cond_block(cond);
35-
self.emit_branch_label_common::<true>(block_asm, target_pc, cond, false);
35+
self.emit_branch_label_common::<true>(block_asm, target_pc | 1, cond, false);
3636
block_asm.end_cond_block();
3737
}
3838

39-
pub fn emit_bl_setup_thumb(&mut self, block_asm: &mut BlockAsm) {
40-
let inst_info = self.jit_buf.current_inst();
41-
42-
let op0 = *inst_info.operands()[0].as_imm().unwrap() as i32;
43-
let lr = (self.jit_buf.current_pc as i32 + 4 + op0) as u32;
44-
45-
block_asm.mov(Reg::LR, lr);
39+
pub fn emit_bl_setup_thumb(&mut self) {
40+
let next_inst_info = &self.jit_buf.insts[self.jit_buf.current_index + 1];
41+
assert!(next_inst_info.op == Op::BlOffT || next_inst_info.op == Op::BlxOffT)
4642
}
4743

4844
pub fn emit_bl_thumb(&mut self, block_asm: &mut BlockAsm) {
49-
let inst_info = self.jit_buf.current_inst();
45+
let previous_inst_info = &self.jit_buf.insts[self.jit_buf.current_index - 1];
46+
assert_eq!(previous_inst_info.op, Op::BlSetupT);
5047

51-
let op0 = *inst_info.operands()[0].as_imm().unwrap();
52-
let lr = self.jit_buf.current_pc + 2;
48+
let relative_pc = *previous_inst_info.operands()[0].as_imm().unwrap() as i32 + 4;
49+
let mut target_pc = (self.jit_buf.current_pc as i32 - 2 + relative_pc) as u32;
5350

54-
let target_pc_reg = block_asm.new_reg();
55-
block_asm.add(target_pc_reg, Reg::LR, op0);
51+
let inst_info = self.jit_buf.current_inst();
52+
let op0 = *inst_info.operands()[0].as_imm().unwrap();
5653

57-
block_asm.mov(Reg::LR, lr | 1);
54+
target_pc += op0;
5855

5956
if inst_info.op == Op::BlxOffT {
60-
block_asm.bic(target_pc_reg, target_pc_reg, 0x1);
57+
target_pc &= !1;
6158
} else {
62-
block_asm.orr(target_pc_reg, target_pc_reg, 0x1);
59+
target_pc |= 1;
6360
}
6461

65-
self.emit_branch_reg_common(block_asm, target_pc_reg, true);
66-
block_asm.free_reg(target_pc_reg);
62+
block_asm.mov(Reg::LR, (self.jit_buf.current_pc + 2) | 1);
63+
self.emit_branch_label_common::<true>(block_asm, target_pc, Cond::AL, true);
6764
}
6865

6966
pub fn emit_bx_thumb(&mut self, block_asm: &mut BlockAsm) {
7067
let inst_info = self.jit_buf.current_inst();
7168

7269
let op0 = *inst_info.operands()[0].as_reg_no_shift().unwrap();
7370

74-
if inst_info.op == Op::BlxRegT {
75-
block_asm.mov(Reg::LR, self.jit_buf.current_pc + 3);
76-
}
7771
block_asm.mov(Reg::PC, op0);
7872
block_asm.save_context();
7973
self.emit_branch_out_metadata(block_asm);
8074
block_asm.epilogue();
8175
}
76+
77+
pub fn emit_blx_thumb(&mut self, block_asm: &mut BlockAsm) {
78+
let inst_info = self.jit_buf.current_inst();
79+
80+
let op0 = *inst_info.operands()[0].as_reg_no_shift().unwrap();
81+
82+
block_asm.mov(Reg::LR, self.jit_buf.current_pc + 3);
83+
self.emit_branch_reg_common(block_asm, op0.into(), true);
84+
}
8285
}

src/jit/emitter/thumb/emit_thumb.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,10 @@ impl<'a, const CPU: CpuType> JitAsm<'a, CPU> {
4949
Op::BT | Op::BeqT | Op::BneT | Op::BcsT | Op::BccT | Op::BmiT | Op::BplT | Op::BvsT | Op::BvcT | Op::BhiT | Op::BlsT | Op::BgeT | Op::BltT | Op::BgtT | Op::BleT => {
5050
self.emit_b_thumb(block_asm)
5151
}
52-
Op::BlSetupT => self.emit_bl_setup_thumb(block_asm),
52+
Op::BlSetupT => self.emit_bl_setup_thumb(),
5353
Op::BlOffT | Op::BlxOffT => self.emit_bl_thumb(block_asm),
54-
Op::BxRegT | Op::BlxRegT => self.emit_bx_thumb(block_asm),
54+
Op::BxRegT => self.emit_bx_thumb(block_asm),
55+
Op::BlxRegT => self.emit_blx_thumb(block_asm),
5556

5657
Op::SwiT => self.emit_swi::<true>(block_asm),
5758
Op::UnkThumb => {}

src/jit/jit_asm.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ fn emit_code_block_internal<const CPU: CpuType, const THUMB: bool>(store_host_sp
177177
assert!(asm.jit_buf.insts_cycle_counts.len() <= u16::MAX as usize, "{CPU:?} {guest_pc:x} {inst_info:?}")
178178
}
179179

180-
let is_unreturnable_branch = !inst_info.out_regs.is_reserved(Reg::LR) && inst_info.is_uncond_branch() && !inst_info.op.is_labelled_branch();
180+
let is_unreturnable_branch = !inst_info.out_regs.is_reserved(Reg::LR) && inst_info.is_uncond_branch();
181181
// let is_uncond_branch = inst_info.is_uncond_branch();
182182
let is_unknown = inst_info.op == Op::UnkArm || inst_info.op == Op::UnkThumb;
183183

0 commit comments

Comments
 (0)