Skip to content

Commit 0607430

Browse files
authored
Merge pull request #69 from pc2/22-latency-inference-2
Implement Latency Template Inference!
2 parents 27caf77 + b6d2c59 commit 0607430

22 files changed

+2777
-697
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
- Add if/when distinction
2626
- Add `assert`, `clog2` and `sizeof`
2727
- Rename standard library: stl => std
28+
- Add doc-comments
29+
2830

2931
### Technical Changes
3032
- Hindley-Milner for Concrete Typing

Cargo.toml

-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ members = [
2626
ariadne = "0.4.1" # for nice errors
2727
num = "0.4"
2828
clap = { version = "4.5.21", features = ["derive", "wrap_help"] }
29-
arrayvec = "0.7.6"
3029

3130
# Tree sitter
3231
tree-sitter = "~0.24.7"

README.md

+6-5
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ In this example, we create a memory block with a read port and a write port. Thi
161161
- [x] Generative Code
162162
- [x] Generative Parameters
163163
- [x] Type Templates
164-
- [ ] Full Template Inference
164+
- [x] Full Template Inference
165165
- [ ] Actions, Triggers and Queries
166166

167167
### Language Features
@@ -180,7 +180,7 @@ In this example, we create a memory block with a read port and a write port. Thi
180180
- [x] Get rid of semicolons
181181
- [x] Access module inputs / outputs through field names
182182
- [ ] Array Slices
183-
- [ ] Bound Specifiers
183+
- [ ] Sized Integers
184184
- [ ] Structs
185185
- [ ] Conditional Bindings
186186
- [x] Generative variables and assignments
@@ -190,7 +190,7 @@ In this example, we create a memory block with a read port and a write port. Thi
190190
- [x] Generative Parameters
191191
- [ ] Generative Parameter Default Arguments
192192
- [x] Type Parameters
193-
- [ ] Generative Asserts
193+
- [x] Generative Asserts
194194
- [x] Multi-Interface Syntax
195195
- [x] Native Module integration syntax
196196
- [x] Intrinsic Modules
@@ -219,7 +219,7 @@ In this example, we create a memory block with a read port and a write port. Thi
219219
- [x] Hindley-Milner typing for Concrete Types
220220
- [x] Template Type Inference
221221
- [x] Generative Parameter Inference
222-
- [ ] Latency Count Inference
222+
- [x] Latency Count Inference
223223
- [ ] Let-syntax
224224

225225
### Latency Counting
@@ -233,7 +233,8 @@ In this example, we create a memory block with a read port and a write port. Thi
233233
- [x] Integrate into Verilog generation
234234
- [x] Latency cuts
235235
- [x] Latency Offset
236-
- [ ] Latency Cuts & Latency Counting for "disjoint Input-Output blocks"
236+
- [x] Latency Cuts & Latency Counting for "disjoint Input-Output blocks"
237+
- [x] Latency Count Inference
237238
- [ ] ~~Split Latencies~~
238239

239240
### LSP

src/alloc.rs

+74-12
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,21 @@ impl<T, IndexMarker> Default for FlatAlloc<T, IndexMarker> {
502502
}
503503
}
504504

505+
/// TODO replace once get_many_mut stabilizes (In Rust 1.86 apparently)
506+
pub fn get2_mut<T>(slice: &mut [T], a: usize, b: usize) -> Option<(&mut T, &mut T)> {
507+
match b.cmp(&a) {
508+
Ordering::Equal => None,
509+
Ordering::Less => {
510+
let (l, r) = slice.split_at_mut(a);
511+
Some((&mut r[0], &mut l[b]))
512+
}
513+
Ordering::Greater => {
514+
let (l, r) = slice.split_at_mut(b);
515+
Some((&mut l[a], &mut r[0]))
516+
}
517+
}
518+
}
519+
505520
impl<T, IndexMarker> FlatAlloc<T, IndexMarker> {
506521
pub const EMPTY_FLAT_ALLOC: Self = Self::new();
507522

@@ -528,6 +543,14 @@ impl<T, IndexMarker> FlatAlloc<T, IndexMarker> {
528543
_ph: PhantomData,
529544
}
530545
}
546+
#[cfg(test)]
547+
// Only for testing, so only enabled with test flag
548+
pub fn from_vec(data: Vec<T>) -> Self {
549+
Self {
550+
data,
551+
_ph: PhantomData,
552+
}
553+
}
531554
pub fn get_next_alloc_id(&self) -> UUID<IndexMarker> {
532555
let uuid = self.data.len();
533556
UUID(uuid, PhantomData)
@@ -571,6 +594,16 @@ impl<T, IndexMarker> FlatAlloc<T, IndexMarker> {
571594
_ph: PhantomData,
572595
}
573596
}
597+
pub fn map2<T2, OT>(
598+
&self,
599+
second: &FlatAlloc<T2, IndexMarker>,
600+
f: impl FnMut((UUID<IndexMarker>, &T, &T2)) -> OT,
601+
) -> FlatAlloc<OT, IndexMarker> {
602+
FlatAlloc {
603+
data: Vec::from_iter(zip_eq(self.iter(), second.iter()).map(f)),
604+
_ph: PhantomData,
605+
}
606+
}
574607
pub fn find(
575608
&self,
576609
mut predicate: impl FnMut(UUID<IndexMarker>, &T) -> bool,
@@ -588,17 +621,7 @@ impl<T, IndexMarker> FlatAlloc<T, IndexMarker> {
588621
id_a: UUID<IndexMarker>,
589622
id_b: UUID<IndexMarker>,
590623
) -> Option<(&mut T, &mut T)> {
591-
match id_b.0.cmp(&id_a.0) {
592-
Ordering::Equal => None,
593-
Ordering::Less => {
594-
let (l, r) = self.data.split_at_mut(id_a.0);
595-
Some((&mut r[0], &mut l[id_b.0]))
596-
}
597-
Ordering::Greater => {
598-
let (l, r) = self.data.split_at_mut(id_b.0);
599-
Some((&mut l[id_a.0], &mut r[0]))
600-
}
601-
}
624+
get2_mut(&mut self.data, id_a.0, id_b.0)
602625
}
603626
pub fn get(&self, id: UUID<IndexMarker>) -> Option<&T> {
604627
self.data.get(id.0)
@@ -639,7 +662,9 @@ impl<T, IndexMarker> IndexMut<UUID<IndexMarker>> for FlatAlloc<T, IndexMarker> {
639662

640663
impl<T: Debug, IndexMarker> Debug for FlatAlloc<T, IndexMarker> {
641664
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
642-
self.data.fmt(f)
665+
f.write_str("FlatAlloc::from_vec(vec!")?;
666+
self.data.fmt(f)?;
667+
f.write_str(")")
643668
}
644669
}
645670

@@ -735,6 +760,41 @@ impl<'a, T, IndexMarker> IntoIterator for &'a mut FlatAlloc<T, IndexMarker> {
735760
}
736761
}
737762

763+
#[derive(Debug)]
764+
pub struct FlatAllocConsumingIter<T, IndexMarker> {
765+
iter: Enumerate<std::vec::IntoIter<T>>,
766+
_ph: PhantomData<IndexMarker>,
767+
}
768+
769+
impl<T, IndexMarker> Iterator for FlatAllocConsumingIter<T, IndexMarker> {
770+
type Item = (UUID<IndexMarker>, T);
771+
772+
fn next(&mut self) -> Option<Self::Item> {
773+
self.iter.next().map(|(id, v)| (UUID(id, PhantomData), v))
774+
}
775+
fn size_hint(&self) -> (usize, Option<usize>) {
776+
self.iter.size_hint()
777+
}
778+
}
779+
impl<T, IndexMarker> ExactSizeIterator for FlatAllocConsumingIter<T, IndexMarker> {
780+
fn len(&self) -> usize {
781+
self.iter.len()
782+
}
783+
}
784+
785+
impl<T, IndexMarker> IntoIterator for FlatAlloc<T, IndexMarker> {
786+
type Item = (UUID<IndexMarker>, T);
787+
788+
type IntoIter = FlatAllocConsumingIter<T, IndexMarker>;
789+
790+
fn into_iter(self) -> Self::IntoIter {
791+
FlatAllocConsumingIter {
792+
iter: self.data.into_iter().enumerate(),
793+
_ph: PhantomData,
794+
}
795+
}
796+
}
797+
738798
#[derive(Debug)]
739799
pub struct ZippedIterator<
740800
IDMarker,
@@ -757,6 +817,7 @@ impl<
757817
{
758818
type Item = (UUID<IDMarker>, OA, OB);
759819

820+
#[track_caller]
760821
fn next(&mut self) -> Option<Self::Item> {
761822
match (self.iter_a.next(), self.iter_b.next()) {
762823
(None, None) => None,
@@ -806,6 +867,7 @@ impl<
806867
{
807868
type Item = (UUID<IDMarker>, OA, OB, OC);
808869

870+
#[track_caller]
809871
fn next(&mut self) -> Option<Self::Item> {
810872
match (self.iter_a.next(), self.iter_b.next(), self.iter_c.next()) {
811873
(None, None, None) => None,

src/codegen/system_verilog.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
use std::borrow::Cow;
22
use std::ops::Deref;
33

4+
use crate::latency::CALCULATE_LATENCY_LATER;
45
use crate::linker::{IsExtern, LinkInfo};
56
use crate::prelude::*;
67

78
use crate::flattening::{DeclarationKind, Instruction, Module, Port};
89
use crate::instantiation::{
910
InstantiatedModule, MultiplexerSource, RealWire, RealWireDataSource, RealWirePathElem,
10-
CALCULATE_LATENCY_LATER,
1111
};
1212
use crate::typing::template::TVec;
1313
use crate::{typing::concrete_type::ConcreteType, value::Value};

src/config.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use clap::{Arg, Command, ValueEnum};
2+
use std::sync::OnceLock;
23
use std::{
34
collections::HashSet,
45
env,
56
ffi::{OsStr, OsString},
67
path::PathBuf,
7-
sync::LazyLock,
88
};
99

1010
/// Describes at what point in the compilation process we should exit early.
@@ -176,14 +176,18 @@ where
176176
})
177177
}
178178

179+
static CONFIG: OnceLock<ConfigStruct> = OnceLock::new();
180+
181+
pub fn initialize_config_from_cli_args() {
182+
match parse_args(std::env::args_os()) {
183+
Ok(parsed_args) => CONFIG.set(parsed_args).unwrap(),
184+
Err(err) => err.exit(),
185+
}
186+
}
187+
179188
/// Access the singleton [ConfigStruct] representing the CLI arguments passed to `sus_compiler`
180189
pub fn config() -> &'static ConfigStruct {
181-
static CONFIG: LazyLock<ConfigStruct> = LazyLock::new(|| {
182-
parse_args(std::env::args_os())
183-
.map_err(|err| err.exit())
184-
.unwrap()
185-
});
186-
&CONFIG
190+
CONFIG.get().unwrap()
187191
}
188192

189193
#[cfg(test)]

src/dev_aid/lsp/hover_info.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
use std::borrow::Cow;
22

33
use crate::alloc::ArenaAllocator;
4+
use crate::latency::CALCULATE_LATENCY_LATER;
45
use crate::prelude::*;
56
use crate::to_string::pretty_print_concrete_instance;
67

78
use lsp_types::{LanguageString, MarkedString};
89

910
use crate::flattening::{DeclarationKind, IdentifierType, InterfaceToDomainMap, Module};
10-
use crate::instantiation::{SubModuleOrWire, CALCULATE_LATENCY_LATER};
11+
use crate::instantiation::SubModuleOrWire;
1112
use crate::linker::{Documentation, FileData, GlobalUUID, LinkInfo};
1213

1314
use crate::typing::{

src/flattening/initialization.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use arrayvec::ArrayVec;
21
use sus_proc_macro::{field, kind, kw};
32

43
use crate::errors::ErrorStore;
@@ -360,7 +359,7 @@ fn initialize_global_object(
360359
errors: ErrorStore::new(),
361360
is_extern,
362361
resolved_globals: ResolvedGlobals::empty(),
363-
checkpoints: ArrayVec::new(),
362+
checkpoints: Vec::new(),
364363
};
365364

366365
link_info.reabsorb_errors_globals(
@@ -374,6 +373,7 @@ fn initialize_global_object(
374373
link_info,
375374
ports: ctx.ports,
376375
latency_inference_info: PortLatencyInferenceInfo::default(),
376+
named_domains: ctx.domains.id_range(),
377377
domains: ctx.domains,
378378
implicit_clk_domain: ctx.implicit_clk_domain,
379379
interfaces: ctx.interfaces,

src/flattening/mod.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ mod parser;
66
mod typechecking;
77
mod walk;
88

9-
use crate::alloc::UUIDAllocator;
9+
use crate::alloc::{UUIDAllocator, UUIDRange};
1010
use crate::prelude::*;
1111
use crate::typing::abstract_type::DomainType;
1212
use crate::typing::type_inference::{DomainVariableIDMarker, TypeVariableIDMarker};
@@ -50,13 +50,18 @@ pub struct Module {
5050
/// Created in Stage 1: Initialization
5151
///
5252
/// [Port::declaration_instruction] are set in Stage 2: Flattening
53+
///
54+
/// Ports can only use domains in [Self::named_domains]
5355
pub ports: FlatAlloc<Port, PortIDMarker>,
5456

5557
/// Created in Stage 2: Flattening
5658
pub latency_inference_info: PortLatencyInferenceInfo,
5759

5860
/// Created in Stage 1: Initialization
61+
///
62+
/// [Self::domains] is then extended during abstract typechecking to add unnamed domains
5963
pub domains: FlatAlloc<DomainInfo, DomainIDMarker>,
64+
pub named_domains: UUIDRange<DomainIDMarker>,
6065
pub implicit_clk_domain: bool,
6166

6267
/// Created in Stage 1: Initialization

src/instantiation/concrete_typecheck.rs

+11-10
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,8 @@ impl InstantiationContext<'_, '_> {
251251

252252
self.typecheck_all_wires();
253253

254+
delayed_constraints.push(LatencyInferenceDelayedConstraint {});
255+
254256
delayed_constraints.resolve_delayed_constraints(self);
255257

256258
self.finalize();
@@ -355,18 +357,8 @@ fn concretize_written_type_with_possible_template_args(
355357
}
356358
}
357359

358-
impl SubmoduleTypecheckConstraint {
359-
/// Directly named type and value parameters are immediately unified, but latency count deltas can only be computed from the latency counting graph
360-
fn try_infer_latency_counts(&mut self, _context: &mut InstantiationContext) {
361-
// TODO
362-
}
363-
}
364-
365360
impl DelayedConstraint<InstantiationContext<'_, '_>> for SubmoduleTypecheckConstraint {
366361
fn try_apply(&mut self, context: &mut InstantiationContext) -> DelayedConstraintStatus {
367-
// Try to infer template arguments based on the connections to the ports of the module.
368-
self.try_infer_latency_counts(context);
369-
370362
let sm = &mut context.submodules[self.sm_id];
371363

372364
let submod_instr =
@@ -500,3 +492,12 @@ impl DelayedConstraint<InstantiationContext<'_, '_>> for SubmoduleTypecheckConst
500492
.error(submod_instr.get_most_relevant_span(), message);
501493
}
502494
}
495+
496+
pub struct LatencyInferenceDelayedConstraint {}
497+
impl DelayedConstraint<InstantiationContext<'_, '_>> for LatencyInferenceDelayedConstraint {
498+
fn try_apply(&mut self, context: &mut InstantiationContext<'_, '_>) -> DelayedConstraintStatus {
499+
context.infer_parameters_for_latencies()
500+
}
501+
502+
fn report_could_not_resolve_error(&self, _context: &InstantiationContext<'_, '_>) {} // Handled by incomplete submodules themselves
503+
}

src/instantiation/execute.rs

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
77
use std::ops::{Deref, Index, IndexMut};
88

9+
use crate::latency::CALCULATE_LATENCY_LATER;
910
use crate::linker::IsExtern;
1011
use crate::prelude::*;
1112
use crate::typing::template::GlobalReference;

src/instantiation/mod.rs

-3
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,6 @@ use crate::{
2222

2323
use crate::typing::concrete_type::ConcreteType;
2424

25-
// Temporary value before proper latency is given
26-
pub const CALCULATE_LATENCY_LATER: i64 = i64::MIN;
27-
2825
/// See [MultiplexerSource]
2926
///
3027
/// This is the post-instantiation equivalent of [crate::flattening::WireReferencePathElement]

0 commit comments

Comments
 (0)