logicaffeine_compile/codegen_dram/
mod.rs1pub mod dataflow;
30pub mod kernels;
31pub mod set_algebra;
32
33use crate::codegen_sva::unified_placement::PrimKind;
34use crate::vm::{CompiledProgram, Op};
35
36#[derive(Debug, Clone, PartialEq, Eq)]
38pub enum DramLowerError {
39 Unsupported(&'static str),
41 NoBitwiseRegion,
43 UnloweredOp(String),
46}
47
48impl std::fmt::Display for DramLowerError {
49 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50 match self {
51 DramLowerError::Unsupported(what) => write!(f, "unsupported {what}"),
52 DramLowerError::NoBitwiseRegion => write!(
53 f,
54 "no DRAM region: the program has no bulk-bitwise/copy work to offload into the DRAM plane"
55 ),
56 DramLowerError::UnloweredOp(what) => write!(f, "unlowered op: {what}"),
57 }
58 }
59}
60
61impl std::error::Error for DramLowerError {}
62
63#[derive(Clone, Copy, PartialEq, Eq, Debug)]
65pub enum DramFragment {
66 OnPlane,
67 Boundary,
68 ControlPlane,
69 OffPlane(&'static str),
70}
71
72pub fn fragment(op: &Op) -> DramFragment {
75 use DramFragment::{Boundary as Bd, ControlPlane as Cp, OffPlane as Off, OnPlane as On};
76 match op {
77 Op::BitAnd { .. } | Op::BitOr { .. } | Op::BitXor { .. } => On,
84 Op::IntersectOp { .. } | Op::UnionOp { .. } => On,
85 Op::DeepClone { .. } => On,
86
87 Op::LoadConst { .. } | Op::Move { .. } | Op::Show { .. } => Bd,
89 Op::NewList { .. }
90 | Op::NewEmptyList { .. }
91 | Op::NewEmptyListWithCapacity { .. }
92 | Op::NewEmptyListFixed { .. }
93 | Op::NewEmptyListI32 { .. }
94 | Op::NewEmptySet { .. }
95 | Op::NewEmptyMap { .. }
96 | Op::NewEmptyMapWithCapacity { .. }
97 | Op::NewRange { .. } => Bd,
98 Op::ListPush { .. } | Op::SetAdd { .. } => Bd,
99 Op::Index { .. } | Op::IndexUnchecked { .. } | Op::Length { .. } => Bd,
100 Op::IterPrepare { .. } | Op::IterNext { .. } | Op::IterPop => Bd,
101
102 Op::Add { .. } | Op::AddAssign { .. } | Op::Sub { .. } | Op::Mul { .. } => Cp,
106 Op::Div { .. } | Op::ExactDiv { .. } | Op::FloorDiv { .. } | Op::Mod { .. } => Cp,
107 Op::DivPow2 { .. } | Op::MagicDivU { .. } | Op::Pow { .. } => Cp,
108 Op::Lt { .. } | Op::Gt { .. } | Op::LtEq { .. } | Op::GtEq { .. } => Cp,
109 Op::Eq { .. } | Op::NotEq { .. } | Op::ApproxEq { .. } | Op::Not { .. } => Cp,
110 Op::Shl { .. } | Op::Shr { .. } => Cp,
111 Op::Concat { .. } | Op::SeqConcat { .. } | Op::FormatValue { .. } => Cp,
112 Op::SliceOp { .. } | Op::Contains { .. } | Op::RemoveFrom { .. } => Cp,
113 Op::SetIndex { .. } | Op::SetIndexUnchecked { .. } | Op::RegionBoundsGuard { .. } => Cp,
114 Op::Jump { .. } | Op::JumpIfFalse { .. } | Op::JumpIfTrue { .. } => Cp,
115 Op::Call { .. }
116 | Op::CallBuiltin { .. }
117 | Op::CallValue { .. }
118 | Op::MakeClosure { .. } => Cp,
119 Op::Return { .. } | Op::ReturnNothing | Op::Halt => Cp,
120 Op::GlobalGet { .. } | Op::GlobalSet { .. } => Cp,
121 Op::EnsureOwned { .. } | Op::CheckPolicy { .. } | Op::ListPushField { .. } => Cp,
122 Op::LoadToday { .. } | Op::LoadNow { .. } => Cp,
123 Op::NewTuple { .. } | Op::DestructureTuple { .. } | Op::ListPop { .. } => Cp,
124 Op::NewStruct { .. } | Op::StructInsert { .. } | Op::GetField { .. } => Cp,
125 Op::NewInductive { .. } | Op::TestArm { .. } | Op::BindArm { .. } => Cp,
126 Op::NewCrdt { .. }
127 | Op::CrdtBump { .. }
128 | Op::CrdtMerge { .. }
129 | Op::CrdtAppend { .. }
130 | Op::CrdtResolve { .. }
131 | Op::CrdtJoin { .. } => Cp,
132 Op::BigIntWide { .. } | Op::Obs { .. } | Op::FailWith { .. } | Op::Args { .. } => Cp,
133 Op::RevSwap { .. }
134 | Op::RevXor { .. }
135 | Op::RevNeg { .. }
136 | Op::RevAdd { .. }
137 | Op::RevSub { .. } => Cp,
138
139 Op::ChanNew { .. }
141 | Op::ChanSend { .. }
142 | Op::ChanRecv { .. }
143 | Op::ChanTrySend { .. }
144 | Op::ChanTryRecv { .. }
145 | Op::ChanClose { .. } => Off("channel"),
146 Op::Spawn { .. } | Op::SpawnHandle { .. } | Op::TaskAwait { .. } | Op::TaskAbort { .. } => {
147 Off("task")
148 }
149 Op::Sleep { .. }
150 | Op::SelectArmRecv { .. }
151 | Op::SelectArmTimeout { .. }
152 | Op::SelectWait { .. } => Off("virtual-time/select"),
153 Op::NetConnect { .. }
154 | Op::NetListen { .. }
155 | Op::NetSend { .. }
156 | Op::NetStream { .. }
157 | Op::NetAwait { .. }
158 | Op::NetMakePeer { .. }
159 | Op::NetSync { .. }
160 | Op::Tcp { .. }
161 | Op::Serve { .. } => Off("networking"),
162 }
163}
164
165pub fn dram_prim(op: &Op) -> Option<PrimKind> {
169 match op {
170 Op::BitAnd { .. } | Op::IntersectOp { .. } => Some(PrimKind::And),
171 Op::BitOr { .. } | Op::UnionOp { .. } => Some(PrimKind::Or),
172 Op::BitXor { .. } => Some(PrimKind::Xor),
173 Op::DeepClone { .. } => Some(PrimKind::Copy),
174 _ => None,
175 }
176}
177
178#[derive(Clone, Copy, PartialEq, Eq, Debug)]
182pub enum DramTier {
183 ComputeDram,
184 Ambit,
185}
186
187pub fn dram_tier(op: &Op) -> Option<DramTier> {
188 match op {
189 Op::BitAnd { .. }
190 | Op::BitOr { .. }
191 | Op::IntersectOp { .. }
192 | Op::UnionOp { .. }
193 | Op::DeepClone { .. } => Some(DramTier::ComputeDram),
194 Op::BitXor { .. } => Some(DramTier::Ambit),
195 _ => None,
196 }
197}
198
199pub fn unsupported_reason(program: &CompiledProgram) -> Option<&'static str> {
203 use crate::aot_unsupported::Offload;
204 crate::aot_unsupported::first(program).map(|o| match o {
205 Offload::Channel => "channel op (a DRAM device has no channels)",
206 Offload::Task => "task spawn/await (a DRAM device has no thread scheduler)",
207 Offload::VirtualTime => "virtual-time / select (needs a cooperative scheduler)",
208 Offload::Net => "networking op (host-only IO)",
209 Offload::Dom => "DOM / browser op (the DRAM fabric has no document to build)",
210 })
211}
212
213pub fn has_bitwise_region(program: &CompiledProgram) -> bool {
215 program
216 .code
217 .iter()
218 .any(|op| matches!(fragment(op), DramFragment::OnPlane))
219}
220
221pub fn dram_refusal(program: &CompiledProgram) -> Option<DramLowerError> {
224 if let Some(reason) = unsupported_reason(program) {
225 return Some(DramLowerError::Unsupported(reason));
226 }
227 if !has_bitwise_region(program) {
228 return Some(DramLowerError::NoBitwiseRegion);
229 }
230 None
231}
232
233#[cfg(test)]
234#[path = "../../../logicaffeine_tests/unit/logicaffeine_compile/codegen_dram/tests.rs"]
235mod tests;