Skip to content

Commit aae0fd1

Browse files
authored
Merge pull request #107 from NoamDev/copy-analysis
Add copy/move capture analysis
2 parents 16012c3 + 8ce9510 commit aae0fd1

File tree

6 files changed

+178
-106
lines changed

6 files changed

+178
-106
lines changed

src/icombs/compiler.rs

Lines changed: 51 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,14 @@ use crate::{
2020
use arcstr::ArcStr;
2121
use indexmap::{IndexMap, IndexSet};
2222
use std::hash::Hash;
23-
24-
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
25-
enum VariableKind {
26-
// Can only be used once.
27-
Linear,
28-
// Replicable, but needs no dereliction
29-
Replicable,
30-
}
23+
use crate::par::process::VariableUsage;
3124

3225
#[derive(Clone, Debug)]
3326
pub enum Error {
3427
/// Error that is emitted when a variable that was never bound/captured is used
3528
UnboundVar(Span, #[allow(unused)] Var),
36-
/// Error that is emitted when a linear variable is not used
37-
UnusedVar(Span),
29+
/// Error that is emitted when it is unclear how a variable is used (move/copy)
30+
UnknownVariableUsage(Span),
3831
GlobalNotFound(GlobalName),
3932
DependencyCycle {
4033
global: GlobalName,
@@ -68,7 +61,7 @@ impl Error {
6861

6962
pub fn spans(&self) -> (Span, Vec<Span>) {
7063
match self {
71-
Error::UnboundVar(span, _) | Error::UnusedVar(span) | Error::UnguardedLoop(span, _) => {
64+
Error::UnboundVar(span, _) | Error::UnknownVariableUsage(span) | Error::UnguardedLoop(span, _) => {
7265
(span.clone(), vec![])
7366
}
7467

@@ -116,15 +109,14 @@ pub struct LoopLabel(Option<LocalName>);
116109

117110
#[derive(Debug)]
118111
pub struct Context {
119-
vars: BTreeMap<Var, (TypedTree, VariableKind)>,
112+
vars: BTreeMap<Var, TypedTree>,
120113
loop_points: BTreeMap<LoopLabel, BTreeSet<LoopLabel>>,
121114
unguarded_loop_labels: Vec<LoopLabel>,
122115
}
123116

124117
pub struct PackData {
125118
names: Vec<Var>,
126119
types: Vec<Type>,
127-
kinds: Vec<VariableKind>,
128120
loop_points: BTreeMap<LoopLabel, BTreeSet<LoopLabel>>,
129121
unguarded_loop_labels: Vec<LoopLabel>,
130122
}
@@ -140,8 +132,7 @@ impl Context {
140132
let mut m_trees = vec![];
141133
let mut m_tys = vec![];
142134
let mut m_vars = vec![];
143-
let mut m_kind = vec![];
144-
for (name, (tree, kind)) in core::mem::take(&mut self.vars) {
135+
for (name, tree) in core::mem::take(&mut self.vars) {
145136
if let Some(captures) = captures {
146137
if let Var::Name(name) = &name {
147138
if !captures.names.contains_key(name) && Some(name) != driver {
@@ -161,15 +152,13 @@ impl Context {
161152
m_vars.push(name);
162153
m_trees.push(tree.tree);
163154
m_tys.push(tree.ty);
164-
m_kind.push(kind);
165155
}
166156
let context_in = multiplex_trees(m_trees);
167157
(
168158
context_in,
169159
PackData {
170160
names: m_vars,
171161
types: m_tys,
172-
kinds: m_kind,
173162
loop_points: core::mem::take(&mut self.loop_points),
174163
unguarded_loop_labels: core::mem::take(&mut self.unguarded_loop_labels),
175164
},
@@ -178,13 +167,13 @@ impl Context {
178167

179168
pub fn unpack(&mut self, packed: &PackData, net: &mut Net) -> Tree {
180169
let mut m_trees = vec![];
181-
for (name, (ty, kind)) in packed
170+
for (name, ty) in packed
182171
.names
183172
.iter()
184-
.zip(packed.types.iter().zip(packed.kinds.iter()))
173+
.zip(packed.types.iter())
185174
{
186175
let (v0, v1) = net.create_wire();
187-
self.bind_variable_with_kind(name.clone(), v0.with_type(ty.clone()), kind.clone());
176+
self.bind_variable(name.clone(), v0.with_type(ty.clone()));
188177
m_trees.push(v1);
189178
}
190179
self.loop_points = packed.loop_points.clone();
@@ -193,8 +182,8 @@ impl Context {
193182
context_out
194183
}
195184

196-
fn bind_variable_with_kind(&mut self, var: Var, tree: TypedTree, kind: VariableKind) {
197-
match self.vars.insert(var.clone(), (tree, kind)) {
185+
fn bind_variable(&mut self, var: Var, tree: TypedTree) {
186+
match self.vars.insert(var.clone(), tree) {
198187
Some(x) => panic!("{:?}", x),
199188
None => (),
200189
}
@@ -234,13 +223,6 @@ pub(crate) fn multiplex_trees(mut trees: Vec<Tree>) -> Tree {
234223
}
235224

236225
impl Compiler {
237-
fn get_kind(&self, tree: &TypedTree) -> VariableKind {
238-
match tree.ty.is_linear(&self.type_defs).unwrap() {
239-
true => VariableKind::Linear,
240-
false => VariableKind::Replicable,
241-
}
242-
}
243-
244226
fn compile_global(&mut self, name: &GlobalName) -> Result<TypedTree> {
245227
if let Some(id) = self.global_name_to_id.get(name) {
246228
let ty = self.id_to_ty.get(*id).unwrap().clone();
@@ -386,13 +368,13 @@ impl Compiler {
386368
f: impl FnOnce(&mut Self) -> Result<T>,
387369
) -> Result<T> {
388370
let mut vars = BTreeMap::new();
389-
for (name, _) in captures.names.iter() {
390-
let (tree, kind) = self.use_variable(name, false)?;
391-
vars.insert(Var::Name(name.clone()), (tree, kind));
371+
for (name, (_span, usage)) in captures.names.iter() {
372+
let tree = self.use_variable(name, usage,false)?;
373+
vars.insert(Var::Name(name.clone()), tree);
392374
}
393375
for (label, _) in self.context.loop_points.clone().iter() {
394-
let (tree, kind) = self.use_var(&Var::Loop(label.0.clone()), false)?;
395-
vars.insert(Var::Loop(label.0.clone()), (tree, kind));
376+
let tree = self.use_var(&Var::Loop(label.0.clone()), &VariableUsage::Copy, false)?;
377+
vars.insert(Var::Loop(label.0.clone()), tree);
396378
}
397379
let loop_points_before = self.context.loop_points.clone();
398380
core::mem::swap(&mut vars, &mut self.context.vars);
@@ -403,50 +385,44 @@ impl Compiler {
403385
}
404386

405387
fn bind_variable(&mut self, var: impl Into<Var>, tree: TypedTree) -> Result<()> {
406-
let kind = self.get_kind(&tree);
407-
let prev = self.context.vars.insert(var.into(), (tree, kind));
388+
let prev = self.context.vars.insert(var.into(), tree);
408389
match prev {
409-
Some((prev_tree, prev_kind)) => {
410-
if prev_kind == VariableKind::Linear {
411-
return Err(Error::UnusedVar(Span::default()));
412-
}
390+
Some(prev_tree) => {
413391
self.net.link(prev_tree.tree, Tree::Era);
414392
Ok(())
415393
}
416394
None => Ok(()),
417395
}
418396
}
419397

420-
fn use_var(&mut self, var: &Var, in_command: bool) -> Result<(TypedTree, VariableKind)> {
421-
if let Some((tree, kind)) = self.context.vars.remove(var) {
398+
fn use_var(&mut self, var: &Var, usage: &VariableUsage, in_command: bool) -> Result<TypedTree> {
399+
if let Some(tree) = self.context.vars.remove(var) {
422400
if in_command {
423-
return Ok((tree, kind));
401+
return Ok(tree);
424402
}
425-
match kind {
426-
VariableKind::Linear => Ok((tree, kind)),
427-
kind => {
403+
match usage {
404+
VariableUsage::Move => Ok(tree),
405+
VariableUsage::Copy=> {
428406
let (w0, w1) = self.net.create_wire();
429407
let (v0, v1) = self.net.create_wire();
430408
self.net
431409
.link(Tree::Dup(Box::new(v0), Box::new(w0)), tree.tree);
432410
self.context.vars.insert(
433411
var.clone(),
434-
(
412+
435413
TypedTree {
436414
tree: w1,
437415
ty: tree.ty.clone(),
438416
},
439-
kind,
440-
),
441417
);
442-
Ok((
418+
Ok(
443419
TypedTree {
444420
tree: v1,
445421
ty: tree.ty.clone(),
446-
},
447-
kind,
448-
))
449-
}
422+
}
423+
)
424+
},
425+
VariableUsage::Unknown => Err(Error::UnknownVariableUsage(Span::None)),
450426
}
451427
} else {
452428
Err(Error::UnboundVar(Default::default(), var.clone()))
@@ -464,9 +440,10 @@ impl Compiler {
464440
fn use_variable(
465441
&mut self,
466442
name: &LocalName,
443+
usage: &VariableUsage,
467444
in_command: bool,
468-
) -> Result<(TypedTree, VariableKind)> {
469-
return self.use_var(&Var::Name(name.clone()), in_command);
445+
) -> Result<TypedTree> {
446+
self.use_var(&Var::Name(name.clone()), usage, in_command)
470447
}
471448

472449
fn create_typed_wire(&mut self, t: Type) -> (TypedTree, TypedTree) {
@@ -523,7 +500,7 @@ impl Compiler {
523500
fn compile_expression(&mut self, expr: &Expression<Type>) -> Result<TypedTree> {
524501
match expr {
525502
Expression::Global(_, name, _) => self.use_global(name),
526-
Expression::Variable(_, name, _) => Ok(self.use_variable(name, false)?.0),
503+
Expression::Variable(_, name, _typ, usage) => Ok(self.use_variable(name, usage,false)?),
527504

528505
Expression::Box(_, captures, expression, typ) => self.with_captures(captures, |this| {
529506
let (context_in, pack_data) = this.context.pack(None, None, None, &mut this.net);
@@ -575,9 +552,10 @@ impl Compiler {
575552
Process::Do {
576553
span,
577554
name,
555+
usage,
578556
typ,
579557
command,
580-
} => self.compile_command(span, name.clone(), typ.clone(), command),
558+
} => self.compile_command(span, name.clone(), usage, typ.clone(), command),
581559

582560
Process::Telltypes(_, _) => unreachable!(),
583561
}
@@ -587,19 +565,20 @@ impl Compiler {
587565
&mut self,
588566
span: &Span,
589567
name: LocalName,
568+
usage: &VariableUsage,
590569
ty: Type,
591570
cmd: &Command<Type>,
592571
) -> Result<()> {
593572
match cmd {
594573
Command::Link(expr) => {
595-
let subject = self.use_variable(&name, true)?.0;
574+
let subject = self.use_variable(&name, usage,true)?;
596575
let value = self.compile_expression(expr)?;
597576
self.link_typed(subject, value);
598577
self.end_context()?;
599578
}
600579
// types get erased.
601580
Command::SendType(argument, process) => {
602-
let subject = self.use_variable(&name, true)?.0;
581+
let subject = self.use_variable(&name, usage,true)?;
603582
let Type::Forall(_, type_name, ret_type) = self.normalize_type(subject.ty.clone())
604583
else {
605584
panic!("Unexpected type for SendType: {:?}", subject.ty);
@@ -611,7 +590,7 @@ impl Compiler {
611590
self.compile_process(process)?;
612591
}
613592
Command::ReceiveType(parameter, process) => {
614-
let subject = self.use_variable(&name, true)?.0;
593+
let subject = self.use_variable(&name, usage, true)?;
615594
let Type::Exists(_, type_name, ret_type) = self.normalize_type(subject.ty.clone())
616595
else {
617596
panic!("Unexpected type for ReceiveType: {:?}", subject.ty);
@@ -636,7 +615,7 @@ impl Compiler {
636615
// name = free
637616
// free = (name < expr >)
638617
// < process >
639-
let subject = self.use_variable(&name, true)?.0;
618+
let subject = self.use_variable(&name,usage, true)?;
640619
let Type::Function(_, _, ret_type) = self.normalize_type(subject.ty.clone()) else {
641620
panic!("Unexpected type for Receive: {:?}", subject.ty);
642621
};
@@ -655,7 +634,7 @@ impl Compiler {
655634
// name = free
656635
// free = (name target)
657636
// < process >
658-
let subject = self.use_variable(&name, true)?.0;
637+
let subject = self.use_variable(&name,usage, true)?;
659638
let Type::Pair(_, arg_type, ret_type) = self.normalize_type(subject.ty.clone())
660639
else {
661640
panic!("Unexpected type for Receive: {:?}", subject.ty);
@@ -671,7 +650,7 @@ impl Compiler {
671650
self.compile_process(process)?;
672651
}
673652
Command::Signal(chosen, process) => {
674-
let subject = self.use_variable(&name, true)?.0;
653+
let subject = self.use_variable(&name,usage, true)?;
675654
let Type::Choice(_, branches) = self.normalize_type(subject.ty.clone()) else {
676655
panic!("Unexpected type for Signal: {:?}", subject.ty);
677656
};
@@ -686,7 +665,7 @@ impl Compiler {
686665
}
687666
Command::Case(names, processes) => {
688667
self.context.unguarded_loop_labels.clear();
689-
let old_tree = self.use_variable(&name, true)?.0;
668+
let old_tree = self.use_variable(&name,usage, true)?;
690669
// Multiplex all other variables in the context.
691670
let (context_in, pack_data) = self.context.pack(None, None, None, &mut self.net);
692671

@@ -720,7 +699,7 @@ impl Compiler {
720699
// < name ! >
721700
// ==
722701
// name = *
723-
let a = self.use_variable(&name, true)?.0.tree;
702+
let a = self.use_variable(&name, usage, true)?.tree;
724703
self.net.link(a, Tree::Era);
725704
self.end_context()?;
726705
}
@@ -729,7 +708,7 @@ impl Compiler {
729708
// ==
730709
// name = *
731710
// < process >
732-
let a = self.use_variable(&name, true)?.0.tree;
711+
let a = self.use_variable(&name, usage, true)?.tree;
733712
self.net.link(a, Tree::Era);
734713
self.compile_process(process)?;
735714
}
@@ -744,13 +723,10 @@ impl Compiler {
744723
let (def0, def1) = self.net.create_wire();
745724
let prev = self.context.vars.insert(
746725
Var::Loop(label.0.clone()),
747-
(
748726
def0.with_type(Type::Break(Span::default())),
749-
VariableKind::Replicable,
750-
),
751727
);
752728

753-
if let Some((prev_tree, _)) = prev {
729+
if let Some(prev_tree) = prev {
754730
self.net.link(prev_tree.tree, Tree::Era);
755731
}
756732

@@ -782,8 +758,8 @@ impl Compiler {
782758
if self.context.unguarded_loop_labels.contains(&label) {
783759
return Err(Error::UnguardedLoop(span.clone(), label.clone().0));
784760
}
785-
let (tree, _) = self.use_var(&Var::Loop(label.0.clone()), false)?;
786-
let driver_tree = self.use_variable(&name, true)?.0;
761+
let tree = self.use_var(&Var::Loop(label.0.clone()), &VariableUsage::Copy,false)?;
762+
let driver_tree = self.use_variable(&name, usage, true)?;
787763
self.bind_variable(driver.clone(), driver_tree)?;
788764
let labels_in_scope = self.context.loop_points.get(&label).unwrap().clone();
789765
let (context_in, _) = self.context.pack(
@@ -800,12 +776,8 @@ impl Compiler {
800776

801777
fn end_context(&mut self) -> Result<()> {
802778
// drop all replicables
803-
for (_, (value, kind)) in core::mem::take(&mut self.context.vars).into_iter() {
804-
if kind == VariableKind::Linear {
805-
return Err(Error::UnusedVar(Default::default()));
806-
} else {
807-
self.net.link(value.tree, Tree::Era);
808-
}
779+
for (_, value) in core::mem::take(&mut self.context.vars).into_iter() {
780+
self.net.link(value.tree, Tree::Era);
809781
}
810782
self.context.loop_points = Default::default();
811783
Ok(())

0 commit comments

Comments
 (0)