@@ -29,10 +29,13 @@ struct PortGroup {
29
29
///
30
30
/// portA'4 -> portB'L-3
31
31
///
32
- /// That would create a inference candidate for template var 'L' with an offset of 7. (L == 7 iff portA' - portB' == 0)
32
+ /// That would create a inference candidate for template var 'L' with an offset of 7. (L == 7 iff |portA| - |portB| == 0)
33
+ ///
34
+ /// So |from| + offset + L == |to|
35
+ ///
36
+ /// L = |to| - |from| - offset
33
37
#[ derive( Debug , Clone ) ]
34
38
struct LatencyInferenceCandidate {
35
- template_id : TemplateID ,
36
39
from : PortID ,
37
40
to : PortID ,
38
41
offset : i64 ,
@@ -162,43 +165,82 @@ fn recurse_down_expression(
162
165
}
163
166
}
164
167
168
+ /// The basic way latency count inference works is as follows:
169
+ /// On the module interface, ports may be marked with latency annotations.
170
+ /// These annotations can be simple constants (portA'0, portB'-3, etc),
171
+ /// or larger expressions involving some template parameter, such as portC'L, portD'L+3-2
172
+ ///
173
+ /// Whereever there is a difference in the latency annitation between two ports of exactly
174
+ /// 1x a variable + some constant offset, the port pair becomes eligible for latency inference
175
+ ///
176
+ /// When the module is flattened, we can immediately construct for every template parameter,
177
+ /// a list of all port pairs that may be used to infer the value of this parameter.
178
+ ///
179
+ /// Once we come to actually performing said inference [Self::try_infer_var], we take the list
180
+ /// of absolute latencies we know for these ports, and take the minimum latency we could find.
181
+ /// This ensures that instantiating the module cannot ever expand beyond the context in which
182
+ /// it is inferred. Finally, all
165
183
#[ derive( Default , Debug ) ]
166
184
pub struct PortLatencyInferenceInfo {
167
185
//port_latency_groups: Vec<Vec<PortGroup>>,
168
- inference_candidates : Vec < LatencyInferenceCandidate > ,
186
+ inference_candidates : TVec < Vec < LatencyInferenceCandidate > > ,
169
187
}
170
188
171
- pub fn make_port_latency_inference_info (
172
- ports : & FlatAlloc < Port , PortIDMarker > ,
173
- instructions : & FlatAlloc < Instruction , FlatIDMarker > ,
174
- num_template_args : usize ,
175
- ) -> PortLatencyInferenceInfo {
176
- let port_infos = ports. map ( |( _port_id, port) | {
177
- let decl = instructions[ port. declaration_instruction ] . unwrap_declaration ( ) ;
178
-
179
- decl. latency_specifier . and_then ( |latency_spec| {
180
- recurse_down_expression ( instructions, latency_spec, num_template_args)
181
- } )
182
- } ) ;
183
-
184
- let mut inference_candidates = Vec :: new ( ) ;
185
-
186
- for ( from, from_info) in port_infos. iter_valids ( ) {
187
- for ( to, to_info) in port_infos. iter_valids ( ) {
188
- if let Some ( ( template_id, offset) ) =
189
- PortLatencyLinearity :: is_pair_latency_candidate ( from_info, to_info)
190
- {
191
- inference_candidates. push ( LatencyInferenceCandidate {
192
- template_id,
193
- from,
194
- to,
195
- offset,
196
- } ) ;
189
+ impl PortLatencyInferenceInfo {
190
+ pub fn make (
191
+ ports : & FlatAlloc < Port , PortIDMarker > ,
192
+ instructions : & FlatAlloc < Instruction , FlatIDMarker > ,
193
+ num_template_args : usize ,
194
+ ) -> PortLatencyInferenceInfo {
195
+ let port_infos = ports. map ( |( _port_id, port) | {
196
+ let decl = instructions[ port. declaration_instruction ] . unwrap_declaration ( ) ;
197
+
198
+ decl. latency_specifier . and_then ( |latency_spec| {
199
+ recurse_down_expression ( instructions, latency_spec, num_template_args)
200
+ } )
201
+ } ) ;
202
+
203
+ let mut inference_candidates = FlatAlloc :: with_size ( num_template_args, Vec :: new ( ) ) ;
204
+
205
+ for ( from, from_info) in port_infos. iter_valids ( ) {
206
+ for ( to, to_info) in port_infos. iter_valids ( ) {
207
+ if ports[ from] . domain != ports[ to] . domain {
208
+ continue ; // ports on different domains cannot be related in latency counting
209
+ }
210
+ if let Some ( ( template_id, offset) ) =
211
+ PortLatencyLinearity :: is_pair_latency_candidate ( from_info, to_info)
212
+ {
213
+ inference_candidates[ template_id] . push ( LatencyInferenceCandidate {
214
+ from,
215
+ to,
216
+ offset,
217
+ } ) ;
218
+ }
197
219
}
198
220
}
221
+
222
+ PortLatencyInferenceInfo {
223
+ inference_candidates,
224
+ }
199
225
}
200
226
201
- PortLatencyInferenceInfo {
202
- inference_candidates,
227
+ /// To infer a specific specific variable, we look at all
228
+ pub fn try_infer_var (
229
+ & self ,
230
+ template_var : TemplateID ,
231
+ port_latencies : & FlatAlloc < Option < i64 > , PortIDMarker > ,
232
+ ) -> Option < i64 > {
233
+ let mut inferred_variable_value = i64:: MAX ;
234
+
235
+ for candidate in & self . inference_candidates [ template_var] {
236
+ let from_latency = port_latencies[ candidate. from ] ?;
237
+ let to_latency = port_latencies[ candidate. to ] ?;
238
+
239
+ let this_pair_infers_to = to_latency - from_latency - candidate. offset ;
240
+
241
+ inferred_variable_value = i64:: min ( inferred_variable_value, this_pair_infers_to) ;
242
+ }
243
+
244
+ ( inferred_variable_value != i64:: MAX ) . then_some ( inferred_variable_value)
203
245
}
204
246
}
0 commit comments