miden_processor/fast/stack_ops.rs
1use miden_core::{WORD_SIZE, ZERO};
2
3use super::FastProcessor;
4use crate::{ErrorContext, ExecutionError};
5
6impl FastProcessor {
7 /// Analogous to `Process::op_pad`.
8 pub fn op_pad(&mut self) -> Result<(), ExecutionError> {
9 self.increment_stack_size()?;
10 self.stack_write(0, ZERO);
11 Ok(())
12 }
13
14 /// Analogous to `Process::op_swap`.
15 pub fn op_swap(&mut self) {
16 self.stack_swap(0, 1);
17 }
18
19 /// Analogous to `Process::op_swapdw`.
20 pub fn op_swap_double_word(&mut self) {
21 self.stack_swap(0, 8);
22 self.stack_swap(1, 9);
23 self.stack_swap(2, 10);
24 self.stack_swap(3, 11);
25 self.stack_swap(4, 12);
26 self.stack_swap(5, 13);
27 self.stack_swap(6, 14);
28 self.stack_swap(7, 15);
29 }
30
31 /// Rotates the top `n` elements of the stack to the left by 1.
32 ///
33 /// For example, if the stack is [a, b, c, d], with `d` at the top, then `rotate_left(3)` will
34 /// result in the top 3 elements being rotated left: [a, c, d, b].
35 ///
36 /// This operation is useful for implementing the `movup` instructions.
37 ///
38 /// The stack size doesn't change.
39 ///
40 /// Note: This method doesn't use the `stack_get()` and `stack_write()` methods because it is
41 /// more efficient to directly manipulate the stack array (~10% performance difference).
42 #[inline(always)]
43 pub fn rotate_left(&mut self, n: usize) {
44 let rotation_bot_index = self.stack_top_idx - n;
45 let new_stack_top_element = self.stack[rotation_bot_index];
46
47 // shift the top n elements down by 1, starting from the bottom of the rotation.
48 for i in 0..n - 1 {
49 self.stack[rotation_bot_index + i] = self.stack[rotation_bot_index + i + 1];
50 }
51
52 // Set the top element (which comes from the bottom of the rotation).
53 self.stack_write(0, new_stack_top_element);
54 }
55
56 /// Rotates the top `n` elements of the stack to the right by 1.
57 ///
58 /// Analogous to `rotate_left`, but in the opposite direction.
59 ///
60 /// Note: This method doesn't use the `stack_get()` and `stack_write()` methods because it is
61 /// more efficient to directly manipulate the stack array (~10% performance difference).
62 #[inline(always)]
63 pub fn rotate_right(&mut self, n: usize) {
64 let rotation_bot_index = self.stack_top_idx - n;
65 let new_stack_bot_element = self.stack[self.stack_top_idx - 1];
66
67 // shift the top n elements up by 1, starting from the top of the rotation.
68 for i in 1..n {
69 self.stack[self.stack_top_idx - i] = self.stack[self.stack_top_idx - i - 1];
70 }
71
72 // Set the bot element (which comes from the top of the rotation).
73 self.stack[rotation_bot_index] = new_stack_bot_element;
74 }
75
76 /// Duplicates the n'th element from the top of the stack to the top of the stack.
77 ///
78 /// The size of the stack is incremented by 1.
79 #[inline(always)]
80 pub fn dup_nth(&mut self, n: usize) -> Result<(), ExecutionError> {
81 let to_dup = self.stack_get(n);
82 self.increment_stack_size()?;
83 self.stack_write(0, to_dup);
84
85 Ok(())
86 }
87
88 /// Swaps the nth word from the top of the stack with the top word of the stack.
89 ///
90 /// Valid values of `n` are 1, 2, and 3.
91 pub fn swapw_nth(&mut self, n: usize) {
92 // For example, for n=3, the stack words and variables look like:
93 // 3 2 1 0
94 // | ... | ... | ... | ... |
95 // ^ ^
96 // nth_word top_word
97 let (rest_of_stack, top_word) = self.stack.split_at_mut(self.stack_top_idx - WORD_SIZE);
98 let (_, nth_word) = rest_of_stack.split_at_mut(rest_of_stack.len() - n * WORD_SIZE);
99
100 nth_word[0..WORD_SIZE].swap_with_slice(&mut top_word[0..WORD_SIZE]);
101 }
102
103 /// Analogous to `Process::op_cswap`.
104 pub fn op_cswap(&mut self, err_ctx: &impl ErrorContext) -> Result<(), ExecutionError> {
105 let condition = self.stack_get(0);
106 self.decrement_stack_size();
107
108 match condition.as_int() {
109 0 => {
110 // do nothing, a and b are already in the right place
111 },
112 1 => {
113 self.stack_swap(0, 1);
114 },
115 _ => {
116 return Err(ExecutionError::not_binary_value_op(condition, err_ctx));
117 },
118 }
119
120 Ok(())
121 }
122
123 /// Analogous to `Process::op_cswapw`.
124 pub fn op_cswapw(&mut self, err_ctx: &impl ErrorContext) -> Result<(), ExecutionError> {
125 let condition = self.stack_get(0);
126 self.decrement_stack_size();
127
128 match condition.as_int() {
129 0 => {
130 // do nothing, the words are already in the right place
131 },
132 1 => {
133 self.stack_swap(0, 4);
134 self.stack_swap(1, 5);
135 self.stack_swap(2, 6);
136 self.stack_swap(3, 7);
137 },
138 _ => {
139 return Err(ExecutionError::not_binary_value_op(condition, err_ctx));
140 },
141 }
142
143 Ok(())
144 }
145}