Skip to content

Commit 2d5c0a7

Browse files
committed
Emit conditional opcodes when possible
1 parent 18f98f7 commit 2d5c0a7

File tree

6 files changed

+525
-385
lines changed

6 files changed

+525
-385
lines changed

src/jit/assembler/basic_block.rs

Lines changed: 167 additions & 101 deletions
Large diffs are not rendered by default.

src/jit/assembler/block_asm.rs

Lines changed: 64 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use crate::bitset::Bitset;
22
use crate::jit::assembler::arm::branch_assembler::B;
33
use crate::jit::assembler::basic_block::BasicBlock;
4-
use crate::jit::assembler::block_inst::{BlockAluOp, BlockAluSetCond, BlockSystemRegOp, BlockTransferOp, BranchEncoding, GuestInstInfo};
4+
use crate::jit::assembler::block_inst::{BlockAluOp, BlockAluSetCond, BlockInst, BlockSystemRegOp, BlockTransferOp, BranchEncoding, GuestInstInfo};
55
use crate::jit::assembler::block_inst_list::BlockInstList;
66
use crate::jit::assembler::block_reg_allocator::ALLOCATION_REGS;
77
use crate::jit::assembler::block_reg_set::BlockRegSet;
8-
use crate::jit::assembler::{BlockAsmBuf, BlockInst, BlockLabel, BlockOperand, BlockOperandShift, BlockReg, ANY_REG_LIMIT};
8+
use crate::jit::assembler::{BlockAsmBuf, BlockInstKind, BlockLabel, BlockOperand, BlockOperandShift, BlockReg, ANY_REG_LIMIT};
99
use crate::jit::inst_info::InstInfo;
1010
use crate::jit::reg::{Reg, RegReserve};
1111
use crate::jit::{Cond, MemoryAmount, ShiftType};
@@ -57,7 +57,7 @@ pub struct BlockAsm<'a> {
5757
tmp_shift_imm_reg: BlockReg,
5858
tmp_func_call_reg: BlockReg,
5959

60-
cond_block_end_label_stack: Vec<BlockLabel>,
60+
cond_block_end_label_stack: Vec<(BlockLabel, Cond, usize)>,
6161

6262
is_common_fun: bool,
6363
host_sp_ptr: *mut usize,
@@ -102,7 +102,7 @@ impl<'a> BlockAsm<'a> {
102102
inst_insert_index: None,
103103
};
104104

105-
instance.buf.insts.push(BlockInst::Prologue);
105+
instance.insert_inst(BlockInstKind::Prologue);
106106

107107
// First argument is store_host_sp: bool
108108
if !is_common_fun {
@@ -125,11 +125,11 @@ impl<'a> BlockAsm<'a> {
125125
instance
126126
}
127127

128-
fn insert_inst(&mut self, inst: BlockInst) {
128+
fn insert_inst(&mut self, inst: impl Into<BlockInst>) {
129129
match self.inst_insert_index {
130-
None => self.buf.insts.push(inst),
130+
None => self.buf.insts.push(inst.into()),
131131
Some(index) => {
132-
self.buf.insts.insert(index, inst);
132+
self.buf.insts.insert(index, inst.into());
133133
self.inst_insert_index = Some(index + 1);
134134
}
135135
}
@@ -226,7 +226,7 @@ impl<'a> BlockAsm<'a> {
226226
fn add_op3(&mut self, op: BlockAluOp, op0: BlockReg, op1: BlockReg, mut op2: BlockOperandShift, set_cond: BlockAluSetCond, thumb_pc_aligned: bool) {
227227
self.check_alu_imm_limit(&mut op2);
228228
self.check_imm_shift_limit(&mut op2);
229-
self.insert_inst(BlockInst::Alu3 {
229+
self.insert_inst(BlockInstKind::Alu3 {
230230
op,
231231
operands: [op0.into(), op1.into(), op2],
232232
set_cond,
@@ -237,7 +237,7 @@ impl<'a> BlockAsm<'a> {
237237
fn add_op2_op1(&mut self, op: BlockAluOp, op1: BlockReg, mut op2: BlockOperandShift, set_cond: BlockAluSetCond, thumb_pc_aligned: bool) {
238238
self.check_alu_imm_limit(&mut op2);
239239
self.check_imm_shift_limit(&mut op2);
240-
self.insert_inst(BlockInst::Alu2Op1 {
240+
self.insert_inst(BlockInstKind::Alu2Op1 {
241241
op,
242242
operands: [op1.into(), op2],
243243
set_cond,
@@ -250,7 +250,7 @@ impl<'a> BlockAsm<'a> {
250250
self.check_alu_imm_limit(&mut op2);
251251
}
252252
self.check_imm_shift_limit(&mut op2);
253-
self.insert_inst(BlockInst::Alu2Op0 {
253+
self.insert_inst(BlockInstKind::Alu2Op0 {
254254
op,
255255
operands: [op0.into(), op2],
256256
set_cond,
@@ -289,7 +289,7 @@ impl<'a> BlockAsm<'a> {
289289
op2 = self.tmp_operand_imm_reg.into();
290290
}
291291
self.check_imm_shift_limit(&mut op2);
292-
self.insert_inst(BlockInst::Transfer {
292+
self.insert_inst(BlockInstKind::Transfer {
293293
op,
294294
operands: [op0.into().into(), op1.into().into(), op2],
295295
signed,
@@ -307,7 +307,7 @@ impl<'a> BlockAsm<'a> {
307307
}
308308

309309
pub fn transfer_read_multiple(&mut self, operand: impl Into<BlockReg>, regs: RegReserve, write_back: bool, pre: bool, add_to_base: bool) {
310-
self.insert_inst(BlockInst::TransferMultiple {
310+
self.insert_inst(BlockInstKind::TransferMultiple {
311311
op: BlockTransferOp::Read,
312312
operand: operand.into(),
313313
regs,
@@ -318,7 +318,7 @@ impl<'a> BlockAsm<'a> {
318318
}
319319

320320
pub fn transfer_write_multiple(&mut self, operand: impl Into<BlockReg>, regs: RegReserve, write_back: bool, pre: bool, add_to_base: bool) {
321-
self.insert_inst(BlockInst::TransferMultiple {
321+
self.insert_inst(BlockInstKind::TransferMultiple {
322322
op: BlockTransferOp::Write,
323323
operand: operand.into(),
324324
regs,
@@ -329,33 +329,33 @@ impl<'a> BlockAsm<'a> {
329329
}
330330

331331
pub fn mrs_cpsr(&mut self, operand: impl Into<BlockReg>) {
332-
self.insert_inst(BlockInst::SystemReg {
332+
self.insert_inst(BlockInstKind::SystemReg {
333333
op: BlockSystemRegOp::Mrs,
334334
operand: operand.into().into(),
335335
})
336336
}
337337

338338
pub fn msr_cpsr(&mut self, operand: impl Into<BlockOperand>) {
339-
self.insert_inst(BlockInst::SystemReg {
339+
self.insert_inst(BlockInstKind::SystemReg {
340340
op: BlockSystemRegOp::Msr,
341341
operand: operand.into(),
342342
})
343343
}
344344

345345
pub fn bfc(&mut self, operand: impl Into<BlockReg>, lsb: u8, width: u8) {
346-
self.insert_inst(BlockInst::Bfc { operand: operand.into(), lsb, width })
346+
self.insert_inst(BlockInstKind::Bfc { operand: operand.into(), lsb, width })
347347
}
348348

349349
pub fn bfi(&mut self, op0: impl Into<BlockReg>, op1: impl Into<BlockReg>, lsb: u8, width: u8) {
350-
self.insert_inst(BlockInst::Bfi {
350+
self.insert_inst(BlockInstKind::Bfi {
351351
operands: [op0.into(), op1.into()],
352352
lsb,
353353
width,
354354
})
355355
}
356356

357357
pub fn muls_guest_thumb_pc_aligned(&mut self, op0: impl Into<BlockReg>, op1: impl Into<BlockReg>, op2: impl Into<BlockOperandShift>) {
358-
self.insert_inst(BlockInst::Mul {
358+
self.insert_inst(BlockInstKind::Mul {
359359
operands: [op0.into().into(), op1.into().into(), op2.into()],
360360
set_cond: BlockAluSetCond::HostGuest,
361361
thumb_pc_aligned: true,
@@ -366,30 +366,29 @@ impl<'a> BlockAsm<'a> {
366366
if !self.used_labels.insert(label.0) {
367367
panic!("{label:?} was already added");
368368
}
369-
self.insert_inst(BlockInst::Label { label, guest_pc: None })
369+
self.insert_inst(BlockInstKind::Label { label, guest_pc: None })
370370
}
371371

372372
pub fn branch(&mut self, label: BlockLabel, cond: Cond) {
373-
self.insert_inst(BlockInst::Branch { label, cond, block_index: 0 })
373+
self.insert_inst(BlockInst::new(cond, BlockInstKind::Branch { label, block_index: 0 }))
374374
}
375375

376376
pub fn save_context(&mut self) {
377-
self.insert_inst(BlockInst::SaveContext {
377+
self.insert_inst(BlockInstKind::SaveContext {
378378
thread_regs_addr_reg: self.thread_regs_addr_reg,
379-
tmp_guest_cpsr_reg: self.tmp_guest_cpsr_reg,
380379
});
381380
}
382381

383382
pub fn save_reg(&mut self, guest_reg: Reg) {
384-
self.insert_inst(BlockInst::SaveReg {
383+
self.insert_inst(BlockInstKind::SaveReg {
385384
guest_reg,
386385
reg_mapped: BlockReg::from(guest_reg),
387386
thread_regs_addr_reg: self.thread_regs_addr_reg,
388387
});
389388
}
390389

391390
pub fn restore_reg(&mut self, guest_reg: Reg) {
392-
self.insert_inst(BlockInst::RestoreReg {
391+
self.insert_inst(BlockInstKind::RestoreReg {
393392
guest_reg,
394393
reg_mapped: BlockReg::from(guest_reg),
395394
thread_regs_addr_reg: self.thread_regs_addr_reg,
@@ -401,12 +400,12 @@ impl<'a> BlockAsm<'a> {
401400
let host_sp_addr_reg = self.thread_regs_addr_reg;
402401
self.mov(host_sp_addr_reg, self.host_sp_ptr as u32);
403402
self.load_u32(BlockReg::Fixed(Reg::SP), host_sp_addr_reg, 0);
404-
self.buf.insts.push(BlockInst::Epilogue { restore_all_regs: true });
403+
self.insert_inst(BlockInstKind::Epilogue { restore_all_regs: true });
405404
}
406405

407406
pub fn epilogue_previous_block(&mut self) {
408407
self.add(BlockReg::Fixed(Reg::SP), BlockReg::Fixed(Reg::SP), ANY_REG_LIMIT as u32 * 4);
409-
self.buf.insts.push(BlockInst::Epilogue { restore_all_regs: false });
408+
self.insert_inst(BlockInstKind::Epilogue { restore_all_regs: false });
410409
}
411410

412411
pub fn call(&mut self, func: impl Into<BlockOperand>) {
@@ -478,7 +477,7 @@ impl<'a> BlockAsm<'a> {
478477
) {
479478
let args = self.handle_call_args(arg0, arg1, arg2, arg3);
480479
self.mov(self.tmp_func_call_reg, func.into());
481-
self.insert_inst(BlockInst::Call {
480+
self.insert_inst(BlockInstKind::Call {
482481
func_reg: self.tmp_func_call_reg,
483482
args: [
484483
args[0].map(|_| BlockReg::Fixed(Reg::R0)),
@@ -520,7 +519,7 @@ impl<'a> BlockAsm<'a> {
520519
has_return: bool,
521520
) {
522521
let args = self.handle_call_args(arg0, arg1, arg2, arg3);
523-
self.insert_inst(BlockInst::CallCommon {
522+
self.insert_inst(BlockInstKind::CallCommon {
524523
mem_offset: offset,
525524
args: [
526525
args[0].map(|_| BlockReg::Fixed(Reg::R0)),
@@ -533,12 +532,12 @@ impl<'a> BlockAsm<'a> {
533532
}
534533

535534
pub fn bkpt(&mut self, id: u16) {
536-
self.insert_inst(BlockInst::Bkpt(id));
535+
self.insert_inst(BlockInstKind::Bkpt(id));
537536
}
538537

539538
pub fn find_guest_pc_inst_index(&self, guest_pc_to_find: u32) -> Option<usize> {
540539
for (i, inst) in self.buf.insts.iter().enumerate().rev() {
541-
if let BlockInst::GuestPc(guest_pc) = inst {
540+
if let BlockInstKind::GuestPc(guest_pc) = &inst.kind {
542541
if *guest_pc == guest_pc_to_find {
543542
return Some(i);
544543
}
@@ -548,7 +547,7 @@ impl<'a> BlockAsm<'a> {
548547
}
549548

550549
pub fn guest_pc(&mut self, pc: u32) {
551-
self.insert_inst(BlockInst::GuestPc(pc));
550+
self.insert_inst(BlockInstKind::GuestPc(pc));
552551
}
553552

554553
pub fn guest_branch(&mut self, cond: Cond, target_pc: u32) {
@@ -560,11 +559,11 @@ impl<'a> BlockAsm<'a> {
560559
}
561560
Some(label) => *label,
562561
};
563-
self.insert_inst(BlockInst::Branch { label, cond, block_index: 0 });
562+
self.insert_inst(BlockInst::new(cond, BlockInstKind::Branch { label, block_index: 0 }));
564563
}
565564

566565
pub fn generic_guest_inst(&mut self, inst_info: &mut InstInfo) {
567-
self.insert_inst(BlockInst::GenericGuestInst {
566+
self.insert_inst(BlockInstKind::GenericGuestInst {
568567
inst: GuestInstInfo::new(inst_info),
569568
regs_mapping: [
570569
BlockReg::from(Reg::R0),
@@ -593,13 +592,20 @@ impl<'a> BlockAsm<'a> {
593592
if cond != Cond::AL {
594593
let label = self.new_label();
595594
self.branch(label, !cond);
596-
self.cond_block_end_label_stack.push(label);
595+
self.cond_block_end_label_stack.push((label, cond, self.buf.insts.len()));
597596
}
598597
}
599598

600599
pub fn end_cond_block(&mut self) {
601-
if let Some(label) = self.cond_block_end_label_stack.pop() {
602-
self.label(label);
600+
if let Some((label, cond, start_index)) = self.cond_block_end_label_stack.pop() {
601+
let cond_block_size = self.buf.insts.len() - start_index;
602+
let (_, outputs) = self.buf.insts[start_index].get_io();
603+
if cond_block_size == 1 && self.buf.insts[start_index].cond == Cond::AL && !outputs.contains(BlockReg::Fixed(Reg::CPSR)) && !outputs.contains(Reg::CPSR.into()) {
604+
self.buf.insts[start_index].cond = cond;
605+
self.buf.insts.remove(start_index - 1);
606+
} else {
607+
self.label(label);
608+
}
603609
}
604610
}
605611

@@ -610,29 +616,30 @@ impl<'a> BlockAsm<'a> {
610616
let mut current_node = self.insts_link.root;
611617
while !current_node.is_null() {
612618
let i = BlockInstList::deref(current_node).value;
613-
if let BlockInst::GuestPc(pc) = &self.buf.insts[i] {
619+
if let BlockInstKind::GuestPc(pc) = &self.buf.insts[i].kind {
614620
if let Some(guest_label) = self.buf.guest_branches_mapping.get(pc) {
615-
self.buf.insts[i] = BlockInst::Label {
621+
self.buf.insts[i] = BlockInstKind::Label {
616622
label: *guest_label,
617623
guest_pc: Some(*pc),
618-
};
624+
}
625+
.into();
619626
}
620627
}
621628

622-
if let BlockInst::Label { label, guest_pc } = self.buf.insts[i] {
629+
if let BlockInstKind::Label { label, guest_pc } = &self.buf.insts[i].kind {
623630
if let Some((p_label, p_guest_pc)) = previous_label {
624-
let replace_guest_pc = p_guest_pc.or(guest_pc);
631+
let replace_guest_pc = p_guest_pc.or(*guest_pc);
625632
previous_label = Some((p_label, replace_guest_pc));
626633
let previous_node = BlockInstList::deref(current_node).previous;
627634
let previous_i = BlockInstList::deref(previous_node).value;
628-
if let BlockInst::Label { guest_pc, .. } = &mut self.buf.insts[previous_i] {
629-
*guest_pc = replace_guest_pc;
630-
}
631635
self.insts_link.remove_entry(current_node);
632636
label_aliases.insert(label.0, p_label.0);
633637
current_node = previous_node;
638+
if let BlockInstKind::Label { guest_pc, .. } = &mut self.buf.insts[previous_i].kind {
639+
*guest_pc = replace_guest_pc;
640+
}
634641
} else {
635-
previous_label = Some((label, guest_pc));
642+
previous_label = Some((*label, *guest_pc));
636643
}
637644
} else {
638645
previous_label = None
@@ -706,8 +713,8 @@ impl<'a> BlockAsm<'a> {
706713
while !current_node.is_null() {
707714
let i = BlockInstList::deref(current_node).value;
708715

709-
match &mut self.buf.insts[i] {
710-
BlockInst::Label { label, .. } => {
716+
match &mut self.buf.insts[i].kind {
717+
BlockInstKind::Label { label, .. } => {
711718
let label = *label;
712719
// block_start_entry can be the same as current_node, when the previous iteration ended with a branch
713720
if basic_block_start != current_node {
@@ -719,7 +726,7 @@ impl<'a> BlockAsm<'a> {
719726
}
720727
last_label = Some(label);
721728
}
722-
BlockInst::Branch { label, .. } => {
729+
BlockInstKind::Branch { label, .. } => {
723730
if let Some(alias) = label_aliases.get(&label.0) {
724731
label.0 = *alias;
725732
}
@@ -730,7 +737,7 @@ impl<'a> BlockAsm<'a> {
730737
}
731738
last_label = None;
732739
}
733-
BlockInst::Call { has_return: false, .. } | BlockInst::Epilogue { .. } => {
740+
BlockInstKind::Call { has_return: false, .. } | BlockInstKind::Epilogue { .. } => {
734741
basic_blocks.push(BasicBlock::new(self, basic_block_start, current_node));
735742
basic_block_start = BlockInstList::deref(current_node).next;
736743
if let Some(last_label) = last_label {
@@ -755,17 +762,18 @@ impl<'a> BlockAsm<'a> {
755762
// Link blocks
756763
for (i, basic_block) in basic_blocks.iter_mut().enumerate() {
757764
let last_inst_index = BlockInstList::deref(basic_block.block_entry_end).value;
758-
match &mut self.buf.insts[last_inst_index] {
759-
BlockInst::Branch { label, cond, block_index, .. } => {
765+
let cond = self.buf.insts[last_inst_index].cond;
766+
match &mut self.buf.insts[last_inst_index].kind {
767+
BlockInstKind::Branch { label, block_index, .. } => {
760768
let labelled_block_index = basic_block_label_mapping.get(&label.0).unwrap();
761769
basic_block.exit_blocks.push(*labelled_block_index);
762770
*block_index = *labelled_block_index;
763-
if *cond != Cond::AL && i + 1 < basic_blocks_len {
771+
if cond != Cond::AL && i + 1 < basic_blocks_len {
764772
basic_block.exit_blocks.push(i + 1);
765773
}
766774
}
767775
// Don't add exit when last command in basic block is a breakout
768-
BlockInst::Call { has_return: false, .. } | BlockInst::Epilogue { .. } => {
776+
BlockInstKind::Call { has_return: false, .. } | BlockInstKind::Epilogue { .. } => {
769777
if i + 1 < basic_blocks_len {
770778
basic_block.exit_blocks.push(i + 1);
771779
}
@@ -793,12 +801,12 @@ impl<'a> BlockAsm<'a> {
793801
let mut basic_block_start_pc = block_start_pc;
794802
let mut current_node = basic_block.block_entry_start;
795803
while !current_node.is_null() {
796-
match &self.buf.insts[BlockInstList::deref(current_node).value] {
797-
BlockInst::Label { guest_pc: Some(pc), .. } => {
804+
match &self.buf.insts[BlockInstList::deref(current_node).value].kind {
805+
BlockInstKind::Label { guest_pc: Some(pc), .. } => {
798806
basic_block_start_pc = *pc;
799807
break;
800808
}
801-
BlockInst::GuestPc(pc) => {
809+
BlockInstKind::GuestPc(pc) => {
802810
basic_block_start_pc = *pc;
803811
break;
804812
}

0 commit comments

Comments
 (0)