-
Notifications
You must be signed in to change notification settings - Fork 220
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(brillig): Add a register abstraction/optimization (#1737)
* chore: brillig register abstraction * chore: small refactor * fix: latest_register starting value * fix: comments * chore: remove unused method * fix: reintroduce a safety register alloc check
- Loading branch information
Showing
5 changed files
with
124 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
59 changes: 59 additions & 0 deletions
59
crates/noirc_evaluator/src/brillig/brillig_ir/registers.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
use acvm::acir::brillig_vm::RegisterIndex; | ||
|
||
use super::ReservedRegisters; | ||
|
||
/// Every brillig stack frame/call context has its own view of register space. | ||
/// This is maintained by copying these registers to the stack during calls and reading them back. | ||
/// | ||
/// Each has a stack base pointer from which all stack allocations can be offset. | ||
pub(crate) struct BrilligRegistersContext { | ||
/// A free-list of registers that have been deallocated and can be used again. | ||
/// TODO(AD): currently, register deallocation is only done with immediate values. | ||
/// TODO(AD): See https://github.com/noir-lang/noir/issues/1720 | ||
deallocated_registers: Vec<RegisterIndex>, | ||
/// A usize indicating the next un-used register. | ||
next_free_register_index: usize, | ||
} | ||
|
||
impl BrilligRegistersContext { | ||
/// Initial register allocation | ||
pub(crate) fn new() -> BrilligRegistersContext { | ||
BrilligRegistersContext { | ||
deallocated_registers: Vec::new(), | ||
next_free_register_index: ReservedRegisters::len(), | ||
} | ||
} | ||
|
||
/// Ensures a register is allocated. | ||
pub(crate) fn ensure_register_is_allocated(&mut self, register: RegisterIndex) { | ||
let index = register.to_usize(); | ||
if index < self.next_free_register_index { | ||
// If it could be allocated, check if it's in the deallocated list and remove it from there | ||
self.deallocated_registers.retain(|&r| r != register); | ||
} else { | ||
// If it couldn't yet be, expand the register space. | ||
self.next_free_register_index = index + 1; | ||
} | ||
} | ||
|
||
/// Creates a new register. | ||
pub(crate) fn allocate_register(&mut self) -> RegisterIndex { | ||
// If we have a register in our free list of deallocated registers, | ||
// consume it first. This prioritizes reuse. | ||
if let Some(register) = self.deallocated_registers.pop() { | ||
return register; | ||
} | ||
// Otherwise, move to our latest register. | ||
let register = RegisterIndex::from(self.next_free_register_index); | ||
self.next_free_register_index += 1; | ||
register | ||
} | ||
|
||
/// Push a register to the deallocation list, ready for reuse. | ||
/// TODO(AD): currently, register deallocation is only done with immediate values. | ||
/// TODO(AD): See https://github.com/noir-lang/noir/issues/1720 | ||
pub(crate) fn deallocate_register(&mut self, register_index: RegisterIndex) { | ||
assert!(!self.deallocated_registers.contains(®ister_index)); | ||
self.deallocated_registers.push(register_index); | ||
} | ||
} |