@@ -98,6 +98,49 @@ impl Ssa {
98
98
function. constant_fold ( false , brillig_info) ;
99
99
}
100
100
101
+ // It could happen that we inlined all calls to a given brillig function.
102
+ // In that case it's unused so we can remove it. This is what we check next.
103
+ self . remove_unused_brillig_functions ( brillig_functions)
104
+ }
105
+
106
+ fn remove_unused_brillig_functions (
107
+ mut self ,
108
+ mut brillig_functions : BTreeMap < FunctionId , Function > ,
109
+ ) -> Ssa {
110
+ // Remove from the above map functions that are called
111
+ for function in self . functions . values ( ) {
112
+ for block_id in function. reachable_blocks ( ) {
113
+ for instruction_id in function. dfg [ block_id] . instructions ( ) {
114
+ let instruction = & function. dfg [ * instruction_id] ;
115
+ let Instruction :: Call { func : func_id, arguments : _ } = instruction else {
116
+ continue ;
117
+ } ;
118
+
119
+ let func_value = & function. dfg [ * func_id] ;
120
+ let Value :: Function ( func_id) = func_value else { continue } ;
121
+
122
+ if function. runtime ( ) . is_acir ( ) {
123
+ brillig_functions. remove ( func_id) ;
124
+ }
125
+ }
126
+ }
127
+ }
128
+
129
+ // The ones that remain are never called: let's remove them.
130
+ for ( func_id, func) in & brillig_functions {
131
+ // We never want to remove the main function (it could be `unconstrained` or it
132
+ // could have been turned into brillig if `--force-brillig` was given).
133
+ // We also don't want to remove entry points.
134
+ let runtime = func. runtime ( ) ;
135
+ if self . main_id == * func_id
136
+ || ( runtime. is_entry_point ( ) && matches ! ( runtime, RuntimeType :: Acir ( _) ) )
137
+ {
138
+ continue ;
139
+ }
140
+
141
+ self . functions . remove ( func_id) ;
142
+ }
143
+
101
144
self
102
145
}
103
146
}
@@ -682,6 +725,11 @@ impl<'brillig> Context<'brillig> {
682
725
683
726
// Should we consider calls to slice_push_back and similar to be mutating operations as well?
684
727
if let Store { value : array, .. } | ArraySet { array, .. } = instruction {
728
+ if function. dfg . is_global ( * array) {
729
+ // Early return as we expect globals to be immutable.
730
+ return ;
731
+ } ;
732
+
685
733
let instruction = match & function. dfg [ * array] {
686
734
Value :: Instruction { instruction, .. } => & function. dfg [ * instruction] ,
687
735
_ => return ,
@@ -1533,6 +1581,82 @@ mod test {
1533
1581
assert_normalized_ssa_equals ( ssa, expected) ;
1534
1582
}
1535
1583
1584
+ #[ test]
1585
+ fn inlines_brillig_call_with_entry_point_globals ( ) {
1586
+ let src = "
1587
+ g0 = Field 2
1588
+
1589
+ acir(inline) fn main f0 {
1590
+ b0():
1591
+ v1 = call f1() -> Field
1592
+ return v1
1593
+ }
1594
+
1595
+ brillig(inline) fn one f1 {
1596
+ b0():
1597
+ v1 = add g0, Field 3
1598
+ return v1
1599
+ }
1600
+ " ;
1601
+ let ssa = Ssa :: from_str ( src) . unwrap ( ) ;
1602
+ let mut ssa = ssa. dead_instruction_elimination ( ) ;
1603
+ let used_globals_map = std:: mem:: take ( & mut ssa. used_globals ) ;
1604
+ let brillig = ssa. to_brillig_with_globals ( false , used_globals_map) ;
1605
+
1606
+ let expected = "
1607
+ g0 = Field 2
1608
+
1609
+ acir(inline) fn main f0 {
1610
+ b0():
1611
+ return Field 5
1612
+ }
1613
+ " ;
1614
+
1615
+ let ssa = ssa. fold_constants_with_brillig ( & brillig) ;
1616
+ assert_normalized_ssa_equals ( ssa, expected) ;
1617
+ }
1618
+
1619
+ #[ test]
1620
+ fn inlines_brillig_call_with_non_entry_point_globals ( ) {
1621
+ let src = "
1622
+ g0 = Field 2
1623
+
1624
+ acir(inline) fn main f0 {
1625
+ b0():
1626
+ v1 = call f1() -> Field
1627
+ return v1
1628
+ }
1629
+
1630
+ brillig(inline) fn entry_point f1 {
1631
+ b0():
1632
+ v1 = call f2() -> Field
1633
+ return v1
1634
+ }
1635
+
1636
+ brillig(inline) fn one f2 {
1637
+ b0():
1638
+ v1 = add g0, Field 3
1639
+ return v1
1640
+ }
1641
+ " ;
1642
+ let ssa = Ssa :: from_str ( src) . unwrap ( ) ;
1643
+ let mut ssa = ssa. dead_instruction_elimination ( ) ;
1644
+ let used_globals_map = std:: mem:: take ( & mut ssa. used_globals ) ;
1645
+ let brillig = ssa. to_brillig_with_globals ( false , used_globals_map) ;
1646
+
1647
+ let expected = "
1648
+ g0 = Field 2
1649
+
1650
+ acir(inline) fn main f0 {
1651
+ b0():
1652
+ return Field 5
1653
+ }
1654
+ " ;
1655
+
1656
+ let ssa = ssa. fold_constants_with_brillig ( & brillig) ;
1657
+ assert_normalized_ssa_equals ( ssa, expected) ;
1658
+ }
1659
+
1536
1660
#[ test]
1537
1661
fn does_not_use_cached_constrain_in_block_that_is_not_dominated ( ) {
1538
1662
let src = "
0 commit comments