Skip to content

Commit

Permalink
Imply release on assignment
Browse files Browse the repository at this point in the history
  • Loading branch information
voltrevo committed Jun 30, 2023
1 parent 996ffc2 commit 52f4233
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 12 deletions.
10 changes: 9 additions & 1 deletion valuescript_compiler/src/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,13 +275,21 @@ impl Instruction {
| Call(left, right, dst)
| Bind(left, right, dst)
| Sub(left, right, dst)
| SubMov(left, right, dst)
| New(left, right, dst) => {
visit(RegisterVisitMut::write(dst));
right.visit_registers_mut_rev(visit);
left.visit_registers_mut_rev(visit);
}

SubMov(key, value, obj) => {
// `obj` is 'read' here in the sense that it needs to be intact for this to work, it's not
// just newly constructed from the inputs.
visit(RegisterVisitMut::read_and_write(obj));

value.visit_registers_mut_rev(visit);
key.visit_registers_mut_rev(visit);
}

Apply(fn_, this, args, dst) => {
visit(RegisterVisitMut::write(dst));
args.visit_registers_mut_rev(visit);
Expand Down
56 changes: 45 additions & 11 deletions valuescript_compiler/src/optimization/simplify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,19 +292,43 @@ impl FnState {
}

fn handle_releases(&self, body: &mut Vec<FnLine>, i: usize) {
let released_reg = match &body[i] {
FnLine::Instruction(_instr) => {
// TODO
return;
let mut calls = Vec::<(Register, usize)>::new();

match &mut body[i] {
FnLine::Instruction(instr) => {
let mut skips_needed = 0;

instr.visit_registers_mut_rev(&mut |rvm| {
skips_needed += 1;

if rvm.write && !rvm.read {
calls.push((rvm.register.clone(), skips_needed));
}
});
}
FnLine::Release(released_reg) => {
calls.push((released_reg.clone(), 0));
}
FnLine::Release(released_reg) => released_reg.clone(),
FnLine::Label(_) | FnLine::Empty | FnLine::Comment(_) => return,
FnLine::Label(_) | FnLine::Empty | FnLine::Comment(_) => {}
};

for (released_reg, skips) in calls {
self.handle_releases_impl(body, i, released_reg, skips);
}
}

fn handle_releases_impl(
&self,
body: &mut Vec<FnLine>,
i: usize,
released_reg: Register,
skips_needed: usize,
) {
// Search backwards to find where this register was last written. If a jump instruction occurs,
// then we don't know for sure whether the release point will be hit, and we can't apply our
// analysis.
let mut j = i;
let mut j = i + 1;
let mut skips = 0;
while j > 0 {
j -= 1;

Expand All @@ -320,6 +344,11 @@ impl FnState {
let mut write_found = false;

instr.visit_registers_mut_rev(&mut |rvm| {
if skips < skips_needed {
skips += 1;
return;
}

if rvm.write && rvm.register.name == released_reg.name {
write_found = true;
}
Expand All @@ -333,7 +362,8 @@ impl FnState {
// Now that we've established that the last write always hits the release point, find the last
// read and use .take() instead of copying. Also, if this .take() never occurs, it means the
// value was never used, and comment out the instruction that writes the value, if possible.
let mut j = i;
let mut j = i + 1;
let mut skip_i = 0;
let mut taken = false;
while j > 0 {
j -= 1;
Expand All @@ -347,6 +377,11 @@ impl FnState {

if !taken {
instr.visit_registers_mut_rev(&mut |rvm| {
if skip_i < skips_needed {
skip_i += 1;
return;
}

if rvm.register.name != released_reg.name {
return;
}
Expand Down Expand Up @@ -386,9 +421,8 @@ fn simplify_fn(mut state: FnState, fn_: &mut Function) {

fn is_jmp_instr(instr: &Instruction) -> bool {
match instr {
Instruction::Jmp(..) | Instruction::JmpIf(..) => true,
Instruction::End
| Instruction::Mov(..)
Instruction::End | Instruction::Jmp(..) | Instruction::JmpIf(..) => true,
Instruction::Mov(..)
| Instruction::OpInc(..)
| Instruction::OpDec(..)
| Instruction::OpPlus(..)
Expand Down

0 comments on commit 52f4233

Please sign in to comment.