Skip to content

Commit

Permalink
Improve performance of register assignment
Browse files Browse the repository at this point in the history
  • Loading branch information
benruijl committed Aug 12, 2024
1 parent 0cd4098 commit ad83512
Showing 1 changed file with 68 additions and 81 deletions.
149 changes: 68 additions & 81 deletions src/evaluate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1340,93 +1340,82 @@ impl<T: std::fmt::Display> ExpressionEvaluator<T> {
})
.collect();

for i in 0..40 {
for (j, last_use) in reg_last_use.iter().enumerate() {
if *last_use - j == i {
if *last_use == self.instructions.len() {
continue;
}
// sort the list of instructions based on the distance
let mut reg_list = reg_last_use.iter().enumerate().collect::<Vec<_>>();
reg_list.sort_by_key(|x| (*x.1 - x.0, x.0));

let old_reg =
if let RegInstr::Add(r, _, _) | RegInstr::Mul(r, _, _) = &new_instr[j] {
if let MemOrReg::Mem(r) = r {
*r
} else {
continue;
}
} else {
continue;
};
'next: for (j, last_use) in reg_list {
if *last_use == self.instructions.len() {
continue;
}

let old_reg = if let RegInstr::Add(r, _, _) | RegInstr::Mul(r, _, _) = &new_instr[j] {
if let MemOrReg::Mem(r) = r {
*r
} else {
continue;
}
} else {
continue;
};

// find free registers in the range
// start at j+1 as we can recycle registers that are last used in iteration j
let mut free_regs = u16::MAX;
// find free registers in the range
// start at j+1 as we can recycle registers that are last used in iteration j
let mut free_regs = u16::MAX & !(1 << 15); // leave xmmm15 open

for k in &new_instr[j + 1..=*last_use] {
match k {
RegInstr::Add(_, f, _) | RegInstr::Mul(_, f, _) => {
free_regs &= f;
}
_ => {
free_regs = 0; // the current instruction is not allowed to be used outside of ASM blocks
}
}
for k in &new_instr[j + 1..=*last_use] {
match k {
RegInstr::Add(_, f, _) | RegInstr::Mul(_, f, _) => {
free_regs &= f;
}

if free_regs == 0 {
continue;
_ => {
free_regs = 0; // the current instruction is not allowed to be used outside of ASM blocks
}
}

for k in 0..15 {
if free_regs & (1 << k) != 0 {
if let RegInstr::Add(r, _, _) | RegInstr::Mul(r, _, _) =
&mut new_instr[j]
{
*r = MemOrReg::Reg(k);
}
if free_regs == 0 {
continue 'next;
}
}

for l in &mut new_instr[j + 1..=*last_use] {
match l {
RegInstr::Add(_, f, a) | RegInstr::Mul(_, f, a) => {
*f &= !(1 << k); // FIXME: do not set on last use?
for x in a {
if *x == MemOrReg::Mem(old_reg) {
*x = MemOrReg::Reg(k);
}
}
}
RegInstr::Pow(_, a, _) => {
if *a == old_reg {
panic!("use outside of ASM block");
}
}
RegInstr::Powf(_, a, b) => {
if *a == old_reg {
panic!("use outside of ASM block");
}
if *b == old_reg {
panic!("use outside of ASM block");
}
}
RegInstr::BuiltinFun(_, _, a) => {
if *a == old_reg {
panic!("use outside of ASM block");
}
}
if let Some(k) = (0..16).position(|k| free_regs & (1 << k) != 0) {
if let RegInstr::Add(r, _, _) | RegInstr::Mul(r, _, _) = &mut new_instr[j] {
*r = MemOrReg::Reg(k);
}

for l in &mut new_instr[j + 1..=*last_use] {
match l {
RegInstr::Add(_, f, a) | RegInstr::Mul(_, f, a) => {
*f &= !(1 << k); // FIXME: do not set on last use?
for x in a {
if *x == MemOrReg::Mem(old_reg) {
*x = MemOrReg::Reg(k);
}
}

break;
}
RegInstr::Pow(_, a, _) => {
if *a == old_reg {
panic!("use outside of ASM block");
}
}
RegInstr::Powf(_, a, b) => {
if *a == old_reg {
panic!("use outside of ASM block");
}
if *b == old_reg {
panic!("use outside of ASM block");
}
}
RegInstr::BuiltinFun(_, _, a) => {
if *a == old_reg {
panic!("use outside of ASM block");
}
}
}
}
}
}

//for (i, x) in new_instr.iter().enumerate() {
// println!("{} {:?}", i, x);
//}

let mut in_asm_block = false;
for ins in &new_instr {
match ins {
Expand Down Expand Up @@ -1515,14 +1504,8 @@ impl<T: std::fmt::Display> ExpressionEvaluator<T> {
}
}
MemOrReg::Mem(out_mem) => {
// we need to find a free temporary register
if *free == 0 {
panic!("no free registers");
// we can move the value of xmm0 into the memory location of the output register
// and then swap later
}

if let Some(out_reg) = (0..15).position(|k| free & (1 << k) != 0) {
// TODO: we would like a last-use check of the free here. Now we need to move
if let Some(out_reg) = (0..16).position(|k| free & (1 << k) != 0) {
if let Some(MemOrReg::Reg(j)) =
a.iter().find(|x| matches!(x, MemOrReg::Reg(_)))
{
Expand Down Expand Up @@ -1577,6 +1560,10 @@ impl<T: std::fmt::Display> ExpressionEvaluator<T> {
format_addr!(*out_mem),
out_reg
);
} else {
unreachable!("No free registers");
// move the value of xmm0 into the memory location of the output register
// and then swap later?
}
}
}
Expand Down Expand Up @@ -1642,7 +1629,7 @@ impl<T: std::fmt::Display> ExpressionEvaluator<T> {

let mut regcount = 0;
*out += "\t__asm__(\n";
for (i, r) in &mut self.result_indices.iter().enumerate() {
for (i, r) in self.result_indices.iter().enumerate() {
if *r < self.param_count {
*out += &format!(
"\t\t\"movsd xmm{}, QWORD PTR[%3+{}]\\n\\t\"\n",
Expand Down

0 comments on commit ad83512

Please sign in to comment.