Skip to content

Commit 0abf1c0

Browse files
committed
WIP
1 parent 7d7a486 commit 0abf1c0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+4435
-11646
lines changed

build.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,8 @@ fn main() {
239239
rust_type = "Cond".to_string();
240240
} else if t == "Register" {
241241
rust_type = "Reg".to_string();
242+
} else if t == "RegisterList" {
243+
rust_type = "RegReserve".to_string();
242244
}
243245

244246
let has_ptr_inner = t == "DOperand" || t == "QOperand" || t == "SOperand" || t == "RawLiteral" || t == "Label";
@@ -256,6 +258,8 @@ fn main() {
256258
delegate_params += &format!("Condition::from({name}), ");
257259
} else if t == "Register" {
258260
delegate_params += &format!("Register::from({name}), ");
261+
} else if t == "RegisterList" {
262+
delegate_params += &format!("RegisterList::from({name}), ");
259263
} else {
260264
delegate_params += &format!("{name}, ");
261265
}
@@ -304,7 +308,7 @@ fn main() {
304308
if !generic_types.is_empty() {
305309
writeln!(
306310
vixl_inst_wrapper_file,
307-
r"impl Masm{fun_name}{}<{generic_types}> for MarcoAssembler {{
311+
r"impl Masm{fun_name}{}<{generic_types}> for MacroAssembler {{
308312
fn {}{}(&mut self, {fun_params}) {{
309313
unsafe {{ masm_{}{}(self.inner, {delegate_params}) }}
310314
}}
@@ -320,7 +324,7 @@ fn main() {
320324
} else {
321325
writeln!(
322326
vixl_inst_wrapper_file,
323-
r"impl Masm{fun_name} for MarcoAssembler {{
327+
r"impl Masm{fun_name} for MacroAssembler {{
324328
fn {}0(&mut self) {{
325329
unsafe {{ masm_{}{}(self.inner) }}
326330
}}

src/jit/analyzer/asm_analyzer.rs

+147
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
use crate::jit::analyzer::basic_block::BasicBlock;
2+
use crate::jit::inst_info::InstInfo;
3+
use crate::jit::op::Op;
4+
use crate::jit::reg::{reg_reserve, Reg, RegReserve};
5+
use crate::jit::Cond;
6+
use bilge::prelude::*;
7+
8+
pub enum JitBranchInfo {
9+
Idle(usize),
10+
Local(usize),
11+
None,
12+
}
13+
14+
// Taken from https://github.com/melonDS-emu/melonDS/blob/24c402af51fe9c0537582173fc48d1ad3daff459/src/ARMJIT.cpp#L352
15+
fn is_idle_loop(insts: &[InstInfo]) -> bool {
16+
let mut regs_written_to = RegReserve::new();
17+
let mut regs_disallowed_to_write = RegReserve::new();
18+
for (i, inst) in insts.iter().enumerate() {
19+
if (inst.is_branch() && i < insts.len() - 1)
20+
|| matches!(inst.op, Op::Swi | Op::SwiT | Op::Mcr | Op::Mrc | Op::MrsRc | Op::MrsRs | Op::MsrIc | Op::MsrIs | Op::MsrRc | Op::MsrRs)
21+
|| inst.op.is_write_mem_transfer()
22+
{
23+
return false;
24+
}
25+
26+
let src_regs = inst.src_regs & !reg_reserve!(Reg::PC);
27+
let out_regs = inst.out_regs & !reg_reserve!(Reg::PC);
28+
regs_disallowed_to_write |= src_regs & !regs_written_to;
29+
30+
if !(out_regs & regs_disallowed_to_write).is_empty() {
31+
return false;
32+
}
33+
regs_written_to |= out_regs;
34+
}
35+
true
36+
}
37+
38+
fn analyze_branch_label(insts: &[InstInfo], thumb: bool, branch_index: usize, cond: Cond, pc: u32, target_pc: u32) -> JitBranchInfo {
39+
let target_pc = target_pc & !1;
40+
if (cond as u8) < (Cond::AL as u8) && target_pc < pc {
41+
let diff = (pc - target_pc) >> if thumb { 1 } else { 2 };
42+
if diff as usize <= branch_index {
43+
let jump_to_index = branch_index - diff as usize;
44+
if is_idle_loop(&insts[jump_to_index..branch_index + 1]) {
45+
return JitBranchInfo::Idle(jump_to_index);
46+
}
47+
}
48+
}
49+
50+
let relative_index = (target_pc as i32 - pc as i32) >> if thumb { 1 } else { 2 };
51+
let target_index = branch_index as i32 + relative_index;
52+
if target_index >= 0 && (target_index as usize) < insts.len() {
53+
JitBranchInfo::Local(target_index as usize)
54+
} else {
55+
JitBranchInfo::None
56+
}
57+
}
58+
59+
#[bitsize(8)]
60+
#[derive(Copy, Clone, FromBits)]
61+
pub struct InstMetadata {
62+
pub idle_loop: bool,
63+
pub external_branch: bool,
64+
pub local_branch_entry: bool,
65+
not_used: u5,
66+
}
67+
68+
impl Default for InstMetadata {
69+
fn default() -> Self {
70+
InstMetadata::from(0)
71+
}
72+
}
73+
74+
#[derive(Default)]
75+
pub struct AsmAnalyzer {
76+
pub basic_blocks: Vec<BasicBlock>,
77+
pub insts_metadata: Vec<InstMetadata>,
78+
}
79+
80+
impl AsmAnalyzer {
81+
fn create_basic_blocks(&mut self, start_pc: u32, insts: &[InstInfo], thumb: bool) {
82+
self.basic_blocks.clear();
83+
self.insts_metadata.clear();
84+
self.insts_metadata.resize(insts.len(), InstMetadata::default());
85+
86+
let pc_shift = if thumb { 1 } else { 2 };
87+
for i in 0..insts.len() {
88+
if insts[i].op.is_labelled_branch() && !insts[i].out_regs.is_reserved(Reg::LR) {
89+
let cond = insts[i].get_branch_cond();
90+
let pc = start_pc + i as u32 * 2;
91+
let relative_pc = insts[i].operands()[0].as_imm().unwrap() as i32 + (2 << pc_shift);
92+
let target_pc = (pc as i32 + relative_pc) as u32;
93+
match analyze_branch_label(insts, thumb, i, cond, pc, target_pc) {
94+
JitBranchInfo::Idle(target_index) => {
95+
self.insts_metadata[i].set_idle_loop(true);
96+
self.insts_metadata[target_index].set_local_branch_entry(true);
97+
}
98+
JitBranchInfo::Local(target_index) => {
99+
self.insts_metadata[target_index].set_local_branch_entry(true);
100+
}
101+
JitBranchInfo::None => {
102+
self.insts_metadata[i].set_external_branch(true);
103+
}
104+
}
105+
}
106+
}
107+
108+
let mut block_start = 0;
109+
for i in 0..insts.len() {
110+
if self.insts_metadata[i].local_branch_entry() {
111+
self.basic_blocks.push(BasicBlock::new(start_pc + ((block_start as u32) << pc_shift), block_start, i - 1));
112+
block_start = i;
113+
}
114+
115+
if insts[i].op.is_labelled_branch() && !insts[i].out_regs.is_reserved(Reg::LR) {
116+
self.basic_blocks.push(BasicBlock::new(start_pc + ((block_start as u32) << pc_shift), block_start, i));
117+
block_start = i + 1;
118+
}
119+
}
120+
if block_start < insts.len() {
121+
self.basic_blocks.push(BasicBlock::new(start_pc + ((block_start as u32) << pc_shift), block_start, insts.len() - 1));
122+
}
123+
124+
for basic_block in &mut self.basic_blocks {
125+
basic_block.resolve_live_regs(insts);
126+
}
127+
}
128+
129+
pub fn get_basic_block_metadata(&self, basic_block_index: usize) -> InstMetadata {
130+
self.insts_metadata[self.basic_blocks[basic_block_index].start_index]
131+
}
132+
133+
pub fn get_next_live_regs(&self, basic_block_index: usize, inst_index: usize) -> RegReserve {
134+
let basic_block = &self.basic_blocks[basic_block_index];
135+
basic_block.live_regs[inst_index - basic_block.start_index + 1]
136+
}
137+
138+
pub fn analyze(&mut self, start_pc: u32, insts: &[InstInfo], thumb: bool) {
139+
self.create_basic_blocks(start_pc, insts, thumb);
140+
141+
for (i, basic_block) in self.basic_blocks.iter().enumerate() {
142+
println!("basic block {i} start");
143+
println!("{:?}", basic_block.debug(insts, thumb));
144+
println!("basic block {i} end");
145+
}
146+
}
147+
}

src/jit/analyzer/basic_block.rs

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
use crate::jit::inst_info::InstInfo;
2+
use crate::jit::reg::RegReserve;
3+
use crate::jit::Cond;
4+
use std::fmt::{Debug, Formatter};
5+
6+
pub struct BasicBlock {
7+
pub start_pc: u32,
8+
pub start_index: usize,
9+
pub end_index: usize,
10+
pub live_regs: Vec<RegReserve>,
11+
}
12+
13+
impl BasicBlock {
14+
pub fn new(start_pc: u32, start_index: usize, end_index: usize) -> Self {
15+
BasicBlock {
16+
start_pc,
17+
start_index,
18+
end_index,
19+
live_regs: Vec::new(),
20+
}
21+
}
22+
23+
pub fn debug<'a>(&'a self, insts: &'a [InstInfo], thumb: bool) -> BasicBlockDebug<'a> {
24+
BasicBlockDebug { basic_block: self, insts, thumb }
25+
}
26+
27+
pub fn get_inputs(&self) -> RegReserve {
28+
self.live_regs[0]
29+
}
30+
31+
pub fn resolve_live_regs(&mut self, insts: &[InstInfo]) {
32+
let inst_length = self.end_index - self.start_index + 1;
33+
self.live_regs.clear();
34+
self.live_regs.resize(inst_length + 1, RegReserve::new());
35+
36+
for i in (0..inst_length).rev() {
37+
let mut previous_ranges = self.live_regs[i + 1];
38+
previous_ranges -= insts[i].out_regs;
39+
self.live_regs[i] = previous_ranges + insts[i].src_regs;
40+
if insts[i].cond != Cond::AL {
41+
self.live_regs[i] += insts[i].out_regs;
42+
}
43+
}
44+
}
45+
}
46+
47+
pub struct BasicBlockDebug<'a> {
48+
basic_block: &'a BasicBlock,
49+
insts: &'a [InstInfo],
50+
thumb: bool,
51+
}
52+
53+
impl Debug for BasicBlockDebug<'_> {
54+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
55+
let pc_shift = if self.thumb { 1 } else { 2 };
56+
for (i, inst) in self.insts.iter().enumerate() {
57+
let pc = self.basic_block.start_pc + ((i as u32) << pc_shift);
58+
writeln!(f, "{pc:x}: live regs: {:?}", self.basic_block.live_regs[i])?;
59+
writeln!(f, "{inst:?}")?;
60+
}
61+
write!(f, "outputs: {:?}", self.basic_block.live_regs.last().unwrap())
62+
}
63+
}

src/jit/analyzer/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pub mod asm_analyzer;
2+
mod basic_block;

src/jit/assembler/arm/alu_assembler.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ impl AluImm {
3636
#[inline]
3737
pub fn add(op0: Reg, op1: Reg, op2: u8, shift: u8, cond: Cond) -> u32 {
3838
let op = Self::generic(0x4, op0, op1, op2, shift, false, cond);
39-
debug_assert_eq!(lookup_opcode(op).0, Op::AddImm);
39+
// debug_assert_eq!(lookup_opcode(op).0, Op::AddImm);
4040
op
4141
}
4242

@@ -48,7 +48,7 @@ impl AluImm {
4848
#[inline]
4949
pub fn adds(op0: Reg, op1: Reg, op2: u8, shift: u8, cond: Cond) -> u32 {
5050
let op = Self::generic(0x4, op0, op1, op2, shift, true, cond);
51-
debug_assert_eq!(lookup_opcode(op).0, Op::AddsImm);
51+
// debug_assert_eq!(lookup_opcode(op).0, Op::AddsImm);
5252
op
5353
}
5454

@@ -74,7 +74,7 @@ impl AluImm {
7474
#[inline]
7575
pub fn cmp(op1: Reg, op2: u8, shift: u8, cond: Cond) -> u32 {
7676
let op = Self::generic(0xA, Reg::R0, op1, op2, shift, true, cond);
77-
debug_assert_eq!(lookup_opcode(op).0, Op::CmpImm);
77+
// debug_assert_eq!(lookup_opcode(op).0, Op::CmpImm);
7878
op
7979
}
8080

@@ -96,7 +96,7 @@ impl AluImm {
9696
#[inline]
9797
pub fn sub(op0: Reg, op1: Reg, op2: u8, shift: u8, cond: Cond) -> u32 {
9898
let op = Self::generic(0x2, op0, op1, op2, shift, false, cond);
99-
debug_assert_eq!(lookup_opcode(op).0, Op::SubImm);
99+
// debug_assert_eq!(lookup_opcode(op).0, Op::SubImm);
100100
op
101101
}
102102

@@ -108,7 +108,7 @@ impl AluImm {
108108
#[inline]
109109
pub fn subs(op0: Reg, op1: Reg, op2: u8, shift: u8, cond: Cond) -> u32 {
110110
let op = Self::generic(0x2, op0, op1, op2, shift, true, cond);
111-
debug_assert_eq!(lookup_opcode(op).0, Op::SubsImm);
111+
// debug_assert_eq!(lookup_opcode(op).0, Op::SubsImm);
112112
op
113113
}
114114

@@ -120,7 +120,7 @@ impl AluImm {
120120
#[inline]
121121
pub fn rsbs(op0: Reg, op1: Reg, op2: u8, shift: u8, cond: Cond) -> u32 {
122122
let op = Self::generic(0x3, op0, op1, op2, shift, true, cond);
123-
debug_assert_eq!(lookup_opcode(op).0, Op::RsbsImm);
123+
// debug_assert_eq!(lookup_opcode(op).0, Op::RsbsImm);
124124
op
125125
}
126126

@@ -132,7 +132,7 @@ impl AluImm {
132132
#[inline]
133133
pub fn mov(op0: Reg, op2: u8, ror: u8, cond: Cond) -> u32 {
134134
let op = Self::generic(0xD, op0, Reg::R0, op2, ror, false, cond);
135-
debug_assert_eq!(lookup_opcode(op).0, Op::MovImm);
135+
// debug_assert_eq!(lookup_opcode(op).0, Op::MovImm);
136136
op
137137
}
138138

@@ -144,7 +144,7 @@ impl AluImm {
144144
#[inline]
145145
pub fn movs(op0: Reg, op2: u8, ror: u8, cond: Cond) -> u32 {
146146
let op = Self::generic(0xD, op0, Reg::R0, op2, ror, true, cond);
147-
debug_assert_eq!(lookup_opcode(op).0, Op::MovsImm);
147+
// debug_assert_eq!(lookup_opcode(op).0, Op::MovsImm);
148148
op
149149
}
150150

src/jit/assembler/arm/mod.rs

-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use bilge::prelude::*;
33
pub mod alu_assembler;
44
pub mod branch_assembler;
55
pub mod transfer_assembler;
6-
pub mod vixl;
76

87
#[bitsize(32)]
98
#[derive(FromBits)]

0 commit comments

Comments
 (0)