Skip to content

Commit c0ab463

Browse files
authored
Merge pull request #135 from TritonVM/raw_code_inline
fix(RawCode): Only inline inlineable code
2 parents 1c556be + f2d40a9 commit c0ab463

File tree

1 file changed

+61
-11
lines changed

1 file changed

+61
-11
lines changed

tasm-lib/src/list/higher_order/inner_function.rs

Lines changed: 61 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -77,20 +77,43 @@ impl RawCode {
7777
}
7878

7979
/// Returns `Some(code)` iff the raw code is a function that can be inlined
80+
///
81+
/// Type hints and breakpoints are stripped.
8082
pub fn inlined_body(&self) -> Option<Vec<LabelledInstruction>> {
81-
// If the RawCode contains a recurse, it cannot be inlined
82-
if self
83+
let is_label = |x: &_| matches!(x, LabelledInstruction::Label(_));
84+
let is_instruction = |x: &_| matches!(x, LabelledInstruction::Instruction(_));
85+
let is_recursive = |x: &_| {
86+
matches!(
87+
x,
88+
LabelledInstruction::Instruction(AnInstruction::Recurse)
89+
| LabelledInstruction::Instruction(AnInstruction::RecurseOrReturn)
90+
)
91+
};
92+
93+
if self.function.iter().any(is_recursive) {
94+
// recursion needs to be wrapped in a function
95+
return None;
96+
}
97+
98+
let mut labels_and_instructions = self
8399
.function
84100
.iter()
85-
.any(|x| matches!(x, LabelledInstruction::Instruction(AnInstruction::Recurse)))
86-
{
87-
None
88-
} else if self.function.len() == 2 {
89-
Some(triton_asm!())
90-
} else {
91-
// Remove label and `return`
92-
Some(self.function[1..=self.function.len() - 2].to_vec())
93-
}
101+
.filter(|i| is_label(i) || is_instruction(i));
102+
103+
let Some(first_thing) = labels_and_instructions.next() else {
104+
return Some(triton_asm!());
105+
};
106+
let LabelledInstruction::Label(_) = first_thing else {
107+
panic!("Raw Code must start with a label.")
108+
};
109+
110+
let Some(LabelledInstruction::Instruction(AnInstruction::Return)) =
111+
labels_and_instructions.next_back()
112+
else {
113+
panic!("Raw Code is probably buggy: too short, or doesn't end with `return`.");
114+
};
115+
116+
Some(labels_and_instructions.cloned().collect())
94117
}
95118
}
96119

@@ -219,3 +242,30 @@ impl InnerFunction {
219242
};
220243
}
221244
}
245+
246+
#[cfg(test)]
247+
mod tests {
248+
use super::*;
249+
250+
#[test]
251+
fn breakpoint_does_not_influence_raw_code_inlining() {
252+
let raw_code = RawCode {
253+
function: triton_asm! { my_label: return break },
254+
input_type: DataType::VoidPointer,
255+
output_type: DataType::VoidPointer,
256+
};
257+
let inlined_code = raw_code.inlined_body().unwrap();
258+
assert_eq!(triton_asm!(), inlined_code);
259+
}
260+
261+
#[test]
262+
fn type_hints_do_not_influence_raw_code_inlining() {
263+
let raw_code = RawCode {
264+
function: triton_asm! { my_label: hint a = stack[0] hint b = stack[1] return },
265+
input_type: DataType::VoidPointer,
266+
output_type: DataType::VoidPointer,
267+
};
268+
let inlined_code = raw_code.inlined_body().unwrap();
269+
assert_eq!(triton_asm!(), inlined_code);
270+
}
271+
}

0 commit comments

Comments
 (0)