1use crate::lcnf::*;
6use std::collections::{HashMap, HashSet};
7
8use super::functions::*;
9use std::collections::VecDeque;
10
11pub struct CCodeWriter {
13 pub(super) buffer: String,
14 pub(super) indent_level: usize,
15 pub(super) indent_str: String,
16}
17impl CCodeWriter {
18 pub(super) fn new(indent_str: &str) -> Self {
19 CCodeWriter {
20 buffer: String::new(),
21 indent_level: 0,
22 indent_str: indent_str.to_string(),
23 }
24 }
25 pub(super) fn indent(&mut self) {
26 self.indent_level += 1;
27 }
28 pub(super) fn dedent(&mut self) {
29 if self.indent_level > 0 {
30 self.indent_level -= 1;
31 }
32 }
33 pub(super) fn write_indent(&mut self) {
34 for _ in 0..self.indent_level {
35 self.buffer.push_str(&self.indent_str);
36 }
37 }
38 pub(super) fn writeln(&mut self, line: &str) {
39 self.write_indent();
40 self.buffer.push_str(line);
41 self.buffer.push('\n');
42 }
43 pub(super) fn write_blank(&mut self) {
44 self.buffer.push('\n');
45 }
46 pub(super) fn result(&self) -> String {
47 self.buffer.clone()
48 }
49 pub(super) fn line_count(&self) -> usize {
50 self.buffer.lines().count()
51 }
52}
53#[derive(Debug, Clone)]
55pub struct ClosureInfo {
56 pub(super) struct_name: String,
58 pub(super) fn_ptr_field: String,
60 pub(super) env_fields: Vec<(String, CType)>,
62 pub(super) arity: usize,
64}
65#[derive(Debug, Clone)]
67pub struct CEmitConfig {
68 pub emit_comments: bool,
70 pub inline_small: bool,
72 pub use_rc: bool,
74 pub indent: String,
76 pub module_name: String,
78 pub use_static: bool,
80}
81#[derive(Debug, Clone, PartialEq)]
83pub enum CExpr {
84 Var(String),
86 IntLit(i64),
88 UIntLit(u64),
90 StringLit(String),
92 Call(String, Vec<CExpr>),
94 BinOp(CBinOp, Box<CExpr>, Box<CExpr>),
96 UnaryOp(CUnaryOp, Box<CExpr>),
98 FieldAccess(Box<CExpr>, String, bool),
100 ArrayAccess(Box<CExpr>, Box<CExpr>),
102 Cast(CType, Box<CExpr>),
104 SizeOf(CType),
106 Null,
108 Ternary(Box<CExpr>, Box<CExpr>, Box<CExpr>),
110 Initializer(CType, Vec<(String, CExpr)>),
112}
113impl CExpr {
114 pub(super) fn var(name: &str) -> Self {
116 CExpr::Var(name.to_string())
117 }
118 pub(super) fn call(name: &str, args: Vec<CExpr>) -> Self {
120 CExpr::Call(name.to_string(), args)
121 }
122 pub(super) fn arrow(self, field: &str) -> Self {
124 CExpr::FieldAccess(Box::new(self), field.to_string(), true)
125 }
126 pub(super) fn dot(self, field: &str) -> Self {
128 CExpr::FieldAccess(Box::new(self), field.to_string(), false)
129 }
130 pub(super) fn binop(op: CBinOp, lhs: CExpr, rhs: CExpr) -> Self {
132 CExpr::BinOp(op, Box::new(lhs), Box::new(rhs))
133 }
134}
135#[allow(dead_code)]
136#[derive(Debug, Clone)]
137pub struct CBPassConfig {
138 pub phase: CBPassPhase,
139 pub enabled: bool,
140 pub max_iterations: u32,
141 pub debug_output: bool,
142 pub pass_name: String,
143}
144impl CBPassConfig {
145 #[allow(dead_code)]
146 pub fn new(name: impl Into<String>, phase: CBPassPhase) -> Self {
147 CBPassConfig {
148 phase,
149 enabled: true,
150 max_iterations: 10,
151 debug_output: false,
152 pass_name: name.into(),
153 }
154 }
155 #[allow(dead_code)]
156 pub fn disabled(mut self) -> Self {
157 self.enabled = false;
158 self
159 }
160 #[allow(dead_code)]
161 pub fn with_debug(mut self) -> Self {
162 self.debug_output = true;
163 self
164 }
165 #[allow(dead_code)]
166 pub fn max_iter(mut self, n: u32) -> Self {
167 self.max_iterations = n;
168 self
169 }
170}
171#[allow(dead_code)]
172#[derive(Debug, Clone, Default)]
173pub struct CBPassStats {
174 pub total_runs: u32,
175 pub successful_runs: u32,
176 pub total_changes: u64,
177 pub time_ms: u64,
178 pub iterations_used: u32,
179}
180impl CBPassStats {
181 #[allow(dead_code)]
182 pub fn new() -> Self {
183 Self::default()
184 }
185 #[allow(dead_code)]
186 pub fn record_run(&mut self, changes: u64, time_ms: u64, iterations: u32) {
187 self.total_runs += 1;
188 self.successful_runs += 1;
189 self.total_changes += changes;
190 self.time_ms += time_ms;
191 self.iterations_used = iterations;
192 }
193 #[allow(dead_code)]
194 pub fn average_changes_per_run(&self) -> f64 {
195 if self.total_runs == 0 {
196 return 0.0;
197 }
198 self.total_changes as f64 / self.total_runs as f64
199 }
200 #[allow(dead_code)]
201 pub fn success_rate(&self) -> f64 {
202 if self.total_runs == 0 {
203 return 0.0;
204 }
205 self.successful_runs as f64 / self.total_runs as f64
206 }
207 #[allow(dead_code)]
208 pub fn format_summary(&self) -> String {
209 format!(
210 "Runs: {}/{}, Changes: {}, Time: {}ms",
211 self.successful_runs, self.total_runs, self.total_changes, self.time_ms
212 )
213 }
214}
215#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
217pub enum CBinOp {
218 Add,
219 Sub,
220 Mul,
221 Div,
222 Mod,
223 Eq,
224 Neq,
225 Lt,
226 Le,
227 Gt,
228 Ge,
229 And,
230 Or,
231 BitAnd,
232 BitOr,
233 BitXor,
234 Shl,
235 Shr,
236}
237struct RcInserter {
240 pub(super) live_vars: HashMap<LcnfVarId, LcnfType>,
242 pub(super) consumed: HashSet<LcnfVarId>,
244}
245impl RcInserter {
246 pub(super) fn new() -> Self {
247 RcInserter {
248 live_vars: HashMap::new(),
249 consumed: HashSet::new(),
250 }
251 }
252 pub(super) fn mark_live(&mut self, id: LcnfVarId, ty: LcnfType) {
254 if !is_scalar_type(&ty) {
255 self.live_vars.insert(id, ty);
256 }
257 }
258 pub(super) fn mark_consumed(&mut self, id: LcnfVarId) {
260 self.consumed.insert(id);
261 }
262 pub(super) fn gen_dec_refs(&self) -> Vec<CStmt> {
264 let mut stmts = Vec::new();
265 for (id, ty) in &self.live_vars {
266 if !self.consumed.contains(id) && !is_scalar_type(ty) {
267 stmts.push(lean_dec_ref(&var_name(*id)));
268 }
269 }
270 stmts
271 }
272 pub(super) fn gen_inc_ref_if_shared(&self, id: LcnfVarId, use_count: usize) -> Vec<CStmt> {
274 let mut stmts = Vec::new();
275 if use_count > 1 {
276 if let Some(ty) = self.live_vars.get(&id) {
277 if !is_scalar_type(ty) {
278 for _ in 0..use_count - 1 {
279 stmts.push(lean_inc_ref(&var_name(id)));
280 }
281 }
282 }
283 }
284 stmts
285 }
286}
287#[allow(dead_code)]
288pub struct CBPassRegistry {
289 pub(super) configs: Vec<CBPassConfig>,
290 pub(super) stats: std::collections::HashMap<String, CBPassStats>,
291}
292impl CBPassRegistry {
293 #[allow(dead_code)]
294 pub fn new() -> Self {
295 CBPassRegistry {
296 configs: Vec::new(),
297 stats: std::collections::HashMap::new(),
298 }
299 }
300 #[allow(dead_code)]
301 pub fn register(&mut self, config: CBPassConfig) {
302 self.stats
303 .insert(config.pass_name.clone(), CBPassStats::new());
304 self.configs.push(config);
305 }
306 #[allow(dead_code)]
307 pub fn enabled_passes(&self) -> Vec<&CBPassConfig> {
308 self.configs.iter().filter(|c| c.enabled).collect()
309 }
310 #[allow(dead_code)]
311 pub fn get_stats(&self, name: &str) -> Option<&CBPassStats> {
312 self.stats.get(name)
313 }
314 #[allow(dead_code)]
315 pub fn total_passes(&self) -> usize {
316 self.configs.len()
317 }
318 #[allow(dead_code)]
319 pub fn enabled_count(&self) -> usize {
320 self.enabled_passes().len()
321 }
322 #[allow(dead_code)]
323 pub fn update_stats(&mut self, name: &str, changes: u64, time_ms: u64, iter: u32) {
324 if let Some(stats) = self.stats.get_mut(name) {
325 stats.record_run(changes, time_ms, iter);
326 }
327 }
328}
329#[allow(dead_code)]
330#[derive(Debug, Clone)]
331pub struct CBWorklist {
332 pub(super) items: std::collections::VecDeque<u32>,
333 pub(super) in_worklist: std::collections::HashSet<u32>,
334}
335impl CBWorklist {
336 #[allow(dead_code)]
337 pub fn new() -> Self {
338 CBWorklist {
339 items: std::collections::VecDeque::new(),
340 in_worklist: std::collections::HashSet::new(),
341 }
342 }
343 #[allow(dead_code)]
344 pub fn push(&mut self, item: u32) -> bool {
345 if self.in_worklist.insert(item) {
346 self.items.push_back(item);
347 true
348 } else {
349 false
350 }
351 }
352 #[allow(dead_code)]
353 pub fn pop(&mut self) -> Option<u32> {
354 let item = self.items.pop_front()?;
355 self.in_worklist.remove(&item);
356 Some(item)
357 }
358 #[allow(dead_code)]
359 pub fn is_empty(&self) -> bool {
360 self.items.is_empty()
361 }
362 #[allow(dead_code)]
363 pub fn len(&self) -> usize {
364 self.items.len()
365 }
366 #[allow(dead_code)]
367 pub fn contains(&self, item: u32) -> bool {
368 self.in_worklist.contains(&item)
369 }
370}
371#[allow(dead_code)]
372#[derive(Debug, Clone)]
373pub struct CBLivenessInfo {
374 pub live_in: Vec<std::collections::HashSet<u32>>,
375 pub live_out: Vec<std::collections::HashSet<u32>>,
376 pub defs: Vec<std::collections::HashSet<u32>>,
377 pub uses: Vec<std::collections::HashSet<u32>>,
378}
379impl CBLivenessInfo {
380 #[allow(dead_code)]
381 pub fn new(block_count: usize) -> Self {
382 CBLivenessInfo {
383 live_in: vec![std::collections::HashSet::new(); block_count],
384 live_out: vec![std::collections::HashSet::new(); block_count],
385 defs: vec![std::collections::HashSet::new(); block_count],
386 uses: vec![std::collections::HashSet::new(); block_count],
387 }
388 }
389 #[allow(dead_code)]
390 pub fn add_def(&mut self, block: usize, var: u32) {
391 if block < self.defs.len() {
392 self.defs[block].insert(var);
393 }
394 }
395 #[allow(dead_code)]
396 pub fn add_use(&mut self, block: usize, var: u32) {
397 if block < self.uses.len() {
398 self.uses[block].insert(var);
399 }
400 }
401 #[allow(dead_code)]
402 pub fn is_live_in(&self, block: usize, var: u32) -> bool {
403 self.live_in
404 .get(block)
405 .map(|s| s.contains(&var))
406 .unwrap_or(false)
407 }
408 #[allow(dead_code)]
409 pub fn is_live_out(&self, block: usize, var: u32) -> bool {
410 self.live_out
411 .get(block)
412 .map(|s| s.contains(&var))
413 .unwrap_or(false)
414 }
415}
416#[derive(Debug, Clone)]
418pub struct COutput {
419 pub header: String,
421 pub source: String,
423 pub declarations: Vec<CDecl>,
425}
426impl COutput {
427 pub(super) fn new() -> Self {
428 COutput {
429 header: String::new(),
430 source: String::new(),
431 declarations: Vec::new(),
432 }
433 }
434}
435#[allow(dead_code)]
436#[derive(Debug, Clone, PartialEq)]
437pub enum CBPassPhase {
438 Analysis,
439 Transformation,
440 Verification,
441 Cleanup,
442}
443impl CBPassPhase {
444 #[allow(dead_code)]
445 pub fn name(&self) -> &str {
446 match self {
447 CBPassPhase::Analysis => "analysis",
448 CBPassPhase::Transformation => "transformation",
449 CBPassPhase::Verification => "verification",
450 CBPassPhase::Cleanup => "cleanup",
451 }
452 }
453 #[allow(dead_code)]
454 pub fn is_modifying(&self) -> bool {
455 matches!(self, CBPassPhase::Transformation | CBPassPhase::Cleanup)
456 }
457}
458#[derive(Debug, Clone)]
460pub struct StructLayout {
461 pub name: String,
463 pub fields: Vec<(String, CType, usize)>,
465 pub total_size: usize,
467 pub alignment: usize,
469}
470#[allow(dead_code)]
471#[derive(Debug, Clone)]
472pub struct CBDepGraph {
473 pub(super) nodes: Vec<u32>,
474 pub(super) edges: Vec<(u32, u32)>,
475}
476impl CBDepGraph {
477 #[allow(dead_code)]
478 pub fn new() -> Self {
479 CBDepGraph {
480 nodes: Vec::new(),
481 edges: Vec::new(),
482 }
483 }
484 #[allow(dead_code)]
485 pub fn add_node(&mut self, id: u32) {
486 if !self.nodes.contains(&id) {
487 self.nodes.push(id);
488 }
489 }
490 #[allow(dead_code)]
491 pub fn add_dep(&mut self, dep: u32, dependent: u32) {
492 self.add_node(dep);
493 self.add_node(dependent);
494 self.edges.push((dep, dependent));
495 }
496 #[allow(dead_code)]
497 pub fn dependents_of(&self, node: u32) -> Vec<u32> {
498 self.edges
499 .iter()
500 .filter(|(d, _)| *d == node)
501 .map(|(_, dep)| *dep)
502 .collect()
503 }
504 #[allow(dead_code)]
505 pub fn dependencies_of(&self, node: u32) -> Vec<u32> {
506 self.edges
507 .iter()
508 .filter(|(_, dep)| *dep == node)
509 .map(|(d, _)| *d)
510 .collect()
511 }
512 #[allow(dead_code)]
513 pub fn topological_sort(&self) -> Vec<u32> {
514 let mut in_degree: std::collections::HashMap<u32, u32> = std::collections::HashMap::new();
515 for &n in &self.nodes {
516 in_degree.insert(n, 0);
517 }
518 for (_, dep) in &self.edges {
519 *in_degree.entry(*dep).or_insert(0) += 1;
520 }
521 let mut queue: std::collections::VecDeque<u32> = self
522 .nodes
523 .iter()
524 .filter(|&&n| in_degree[&n] == 0)
525 .copied()
526 .collect();
527 let mut result = Vec::new();
528 while let Some(node) = queue.pop_front() {
529 result.push(node);
530 for dep in self.dependents_of(node) {
531 let cnt = in_degree.entry(dep).or_insert(0);
532 *cnt = cnt.saturating_sub(1);
533 if *cnt == 0 {
534 queue.push_back(dep);
535 }
536 }
537 }
538 result
539 }
540 #[allow(dead_code)]
541 pub fn has_cycle(&self) -> bool {
542 self.topological_sort().len() < self.nodes.len()
543 }
544}
545#[derive(Debug, Clone, PartialEq)]
547pub enum CDecl {
548 Function {
550 ret_type: CType,
551 name: String,
552 params: Vec<(CType, String)>,
553 body: Vec<CStmt>,
554 is_static: bool,
555 },
556 Struct {
558 name: String,
559 fields: Vec<(CType, String)>,
560 },
561 Typedef { original: CType, alias: String },
563 Global {
565 ty: CType,
566 name: String,
567 init: Option<CExpr>,
568 is_static: bool,
569 },
570 ForwardDecl {
572 ret_type: CType,
573 name: String,
574 params: Vec<(CType, String)>,
575 },
576}
577#[derive(Debug, Clone, PartialEq, Eq, Hash)]
579pub enum CType {
580 Void,
582 Int,
584 UInt,
586 Bool,
588 Char,
590 Ptr(Box<CType>),
592 Struct(String),
594 FnPtr(Vec<CType>, Box<CType>),
596 Array(Box<CType>, usize),
598 SizeT,
600 U8,
602 LeanObject,
604}
605#[allow(dead_code)]
606#[derive(Debug, Clone)]
607pub struct CBAnalysisCache {
608 pub(super) entries: std::collections::HashMap<String, CBCacheEntry>,
609 pub(super) max_size: usize,
610 pub(super) hits: u64,
611 pub(super) misses: u64,
612}
613impl CBAnalysisCache {
614 #[allow(dead_code)]
615 pub fn new(max_size: usize) -> Self {
616 CBAnalysisCache {
617 entries: std::collections::HashMap::new(),
618 max_size,
619 hits: 0,
620 misses: 0,
621 }
622 }
623 #[allow(dead_code)]
624 pub fn get(&mut self, key: &str) -> Option<&CBCacheEntry> {
625 if self.entries.contains_key(key) {
626 self.hits += 1;
627 self.entries.get(key)
628 } else {
629 self.misses += 1;
630 None
631 }
632 }
633 #[allow(dead_code)]
634 pub fn insert(&mut self, key: String, data: Vec<u8>) {
635 if self.entries.len() >= self.max_size {
636 if let Some(oldest) = self.entries.keys().next().cloned() {
637 self.entries.remove(&oldest);
638 }
639 }
640 self.entries.insert(
641 key.clone(),
642 CBCacheEntry {
643 key,
644 data,
645 timestamp: 0,
646 valid: true,
647 },
648 );
649 }
650 #[allow(dead_code)]
651 pub fn invalidate(&mut self, key: &str) {
652 if let Some(entry) = self.entries.get_mut(key) {
653 entry.valid = false;
654 }
655 }
656 #[allow(dead_code)]
657 pub fn clear(&mut self) {
658 self.entries.clear();
659 }
660 #[allow(dead_code)]
661 pub fn hit_rate(&self) -> f64 {
662 let total = self.hits + self.misses;
663 if total == 0 {
664 return 0.0;
665 }
666 self.hits as f64 / total as f64
667 }
668 #[allow(dead_code)]
669 pub fn size(&self) -> usize {
670 self.entries.len()
671 }
672}
673#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
675pub enum CUnaryOp {
676 Neg,
677 Not,
678 BitNot,
679 Deref,
680 AddrOf,
681}
682pub struct CBackend {
687 pub(super) config: CEmitConfig,
688 pub(super) stats: CEmitStats,
689 pub(super) struct_decls: HashMap<String, Vec<(CType, String)>>,
691 pub(super) forward_decls: Vec<CDecl>,
693 pub(super) temp_counter: usize,
695 pub(super) name_map: HashMap<String, String>,
697 pub(super) closure_functions: HashSet<String>,
699}
700impl CBackend {
701 pub fn new(config: CEmitConfig) -> Self {
703 CBackend {
704 config,
705 stats: CEmitStats::default(),
706 struct_decls: HashMap::new(),
707 forward_decls: Vec::new(),
708 temp_counter: 0,
709 name_map: HashMap::new(),
710 closure_functions: HashSet::new(),
711 }
712 }
713 pub fn default_backend() -> Self {
715 Self::new(CEmitConfig::default())
716 }
717 pub(super) fn fresh_temp(&mut self) -> String {
719 let name = format!("_t{}", self.temp_counter);
720 self.temp_counter += 1;
721 name
722 }
723 pub(super) fn get_c_name(&mut self, lcnf_name: &str) -> String {
725 if let Some(name) = self.name_map.get(lcnf_name) {
726 return name.clone();
727 }
728 let mangled = mangle_name(lcnf_name);
729 self.name_map.insert(lcnf_name.to_string(), mangled.clone());
730 mangled
731 }
732 pub fn emit_module(&mut self, module: &LcnfModule) -> COutput {
734 let mut output = COutput::new();
735 let mut decls: Vec<CDecl> = Vec::new();
736 for fun in &module.fun_decls {
737 let c_name = self.get_c_name(&fun.name);
738 let c_params = self.emit_params(&fun.params);
739 let c_ret = lcnf_type_to_ctype(&fun.ret_type);
740 decls.push(CDecl::ForwardDecl {
741 ret_type: c_ret,
742 name: c_name,
743 params: c_params,
744 });
745 }
746 for ext in &module.extern_decls {
747 let c_name = self.get_c_name(&ext.name);
748 let c_params = self.emit_params(&ext.params);
749 let c_ret = lcnf_type_to_ctype(&ext.ret_type);
750 decls.push(CDecl::ForwardDecl {
751 ret_type: c_ret,
752 name: c_name,
753 params: c_params,
754 });
755 }
756 for fun in &module.fun_decls {
757 let fun_decl = self.emit_fun_decl(fun);
758 decls.push(fun_decl);
759 }
760 let mut header_writer = CCodeWriter::new(&self.config.indent);
761 let guard = format!(
762 "{}_H",
763 self.config.module_name.to_uppercase().replace('.', "_")
764 );
765 header_writer.writeln(&format!("#ifndef {}", guard));
766 header_writer.writeln(&format!("#define {}", guard));
767 header_writer.write_blank();
768 header_writer.writeln("#include <stdint.h>");
769 header_writer.writeln("#include <stddef.h>");
770 header_writer.writeln("#include \"lean_runtime.h\"");
771 header_writer.write_blank();
772 for name in self.struct_decls.keys() {
773 header_writer.writeln(&format!("struct {};", name));
774 }
775 header_writer.write_blank();
776 for (name, fields) in &self.struct_decls {
777 let struct_decl = CDecl::Struct {
778 name: name.clone(),
779 fields: fields.clone(),
780 };
781 emit_decl(&mut header_writer, &struct_decl);
782 }
783 for d in &decls {
784 if let CDecl::ForwardDecl { .. } = d {
785 emit_decl(&mut header_writer, d);
786 }
787 }
788 header_writer.write_blank();
789 header_writer.writeln(&format!("#endif /* {} */", guard));
790 output.header = header_writer.result();
791 let mut source_writer = CCodeWriter::new(&self.config.indent);
792 source_writer.writeln(&format!("#include \"{}.h\"", self.config.module_name));
793 source_writer.write_blank();
794 for d in &decls {
795 if let CDecl::Function { .. } = d {
796 emit_decl(&mut source_writer, d);
797 }
798 }
799 self.stats.total_lines = source_writer.line_count() + header_writer.line_count();
800 output.source = source_writer.result();
801 output.declarations = decls;
802 output
803 }
804 pub fn emit_fun_decl(&mut self, decl: &LcnfFunDecl) -> CDecl {
806 let c_name = self.get_c_name(&decl.name);
807 let c_params = self.emit_params(&decl.params);
808 let c_ret = lcnf_type_to_ctype(&decl.ret_type);
809 let mut body_stmts = Vec::new();
810 if self.config.emit_comments {
811 body_stmts.push(CStmt::Comment(format!(
812 "Function: {} (recursive={})",
813 decl.name, decl.is_recursive
814 )));
815 }
816 let expr_stmts = self.emit_expr(&decl.body, &decl.ret_type);
817 body_stmts.extend(expr_stmts);
818 self.stats.functions_emitted += 1;
819 CDecl::Function {
820 ret_type: c_ret,
821 name: c_name,
822 params: c_params,
823 body: body_stmts,
824 is_static: decl.is_lifted && self.config.use_static,
825 }
826 }
827 pub(super) fn emit_params(&self, params: &[LcnfParam]) -> Vec<(CType, String)> {
829 params
830 .iter()
831 .filter(|p| !p.erased)
832 .map(|p| (lcnf_type_to_ctype(&p.ty), var_name(p.id)))
833 .collect()
834 }
835 pub fn emit_type(&self, ty: &LcnfType) -> CType {
837 lcnf_type_to_ctype(ty)
838 }
839 pub fn emit_expr(&mut self, expr: &LcnfExpr, ret_ty: &LcnfType) -> Vec<CStmt> {
841 match expr {
842 LcnfExpr::Let {
843 id,
844 name,
845 ty,
846 value,
847 body,
848 } => {
849 let mut stmts = Vec::new();
850 let c_ty = lcnf_type_to_ctype(ty);
851 let c_name = var_name(*id);
852 if self.config.emit_comments && !name.is_empty() {
853 stmts.push(CStmt::Comment(format!("{} : {}", name, ty)));
854 }
855 let (init_stmts, init_expr) = self.emit_let_value(value, ty);
856 stmts.extend(init_stmts);
857 stmts.push(CStmt::VarDecl {
858 ty: c_ty,
859 name: c_name,
860 init: Some(init_expr),
861 });
862 let body_stmts = self.emit_expr(body, ret_ty);
863 stmts.extend(body_stmts);
864 stmts
865 }
866 LcnfExpr::Case {
867 scrutinee,
868 scrutinee_ty,
869 alts,
870 default,
871 } => {
872 let mut stmts = Vec::new();
873 let scrut_name = var_name(*scrutinee);
874 if is_scalar_type(scrutinee_ty) {
875 stmts.extend(self.emit_scalar_case(&scrut_name, alts, default, ret_ty));
876 } else {
877 let tag_var = self.fresh_temp();
878 stmts.push(CStmt::VarDecl {
879 ty: CType::U8,
880 name: tag_var.clone(),
881 init: Some(lean_obj_tag(&scrut_name)),
882 });
883 let mut cases: Vec<(u32, Vec<CStmt>)> = Vec::new();
884 for alt in alts {
885 let mut case_body = Vec::new();
886 if self.config.emit_comments {
887 case_body.push(CStmt::Comment(format!(
888 "Constructor: {}#{}",
889 alt.ctor_name, alt.ctor_tag
890 )));
891 }
892 for (i, param) in alt.params.iter().enumerate() {
893 if param.erased {
894 continue;
895 }
896 let field_ty = lcnf_type_to_ctype(¶m.ty);
897 let field_name = var_name(param.id);
898 case_body.push(CStmt::VarDecl {
899 ty: field_ty.clone(),
900 name: field_name.clone(),
901 init: Some(lean_ctor_get(&scrut_name, i)),
902 });
903 if self.config.use_rc && needs_rc(&field_ty) {
904 case_body.push(lean_inc_ref(&field_name));
905 self.stats.rc_inc_calls += 1;
906 }
907 }
908 let branch_stmts = self.emit_expr(&alt.body, ret_ty);
909 case_body.extend(branch_stmts);
910 cases.push((alt.ctor_tag, case_body));
911 }
912 let default_body = if let Some(def) = default {
913 self.emit_expr(def, ret_ty)
914 } else {
915 vec![CStmt::Expr(CExpr::call(
916 "lean_internal_panic_unreachable",
917 vec![],
918 ))]
919 };
920 stmts.push(CStmt::Switch {
921 scrutinee: CExpr::var(&tag_var),
922 cases,
923 default: default_body,
924 });
925 self.stats.switches_emitted += 1;
926 }
927 if self.config.use_rc && !is_scalar_type(scrutinee_ty) {
928 stmts.push(lean_dec_ref(&scrut_name));
929 self.stats.rc_dec_calls += 1;
930 }
931 stmts
932 }
933 LcnfExpr::Return(arg) => {
934 let c_expr = self.emit_arg(arg);
935 vec![CStmt::Return(Some(c_expr))]
936 }
937 LcnfExpr::Unreachable => {
938 vec![
939 CStmt::Expr(CExpr::call("lean_internal_panic_unreachable", vec![])),
940 CStmt::Return(Some(CExpr::Null)),
941 ]
942 }
943 LcnfExpr::TailCall(func, args) => {
944 let c_func = self.emit_arg(func);
945 let c_args: Vec<CExpr> = args.iter().map(|a| self.emit_arg(a)).collect();
946 let call_expr = match c_func {
947 CExpr::Var(name) => CExpr::Call(name, c_args),
948 _ => {
949 let tmp = self.fresh_temp();
950 return vec![
951 CStmt::Comment("Indirect tail call".to_string()),
952 CStmt::Return(Some(CExpr::Call(tmp, c_args))),
953 ];
954 }
955 };
956 vec![CStmt::Return(Some(call_expr))]
957 }
958 }
959 }
960 pub(super) fn emit_scalar_case(
962 &mut self,
963 scrut_name: &str,
964 alts: &[LcnfAlt],
965 default: &Option<Box<LcnfExpr>>,
966 ret_ty: &LcnfType,
967 ) -> Vec<CStmt> {
968 let mut stmts = Vec::new();
969 if alts.is_empty() {
970 if let Some(def) = default {
971 stmts.extend(self.emit_expr(def, ret_ty));
972 } else {
973 stmts.push(CStmt::Expr(CExpr::call(
974 "lean_internal_panic_unreachable",
975 vec![],
976 )));
977 }
978 return stmts;
979 }
980 let mut remaining = alts.to_vec();
981 remaining.reverse();
982 let first = remaining
983 .pop()
984 .expect("alts is non-empty after reverse; guaranteed by caller");
985 let mut result = {
986 let cond = CExpr::binop(
987 CBinOp::Eq,
988 CExpr::var(scrut_name),
989 CExpr::UIntLit(first.ctor_tag as u64),
990 );
991 let then_body = self.emit_expr(&first.body, ret_ty);
992 let else_body = if remaining.is_empty() {
993 if let Some(def) = default {
994 self.emit_expr(def, ret_ty)
995 } else {
996 vec![CStmt::Expr(CExpr::call(
997 "lean_internal_panic_unreachable",
998 vec![],
999 ))]
1000 }
1001 } else {
1002 Vec::new()
1003 };
1004 CStmt::If {
1005 cond,
1006 then_body,
1007 else_body,
1008 }
1009 };
1010 while let Some(alt) = remaining.pop() {
1011 let cond = CExpr::binop(
1012 CBinOp::Eq,
1013 CExpr::var(scrut_name),
1014 CExpr::UIntLit(alt.ctor_tag as u64),
1015 );
1016 let then_body = self.emit_expr(&alt.body, ret_ty);
1017 let else_body = if remaining.is_empty() {
1018 if let Some(def) = default {
1019 self.emit_expr(def, ret_ty)
1020 } else {
1021 vec![result]
1022 }
1023 } else {
1024 vec![result]
1025 };
1026 result = CStmt::If {
1027 cond,
1028 then_body,
1029 else_body,
1030 };
1031 }
1032 stmts.push(result);
1033 stmts
1034 }
1035 pub(super) fn emit_let_value(
1037 &mut self,
1038 value: &LcnfLetValue,
1039 _ty: &LcnfType,
1040 ) -> (Vec<CStmt>, CExpr) {
1041 match value {
1042 LcnfLetValue::App(func, args) => {
1043 let c_func = self.emit_arg(func);
1044 let c_args: Vec<CExpr> = args.iter().map(|a| self.emit_arg(a)).collect();
1045 let call = match c_func {
1046 CExpr::Var(name) => CExpr::Call(name, c_args),
1047 _ => {
1048 let tmp = self.fresh_temp();
1049 let stmts = gen_closure_apply("_closure", &c_args, &tmp);
1050 return (stmts, CExpr::var(&tmp));
1051 }
1052 };
1053 (Vec::new(), call)
1054 }
1055 LcnfLetValue::Proj(_name, idx, var) => {
1056 let obj = var_name(*var);
1057 (Vec::new(), lean_ctor_get(&obj, *idx as usize))
1058 }
1059 LcnfLetValue::Ctor(name, tag, args) => {
1060 let mut stmts = Vec::new();
1061 let num_objs = args.len();
1062 let ctor_var = self.fresh_temp();
1063 stmts.push(CStmt::VarDecl {
1064 ty: CType::LeanObject,
1065 name: ctor_var.clone(),
1066 init: Some(lean_alloc_ctor(*tag, num_objs, 0)),
1067 });
1068 for (i, arg) in args.iter().enumerate() {
1069 let c_arg = self.emit_arg(arg);
1070 stmts.push(lean_ctor_set(&ctor_var, i, c_arg));
1071 }
1072 if self.config.emit_comments {
1073 stmts.insert(0, CStmt::Comment(format!("Construct {}#{}", name, tag)));
1074 }
1075 (stmts, CExpr::var(&ctor_var))
1076 }
1077 LcnfLetValue::Lit(lit) => {
1078 let c_expr = match lit {
1079 LcnfLit::Nat(n) => CExpr::UIntLit(*n),
1080 LcnfLit::Str(s) => {
1081 CExpr::call("lean_mk_string", vec![CExpr::StringLit(s.clone())])
1082 }
1083 };
1084 (Vec::new(), c_expr)
1085 }
1086 LcnfLetValue::Erased => (Vec::new(), lean_box(CExpr::UIntLit(0))),
1087 LcnfLetValue::FVar(var) => (Vec::new(), CExpr::var(&var_name(*var))),
1088 LcnfLetValue::Reset(var) => (
1089 Vec::new(),
1090 CExpr::call("lean_obj_reset", vec![CExpr::var(&var_name(*var))]),
1091 ),
1092 LcnfLetValue::Reuse(slot, name, tag, args) => {
1093 let mut stmts = Vec::new();
1094 let num_objs = args.len();
1095 let ctor_var = self.fresh_temp();
1096 stmts.push(CStmt::VarDecl {
1097 ty: CType::LeanObject,
1098 name: ctor_var.clone(),
1099 init: Some(CExpr::call(
1100 "lean_alloc_ctor_using",
1101 vec![
1102 CExpr::var(&var_name(*slot)),
1103 CExpr::UIntLit(*tag as u64),
1104 CExpr::UIntLit(num_objs as u64),
1105 CExpr::UIntLit(0),
1106 ],
1107 )),
1108 });
1109 for (i, arg) in args.iter().enumerate() {
1110 let c_arg = self.emit_arg(arg);
1111 stmts.push(lean_ctor_set(&ctor_var, i, c_arg));
1112 }
1113 if self.config.emit_comments {
1114 stmts.insert(
1115 0,
1116 CStmt::Comment(format!("Reuse slot for {}#{}", name, tag)),
1117 );
1118 }
1119 (stmts, CExpr::var(&ctor_var))
1120 }
1121 }
1122 }
1123 pub(super) fn emit_arg(&self, arg: &LcnfArg) -> CExpr {
1125 match arg {
1126 LcnfArg::Var(id) => CExpr::var(&var_name(*id)),
1127 LcnfArg::Lit(lit) => match lit {
1128 LcnfLit::Nat(n) => CExpr::UIntLit(*n),
1129 LcnfLit::Str(s) => CExpr::call("lean_mk_string", vec![CExpr::StringLit(s.clone())]),
1130 },
1131 LcnfArg::Erased => lean_box(CExpr::UIntLit(0)),
1132 LcnfArg::Type(_) => lean_box(CExpr::UIntLit(0)),
1133 }
1134 }
1135 pub fn stats(&self) -> &CEmitStats {
1137 &self.stats
1138 }
1139}
1140#[derive(Debug, Clone, PartialEq)]
1142pub enum CStmt {
1143 VarDecl {
1145 ty: CType,
1146 name: String,
1147 init: Option<CExpr>,
1148 },
1149 Assign(CExpr, CExpr),
1151 If {
1153 cond: CExpr,
1154 then_body: Vec<CStmt>,
1155 else_body: Vec<CStmt>,
1156 },
1157 Switch {
1159 scrutinee: CExpr,
1160 cases: Vec<(u32, Vec<CStmt>)>,
1161 default: Vec<CStmt>,
1162 },
1163 While { cond: CExpr, body: Vec<CStmt> },
1165 Return(Option<CExpr>),
1167 Block(Vec<CStmt>),
1169 Expr(CExpr),
1171 Comment(String),
1173 Blank,
1175 Label(String),
1177 Goto(String),
1179 Break,
1181}
1182#[allow(dead_code)]
1183#[derive(Debug, Clone)]
1184pub struct CBDominatorTree {
1185 pub idom: Vec<Option<u32>>,
1186 pub dom_children: Vec<Vec<u32>>,
1187 pub dom_depth: Vec<u32>,
1188}
1189impl CBDominatorTree {
1190 #[allow(dead_code)]
1191 pub fn new(size: usize) -> Self {
1192 CBDominatorTree {
1193 idom: vec![None; size],
1194 dom_children: vec![Vec::new(); size],
1195 dom_depth: vec![0; size],
1196 }
1197 }
1198 #[allow(dead_code)]
1199 pub fn set_idom(&mut self, node: usize, idom: u32) {
1200 self.idom[node] = Some(idom);
1201 }
1202 #[allow(dead_code)]
1203 pub fn dominates(&self, a: usize, b: usize) -> bool {
1204 if a == b {
1205 return true;
1206 }
1207 let mut cur = b;
1208 loop {
1209 match self.idom[cur] {
1210 Some(parent) if parent as usize == a => return true,
1211 Some(parent) if parent as usize == cur => return false,
1212 Some(parent) => cur = parent as usize,
1213 None => return false,
1214 }
1215 }
1216 }
1217 #[allow(dead_code)]
1218 pub fn depth(&self, node: usize) -> u32 {
1219 self.dom_depth.get(node).copied().unwrap_or(0)
1220 }
1221}
1222#[derive(Debug, Clone, Default)]
1224pub struct CEmitStats {
1225 pub functions_emitted: usize,
1227 pub structs_emitted: usize,
1229 pub rc_inc_calls: usize,
1231 pub rc_dec_calls: usize,
1233 pub closures_emitted: usize,
1235 pub switches_emitted: usize,
1237 pub total_lines: usize,
1239}
1240#[allow(dead_code)]
1241#[derive(Debug, Clone)]
1242pub struct CBCacheEntry {
1243 pub key: String,
1244 pub data: Vec<u8>,
1245 pub timestamp: u64,
1246 pub valid: bool,
1247}
1248#[allow(dead_code)]
1249pub struct CBConstantFoldingHelper;
1250impl CBConstantFoldingHelper {
1251 #[allow(dead_code)]
1252 pub fn fold_add_i64(a: i64, b: i64) -> Option<i64> {
1253 a.checked_add(b)
1254 }
1255 #[allow(dead_code)]
1256 pub fn fold_sub_i64(a: i64, b: i64) -> Option<i64> {
1257 a.checked_sub(b)
1258 }
1259 #[allow(dead_code)]
1260 pub fn fold_mul_i64(a: i64, b: i64) -> Option<i64> {
1261 a.checked_mul(b)
1262 }
1263 #[allow(dead_code)]
1264 pub fn fold_div_i64(a: i64, b: i64) -> Option<i64> {
1265 if b == 0 {
1266 None
1267 } else {
1268 a.checked_div(b)
1269 }
1270 }
1271 #[allow(dead_code)]
1272 pub fn fold_add_f64(a: f64, b: f64) -> f64 {
1273 a + b
1274 }
1275 #[allow(dead_code)]
1276 pub fn fold_mul_f64(a: f64, b: f64) -> f64 {
1277 a * b
1278 }
1279 #[allow(dead_code)]
1280 pub fn fold_neg_i64(a: i64) -> Option<i64> {
1281 a.checked_neg()
1282 }
1283 #[allow(dead_code)]
1284 pub fn fold_not_bool(a: bool) -> bool {
1285 !a
1286 }
1287 #[allow(dead_code)]
1288 pub fn fold_and_bool(a: bool, b: bool) -> bool {
1289 a && b
1290 }
1291 #[allow(dead_code)]
1292 pub fn fold_or_bool(a: bool, b: bool) -> bool {
1293 a || b
1294 }
1295 #[allow(dead_code)]
1296 pub fn fold_shl_i64(a: i64, b: u32) -> Option<i64> {
1297 a.checked_shl(b)
1298 }
1299 #[allow(dead_code)]
1300 pub fn fold_shr_i64(a: i64, b: u32) -> Option<i64> {
1301 a.checked_shr(b)
1302 }
1303 #[allow(dead_code)]
1304 pub fn fold_rem_i64(a: i64, b: i64) -> Option<i64> {
1305 if b == 0 {
1306 None
1307 } else {
1308 Some(a % b)
1309 }
1310 }
1311 #[allow(dead_code)]
1312 pub fn fold_bitand_i64(a: i64, b: i64) -> i64 {
1313 a & b
1314 }
1315 #[allow(dead_code)]
1316 pub fn fold_bitor_i64(a: i64, b: i64) -> i64 {
1317 a | b
1318 }
1319 #[allow(dead_code)]
1320 pub fn fold_bitxor_i64(a: i64, b: i64) -> i64 {
1321 a ^ b
1322 }
1323 #[allow(dead_code)]
1324 pub fn fold_bitnot_i64(a: i64) -> i64 {
1325 !a
1326 }
1327}