1
1
use std:: collections:: HashMap ;
2
2
3
- use acvm:: acir :: brillig:: RegisterIndex ;
3
+ use acvm:: brillig_vm :: brillig:: { HeapArray , HeapVector , RegisterIndex , RegisterOrMemory } ;
4
4
5
5
use crate :: {
6
6
brillig:: brillig_ir:: {
7
7
artifact:: { BrilligParameter , Label } ,
8
8
BrilligContext ,
9
9
} ,
10
10
ssa_refactor:: ir:: {
11
+ dfg:: DataFlowGraph ,
11
12
function:: { Function , FunctionId } ,
12
- types:: Type ,
13
+ types:: { CompositeType , Type } ,
13
14
value:: ValueId ,
14
15
} ,
15
16
} ;
16
17
17
- use super :: brillig_block:: compute_size_of_type;
18
-
19
18
pub ( crate ) struct FunctionContext {
20
19
pub ( crate ) function_id : FunctionId ,
21
- /// Map from SSA values to Register Indices .
22
- pub ( crate ) ssa_value_to_register : HashMap < ValueId , RegisterIndex > ,
20
+ /// Map from SSA values to register or memory .
21
+ pub ( crate ) ssa_value_to_brillig_variable : HashMap < ValueId , RegisterOrMemory > ,
23
22
}
24
23
25
24
impl FunctionContext {
26
- /// Gets a `RegisterIndex` for a `ValueId`, if one already exists
27
- /// or creates a new `RegisterIndex` using the latest available
28
- /// free register.
29
- pub ( crate ) fn get_or_create_register (
25
+ /// For a given SSA value id, create and cache the a corresponding variable.
26
+ /// This will allocate the needed registers for the variable.
27
+ pub ( crate ) fn create_variable (
28
+ & mut self ,
29
+ brillig_context : & mut BrilligContext ,
30
+ value : ValueId ,
31
+ dfg : & DataFlowGraph ,
32
+ ) -> RegisterOrMemory {
33
+ let typ = dfg. type_of_value ( value) ;
34
+
35
+ let variable = match typ {
36
+ Type :: Numeric ( _) | Type :: Reference => {
37
+ let register = brillig_context. allocate_register ( ) ;
38
+ RegisterOrMemory :: RegisterIndex ( register)
39
+ }
40
+ Type :: Array ( _, _) => {
41
+ let pointer_register = brillig_context. allocate_register ( ) ;
42
+ let size = compute_size_of_type ( & typ) ;
43
+ RegisterOrMemory :: HeapArray ( HeapArray { pointer : pointer_register, size } )
44
+ }
45
+ Type :: Slice ( _) => {
46
+ let pointer_register = brillig_context. allocate_register ( ) ;
47
+ let size_register = brillig_context. allocate_register ( ) ;
48
+ RegisterOrMemory :: HeapVector ( HeapVector {
49
+ pointer : pointer_register,
50
+ size : size_register,
51
+ } )
52
+ }
53
+ Type :: Function => {
54
+ unreachable ! ( "ICE: Function values should have been removed from the SSA" )
55
+ }
56
+ } ;
57
+
58
+ // Cache the `ValueId` so that if we call get_variable, it will
59
+ // return the registers that have just been created.
60
+ //
61
+ // WARNING: This assumes that a registers won't be reused for a different value.
62
+ // If you overwrite the registers, then the cache will be invalid.
63
+
64
+ if self . ssa_value_to_brillig_variable . insert ( value, variable) . is_some ( ) {
65
+ unreachable ! ( "ICE: ValueId {value:?} was already in cache" ) ;
66
+ }
67
+
68
+ variable
69
+ }
70
+
71
+ /// For a given SSA value id, return the corresponding cached variable.
72
+ pub ( crate ) fn get_variable ( & mut self , value : ValueId ) -> RegisterOrMemory {
73
+ * self
74
+ . ssa_value_to_brillig_variable
75
+ . get ( & value)
76
+ . unwrap_or_else ( || panic ! ( "ICE: Value not found in cache {value}" ) )
77
+ }
78
+
79
+ pub ( crate ) fn get_or_create_variable (
30
80
& mut self ,
31
81
brillig_context : & mut BrilligContext ,
32
82
value : ValueId ,
83
+ dfg : & DataFlowGraph ,
84
+ ) -> RegisterOrMemory {
85
+ if let Some ( variable) = self . ssa_value_to_brillig_variable . get ( & value) {
86
+ return * variable;
87
+ }
88
+
89
+ self . create_variable ( brillig_context, value, dfg)
90
+ }
91
+
92
+ /// Creates a variable that fits in a single register and returns the register.
93
+ pub ( crate ) fn create_register_variable (
94
+ & mut self ,
95
+ brillig_context : & mut BrilligContext ,
96
+ value : ValueId ,
97
+ dfg : & DataFlowGraph ,
33
98
) -> RegisterIndex {
34
- if let Some ( register_index) = self . ssa_value_to_register . get ( & value) {
35
- return * register_index;
99
+ let variable = self . create_variable ( brillig_context, value, dfg) ;
100
+ self . extract_register ( variable)
101
+ }
102
+
103
+ pub ( crate ) fn extract_register ( & self , variable : RegisterOrMemory ) -> RegisterIndex {
104
+ match variable {
105
+ RegisterOrMemory :: RegisterIndex ( register_index) => register_index,
106
+ _ => unreachable ! ( "ICE: Expected register, got {variable:?}" ) ,
36
107
}
108
+ }
37
109
38
- let register = brillig_context. allocate_register ( ) ;
110
+ pub ( crate ) fn extract_heap_array ( & self , variable : RegisterOrMemory ) -> HeapArray {
111
+ match variable {
112
+ RegisterOrMemory :: HeapArray ( array) => array,
113
+ _ => unreachable ! ( "ICE: Expected array, got {variable:?}" ) ,
114
+ }
115
+ }
39
116
40
- // Cache the `ValueId` so that if we call it again, it will
41
- // return the register that has just been created.
42
- //
43
- // WARNING: This assumes that a register has not been
44
- // modified. If a MOV instruction has overwritten the value
45
- // at a register, then this cache will be invalid.
46
- self . ssa_value_to_register . insert ( value, register) ;
117
+ pub ( crate ) fn extract_heap_vector ( & self , variable : RegisterOrMemory ) -> HeapVector {
118
+ match variable {
119
+ RegisterOrMemory :: HeapVector ( vector) => vector,
120
+ _ => unreachable ! ( "ICE: Expected vector, got {variable:?}" ) ,
121
+ }
122
+ }
47
123
48
- register
124
+ /// Collects the registers that a given variable is stored in.
125
+ pub ( crate ) fn extract_registers ( & self , variable : RegisterOrMemory ) -> Vec < RegisterIndex > {
126
+ match variable {
127
+ RegisterOrMemory :: RegisterIndex ( register_index) => vec ! [ register_index] ,
128
+ RegisterOrMemory :: HeapArray ( array) => {
129
+ vec ! [ array. pointer]
130
+ }
131
+ RegisterOrMemory :: HeapVector ( vector) => {
132
+ vec ! [ vector. pointer, vector. size]
133
+ }
134
+ }
49
135
}
50
136
51
137
/// Creates a function label from a given SSA function id.
@@ -62,6 +148,7 @@ impl FunctionContext {
62
148
match typ {
63
149
Type :: Numeric ( _) | Type :: Reference => BrilligParameter :: Register ,
64
150
Type :: Array ( ..) => BrilligParameter :: HeapArray ( compute_size_of_type ( & typ) ) ,
151
+ Type :: Slice ( _) => BrilligParameter :: HeapVector ,
65
152
_ => unimplemented ! ( "Unsupported function parameter type {typ:?}" ) ,
66
153
}
67
154
} )
@@ -77,9 +164,25 @@ impl FunctionContext {
77
164
match typ {
78
165
Type :: Numeric ( _) | Type :: Reference => BrilligParameter :: Register ,
79
166
Type :: Array ( ..) => BrilligParameter :: HeapArray ( compute_size_of_type ( & typ) ) ,
167
+ Type :: Slice ( _) => BrilligParameter :: HeapVector ,
80
168
_ => unimplemented ! ( "Unsupported return value type {typ:?}" ) ,
81
169
}
82
170
} )
83
171
. collect ( )
84
172
}
85
173
}
174
+
175
+ /// Computes the size of an SSA composite type
176
+ pub ( crate ) fn compute_size_of_composite_type ( typ : & CompositeType ) -> usize {
177
+ typ. iter ( ) . map ( compute_size_of_type) . sum ( )
178
+ }
179
+
180
+ /// Finds out the size of a given SSA type
181
+ /// This is needed to store values in memory
182
+ pub ( crate ) fn compute_size_of_type ( typ : & Type ) -> usize {
183
+ match typ {
184
+ Type :: Numeric ( _) => 1 ,
185
+ Type :: Array ( types, item_count) => compute_size_of_composite_type ( types) * item_count,
186
+ _ => todo ! ( "ICE: Type not supported {typ:?}" ) ,
187
+ }
188
+ }
0 commit comments