Skip to content

Commit 2ed0334

Browse files
authored
compiler: reorg intermediate representation (#66)
* compiler: reorg intermediate representation * cleanup
1 parent a1690c4 commit 2ed0334

File tree

11 files changed

+243
-180
lines changed

11 files changed

+243
-180
lines changed

crates/lean_compiler/src/a_simplify_lang.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{
22
Counter, F,
3-
intermediate_bytecode::HighLevelOperation,
3+
ir::HighLevelOperation,
44
lang::{
55
Boolean, ConstExpression, ConstMallocLabel, Expression, Function, Line, Program,
66
SimpleExpr, Var,

crates/lean_compiler/src/b_compile_intermediate.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{F, a_simplify_lang::*, intermediate_bytecode::*, lang::*, precompiles::*};
1+
use crate::{F, a_simplify_lang::*, ir::*, lang::*, precompiles::*};
22
use lean_vm::*;
33
use p3_field::Field;
44
use std::{

crates/lean_compiler/src/c_compile_final.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{F, PUBLIC_INPUT_START, ZERO_VEC_PTR, intermediate_bytecode::*, lang::*};
1+
use crate::{F, PUBLIC_INPUT_START, ZERO_VEC_PTR, ir::*, lang::*};
22
use lean_vm::*;
33
use p3_field::{PrimeCharacteristicRing, PrimeField32};
44
use std::collections::BTreeMap;
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
use super::instruction::IntermediateInstruction;
2+
use lean_vm::Label;
3+
use std::collections::BTreeMap;
4+
use std::fmt::{Display, Formatter};
5+
6+
/// Container for the complete intermediate representation of a program.
7+
///
8+
/// This structure holds all the compiled intermediate bytecode along with
9+
/// metadata needed for execution and analysis.
10+
#[derive(Debug, Clone)]
11+
pub struct IntermediateBytecode {
12+
/// Main bytecode organized by function labels.
13+
///
14+
/// Each label corresponds to a function entry point.
15+
pub bytecode: BTreeMap<Label, Vec<IntermediateInstruction>>,
16+
17+
/// Match statement bytecode blocks.
18+
///
19+
/// Each match statement produces multiple case blocks.
20+
pub match_blocks: Vec<Vec<Vec<IntermediateInstruction>>>,
21+
22+
/// Memory requirements for each function.
23+
///
24+
/// Maps function names to their stack frame size.
25+
pub memory_size_per_function: BTreeMap<String, usize>,
26+
}
27+
28+
impl Display for IntermediateBytecode {
29+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
30+
for (label, instructions) in &self.bytecode {
31+
writeln!(f, "\n{label}:")?;
32+
for instruction in instructions {
33+
writeln!(f, " {instruction}")?;
34+
}
35+
}
36+
for (i, match_blocks) in self.match_blocks.iter().enumerate() {
37+
writeln!(f, "\nMatch {i}:")?;
38+
for (j, case) in match_blocks.iter().enumerate() {
39+
writeln!(f, " Case {j}:")?;
40+
for instruction in case {
41+
writeln!(f, " {instruction}")?;
42+
}
43+
}
44+
}
45+
writeln!(f, "\nMemory size per function:")?;
46+
for (function_name, size) in &self.memory_size_per_function {
47+
writeln!(f, "{function_name}: {size}")?;
48+
}
49+
Ok(())
50+
}
51+
}
Lines changed: 39 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,10 @@
1-
use std::collections::BTreeMap;
2-
use std::fmt::Display;
3-
use std::fmt::Formatter;
4-
5-
use p3_field::PrimeCharacteristicRing;
6-
use p3_field::PrimeField64;
7-
use utils::ToUsize;
8-
9-
use crate::{F, lang::ConstExpression};
10-
use lean_vm::*;
11-
12-
#[derive(Debug, Clone)]
13-
pub struct IntermediateBytecode {
14-
pub bytecode: BTreeMap<Label, Vec<IntermediateInstruction>>,
15-
pub match_blocks: Vec<Vec<Vec<IntermediateInstruction>>>,
16-
pub memory_size_per_function: BTreeMap<String, usize>,
17-
}
18-
19-
#[derive(Debug, Clone, PartialEq, Eq)]
20-
pub enum IntermediateValue {
21-
Constant(ConstExpression),
22-
Fp,
23-
MemoryAfterFp { offset: ConstExpression }, // m[fp + offset]
24-
}
25-
26-
impl From<ConstExpression> for IntermediateValue {
27-
fn from(value: ConstExpression) -> Self {
28-
Self::Constant(value)
29-
}
30-
}
31-
impl TryFrom<HighLevelOperation> for Operation {
32-
type Error = String;
33-
34-
fn try_from(value: HighLevelOperation) -> Result<Self, Self::Error> {
35-
match value {
36-
HighLevelOperation::Add => Ok(Self::Add),
37-
HighLevelOperation::Mul => Ok(Self::Mul),
38-
_ => Err(format!("Cannot convert {value:?} to +/x")),
39-
}
40-
}
41-
}
42-
43-
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
44-
pub enum IntermediaryMemOrFpOrConstant {
45-
MemoryAfterFp { offset: ConstExpression }, // m[fp + offset]
46-
Fp,
47-
Constant(ConstExpression),
48-
}
49-
50-
impl IntermediateValue {
51-
pub const fn label(label: Label) -> Self {
52-
Self::Constant(ConstExpression::label(label))
53-
}
54-
55-
pub const fn is_constant(&self) -> bool {
56-
matches!(self, Self::Constant(_))
57-
}
58-
}
59-
60-
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
61-
pub enum HighLevelOperation {
62-
Add,
63-
Mul,
64-
Sub,
65-
Div, // in the end everything compiles to either Add or Mul
66-
Exp, // Exponentiation, only for const expressions
67-
Mod, // Modulo, only for const expressions
68-
}
69-
70-
impl HighLevelOperation {
71-
pub fn eval(&self, a: F, b: F) -> F {
72-
match self {
73-
Self::Add => a + b,
74-
Self::Mul => a * b,
75-
Self::Sub => a - b,
76-
Self::Div => a / b,
77-
Self::Exp => a.exp_u64(b.as_canonical_u64()),
78-
Self::Mod => F::from_usize(a.to_usize() % b.to_usize()),
79-
}
80-
}
81-
}
1+
use super::operation::HighLevelOperation;
2+
use super::value::{IntermediaryMemOrFpOrConstant, IntermediateValue};
3+
use crate::lang::ConstExpression;
4+
use lean_vm::{Operation, SourceLineNumber};
5+
use std::fmt::{Display, Formatter};
826

7+
/// Core instruction type for the intermediate representation.
838
#[derive(Debug, Clone)]
849
pub enum IntermediateInstruction {
8510
Computation {
@@ -200,64 +125,9 @@ impl IntermediateInstruction {
200125
}
201126
}
202127

203-
impl Display for IntermediateValue {
204-
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
205-
match self {
206-
Self::Constant(value) => write!(f, "{value}"),
207-
Self::Fp => write!(f, "fp"),
208-
Self::MemoryAfterFp { offset } => {
209-
write!(f, "m[fp + {offset}]")
210-
}
211-
}
212-
}
213-
}
214-
215-
impl Display for IntermediaryMemOrFpOrConstant {
216-
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
217-
match self {
218-
Self::MemoryAfterFp { offset } => write!(f, "m[fp + {offset}]"),
219-
Self::Fp => write!(f, "fp"),
220-
Self::Constant(c) => write!(f, "{c}"),
221-
}
222-
}
223-
}
224-
225128
impl Display for IntermediateInstruction {
226129
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
227130
match self {
228-
Self::Deref {
229-
shift_0,
230-
shift_1,
231-
res,
232-
} => write!(f, "{res} = m[m[fp + {shift_0}] + {shift_1}]"),
233-
Self::DotProduct {
234-
arg0,
235-
arg1,
236-
res,
237-
size,
238-
} => write!(f, "dot_product({arg0}, {arg1}, {res}, {size})"),
239-
Self::MultilinearEval {
240-
coeffs,
241-
point,
242-
res,
243-
n_vars,
244-
} => write!(f, "multilinear_eval({coeffs}, {point}, {res}, {n_vars})"),
245-
Self::DecomposeBits {
246-
res_offset,
247-
to_decompose,
248-
} => {
249-
write!(f, "m[fp + {res_offset}..] = decompose_bits(")?;
250-
for (i, expr) in to_decompose.iter().enumerate() {
251-
if i > 0 {
252-
write!(f, ", ")?;
253-
}
254-
write!(f, "{expr}")?;
255-
}
256-
write!(f, ")")
257-
}
258-
Self::CounterHint { res_offset } => {
259-
write!(f, "m[fp + {res_offset}] = counter_hint()")
260-
}
261131
Self::Computation {
262132
operation,
263133
arg_a,
@@ -266,6 +136,11 @@ impl Display for IntermediateInstruction {
266136
} => {
267137
write!(f, "{res} = {arg_a} {operation} {arg_c}")
268138
}
139+
Self::Deref {
140+
shift_0,
141+
shift_1,
142+
res,
143+
} => write!(f, "{res} = m[m[fp + {shift_0}] + {shift_1}]"),
269144
Self::Panic => write!(f, "panic"),
270145
Self::Jump { dest, updated_fp } => {
271146
if let Some(fp) = updated_fp {
@@ -291,6 +166,18 @@ impl Display for IntermediateInstruction {
291166
Self::Poseidon2_24 { arg_a, arg_b, res } => {
292167
write!(f, "{res} = poseidon2_24({arg_a}, {arg_b})")
293168
}
169+
Self::DotProduct {
170+
arg0,
171+
arg1,
172+
res,
173+
size,
174+
} => write!(f, "dot_product({arg0}, {arg1}, {res}, {size})"),
175+
Self::MultilinearEval {
176+
coeffs,
177+
point,
178+
res,
179+
n_vars,
180+
} => write!(f, "multilinear_eval({coeffs}, {point}, {res}, {n_vars})"),
294181
Self::Inverse { arg, res_offset } => {
295182
write!(f, "m[fp + {res_offset}] = inverse({arg})")
296183
}
@@ -309,6 +196,22 @@ impl Display for IntermediateInstruction {
309196
write!(f, "m[fp + {offset}] = request_memory({size})")
310197
}
311198
}
199+
Self::DecomposeBits {
200+
res_offset,
201+
to_decompose,
202+
} => {
203+
write!(f, "m[fp + {res_offset}..] = decompose_bits(")?;
204+
for (i, expr) in to_decompose.iter().enumerate() {
205+
if i > 0 {
206+
write!(f, ", ")?;
207+
}
208+
write!(f, "{expr}")?;
209+
}
210+
write!(f, ")")
211+
}
212+
Self::CounterHint { res_offset } => {
213+
write!(f, "m[fp + {res_offset}] = counter_hint()")
214+
}
312215
Self::Print { line_info, content } => {
313216
write!(f, "print {line_info}: ")?;
314217
for (i, c) in content.iter().enumerate() {
@@ -323,41 +226,3 @@ impl Display for IntermediateInstruction {
323226
}
324227
}
325228
}
326-
327-
impl Display for HighLevelOperation {
328-
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
329-
match self {
330-
Self::Add => write!(f, "+"),
331-
Self::Mul => write!(f, "*"),
332-
Self::Sub => write!(f, "-"),
333-
Self::Div => write!(f, "/"),
334-
Self::Exp => write!(f, "**"),
335-
Self::Mod => write!(f, "%"),
336-
}
337-
}
338-
}
339-
340-
impl Display for IntermediateBytecode {
341-
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
342-
for (label, instructions) in &self.bytecode {
343-
writeln!(f, "\n{label}:")?;
344-
for instruction in instructions {
345-
writeln!(f, " {instruction}")?;
346-
}
347-
}
348-
for (i, match_blocks) in self.match_blocks.iter().enumerate() {
349-
writeln!(f, "\nMatch {i}:")?;
350-
for (j, case) in match_blocks.iter().enumerate() {
351-
writeln!(f, " Case {j}:")?;
352-
for instruction in case {
353-
writeln!(f, " {instruction}")?;
354-
}
355-
}
356-
}
357-
writeln!(f, "\nMemory size per function:")?;
358-
for (function_name, size) in &self.memory_size_per_function {
359-
writeln!(f, "{function_name}: {size}")?;
360-
}
361-
Ok(())
362-
}
363-
}

crates/lean_compiler/src/ir/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//! Intermediate Representation (IR) for the Lean compiler.
2+
3+
pub mod bytecode;
4+
pub mod instruction;
5+
pub mod operation;
6+
pub mod value;
7+
8+
pub use bytecode::IntermediateBytecode;
9+
pub use instruction::IntermediateInstruction;
10+
pub use operation::HighLevelOperation;
11+
pub use value::{IntermediaryMemOrFpOrConstant, IntermediateValue};

0 commit comments

Comments
 (0)