1use std::collections::{BTreeMap, BTreeSet, HashMap};
14use std::fmt;
15use std::sync::Arc;
16
17use crate::ast::{Bits128, PortType, Purity, Value};
18use crate::compile::assembly::{PolydatAssembler, ResolvedDag, WireRef};
19use crate::compile::jit::JitKernelRaw;
20use crate::compile::jit::host_isa::EffectiveIsa;
21use crate::compile::simd_plan::{SimdTypeShape, validate_simd_variant};
22use crate::iteration::simd_ordinal::{OrdinalLaneClock, OrdinalPacketStamp};
23use crate::iteration::source::OrdinalBatchLease;
24use crate::kernel::{InputKind, PolydatKernel, PolydatProgram, WireSource};
25
26const TIER1_U64_LANES: usize = 2;
27const TIER1_MIN_MEMBERS: usize = 2;
28
29#[derive(Clone, Debug, PartialEq, Eq)]
30pub enum Tier1SimdError {
33 OutputNotFound(String),
35 DrivingInputNotFound(String),
37 DrivingInputNotUsed(String),
39 OutputPortUnsupported,
41 TooFewMembers {
43 found: usize,
45 minimum: usize,
47 },
48 NodeIneligible {
50 node: String,
52 reason: String,
54 },
55 ShapeMismatch {
57 node: String,
59 },
60 BoundaryUnsupported {
62 node: String,
64 },
65 BoundaryTypeMismatch {
67 boundary: String,
69 expected: PortType,
71 },
72 MutableBroadcast(String),
74 NoneAwareNode(String),
76 OutputModifierUnsupported(String),
78 ConstOutputUnsupported(String),
80 RuntimeShapeUnsupported(PortType),
82 ConstantEvaluationFailed(String),
84 VectorGraphBuild(String),
86 VectorCompilation(String),
88 CapabilityDetection(String),
90 ActiveLease,
92 LeaseInputMismatch {
94 expected: usize,
96 got: usize,
98 },
99 LeaseSequenceMismatch {
101 expected: u64,
103 got: u64,
105 },
106 LeaseStreamMismatch,
108 ActivationWentBackwards {
110 previous: u64,
112 got: u64,
114 },
115 UnknownBroadcast(String),
117 BroadcastTypeMismatch {
119 name: String,
121 expected: PortType,
123 got: PortType,
125 },
126}
127
128impl fmt::Display for Tier1SimdError {
129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130 match self {
131 Self::OutputNotFound(name) => write!(f, "SIMD output '{name}' does not exist"),
132 Self::DrivingInputNotFound(name) => {
133 write!(f, "SIMD driving input '{name}' does not exist")
134 }
135 Self::DrivingInputNotUsed(name) => {
136 write!(
137 f,
138 "selected output does not depend on driving input '{name}'"
139 )
140 }
141 Self::OutputPortUnsupported => {
142 f.write_str("Tier-1 SIMD requires the selected node's sole output port")
143 }
144 Self::TooFewMembers { found, minimum } => write!(
145 f,
146 "Tier-1 SIMD requires at least {minimum} promoted nodes, found {found}"
147 ),
148 Self::NodeIneligible { node, reason } => {
149 write!(f, "node '{node}' is not SIMD-promotable: {reason}")
150 }
151 Self::ShapeMismatch { node } => {
152 write!(f, "node '{node}' changes the SIMD lane shape")
153 }
154 Self::BoundaryUnsupported { node } => {
155 write!(
156 f,
157 "node '{node}' cannot be used as a Tier-1 packet boundary"
158 )
159 }
160 Self::BoundaryTypeMismatch { boundary, expected } => write!(
161 f,
162 "SIMD boundary '{boundary}' does not carry the required {expected} scalar type"
163 ),
164 Self::MutableBroadcast(name) => write!(
165 f,
166 "input '{name}' is externally writable; only the driving ordinal may change inside a lease"
167 ),
168 Self::NoneAwareNode(node) => write!(
169 f,
170 "node '{node}' accepts None inputs and needs explicit packet validity semantics"
171 ),
172 Self::OutputModifierUnsupported(name) => write!(
173 f,
174 "output '{name}' has a visibility modifier and cannot be speculatively packetized"
175 ),
176 Self::ConstOutputUnsupported(name) => write!(
177 f,
178 "output '{name}' is an init binding and cannot be advanced as a scalar stream"
179 ),
180 Self::RuntimeShapeUnsupported(typ) => write!(
181 f,
182 "the landed Tier-1 lease driver supports u64/RegI64x2, not {typ}"
183 ),
184 Self::ConstantEvaluationFailed(node) => {
185 write!(
186 f,
187 "constant boundary node '{node}' could not be evaluated safely"
188 )
189 }
190 Self::VectorGraphBuild(reason) => {
191 write!(f, "failed to build the register-typed SIMD graph: {reason}")
192 }
193 Self::VectorCompilation(reason) => {
194 write!(
195 f,
196 "the effective native ISA declined the SIMD graph: {reason}"
197 )
198 }
199 Self::CapabilityDetection(reason) => {
200 write!(f, "native ISA detection failed: {reason}")
201 }
202 Self::ActiveLease => f.write_str("the previous ordinal lease is not fully drained"),
203 Self::LeaseInputMismatch { expected, got } => write!(
204 f,
205 "ordinal lease targets input {got}, but the SIMD plan drives input {expected}"
206 ),
207 Self::LeaseSequenceMismatch { expected, got } => write!(
208 f,
209 "ordinal lease arrived out of reservation order: expected {expected}, got {got}"
210 ),
211 Self::LeaseStreamMismatch => {
212 f.write_str("ordinal lease stream/generation changed within one activation")
213 }
214 Self::ActivationWentBackwards { previous, got } => write!(
215 f,
216 "activation epoch moved backwards from {previous} to {got}"
217 ),
218 Self::UnknownBroadcast(name) => {
219 write!(
220 f,
221 "'{name}' is not a scope-stable broadcast input of this SIMD plan"
222 )
223 }
224 Self::BroadcastTypeMismatch {
225 name,
226 expected,
227 got,
228 } => write!(f, "broadcast '{name}' expects {expected}, got {got}"),
229 }
230 }
231}
232
233impl std::error::Error for Tier1SimdError {}
234
235#[derive(Debug)]
238pub struct Tier1LeaseStartError {
239 reason: Tier1SimdError,
240 lease: OrdinalBatchLease,
241}
242
243impl Tier1LeaseStartError {
244 pub const fn reason(&self) -> &Tier1SimdError {
246 &self.reason
247 }
248
249 pub fn into_parts(self) -> (Tier1SimdError, OrdinalBatchLease) {
251 (self.reason, self.lease)
252 }
253}
254
255impl fmt::Display for Tier1LeaseStartError {
256 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
257 self.reason.fmt(f)
258 }
259}
260
261impl std::error::Error for Tier1LeaseStartError {}
262
263#[derive(Clone, Debug, PartialEq, Eq)]
264pub struct Tier1SimdDescriptor {
267 pub output: String,
269 pub driving_input: String,
271 pub scalar_type: PortType,
273 pub register_type: PortType,
275 pub lanes: u8,
277 pub member_nodes: Vec<String>,
279 pub broadcast_inputs: Vec<String>,
281 pub effective_isa_fingerprint: String,
283}
284
285#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
286pub struct Tier1SimdStats {
288 pub leases_completed: u64,
290 pub vector_packets: u64,
292 pub scalar_fragment_lanes: u64,
294 pub scalar_recovery_lanes: u64,
296 pub values_drained: u64,
298}
299
300#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
301enum BoundaryKey {
302 Input(usize),
303 Constant(usize),
304}
305
306#[derive(Clone, Debug)]
307enum BoundaryValue {
308 Driving,
309 Broadcast { input_index: usize, name: String },
310 Constant { value: Value },
311}
312
313struct ReadyPacket {
314 stamp: OrdinalPacketStamp,
315 lanes: [Value; TIER1_U64_LANES],
316}
317
318struct ActiveLease {
319 lease: OrdinalBatchLease,
320 activation_epoch: u64,
321 next_ordinal: u64,
322 scalar_only: bool,
323 ready: Option<ReadyPacket>,
324}
325
326pub struct Tier1SimdExecutor {
329 descriptor: Tier1SimdDescriptor,
330 shape: SimdTypeShape,
331 driving_input_index: usize,
332 scalar: PolydatKernel,
333 vector: JitKernelRaw,
334 vector_output_slot: usize,
335 boundaries: Vec<BoundaryValue>,
336 active: Option<ActiveLease>,
337 activation_epoch: Option<u64>,
338 expected_lease_sequence: u64,
339 stream_identity: Option<(u64, u64)>,
340 stats: Tier1SimdStats,
341}
342
343impl Tier1SimdExecutor {
344 pub fn descriptor(&self) -> &Tier1SimdDescriptor {
346 &self.descriptor
347 }
348
349 pub const fn stats(&self) -> Tier1SimdStats {
351 self.stats
352 }
353
354 pub fn scalar_program(&self) -> &Arc<PolydatProgram> {
356 self.scalar.program()
357 }
358
359 pub const fn has_active_lease(&self) -> bool {
361 self.active.is_some()
362 }
363
364 pub fn remaining(&self) -> u64 {
366 self.active
367 .as_ref()
368 .map(|active| active.lease.range().end - active.next_ordinal)
369 .unwrap_or(0)
370 }
371
372 pub fn set_broadcast(&mut self, name: &str, value: Value) -> Result<(), Tier1SimdError> {
376 if self.active.is_some() {
377 return Err(Tier1SimdError::ActiveLease);
378 }
379 let Some(input_index) = self.boundaries.iter().find_map(|boundary| match boundary {
380 BoundaryValue::Broadcast {
381 input_index,
382 name: candidate,
383 } if candidate == name => Some(*input_index),
384 _ => None,
385 }) else {
386 return Err(Tier1SimdError::UnknownBroadcast(name.to_string()));
387 };
388 if !value.satisfies_slot(self.shape.scalar) || value.port_type() != self.shape.scalar {
389 return Err(Tier1SimdError::BroadcastTypeMismatch {
390 name: name.to_string(),
391 expected: self.shape.scalar,
392 got: value.port_type(),
393 });
394 }
395 self.scalar.state().set_input(input_index, value);
396 Ok(())
397 }
398
399 pub fn begin_lease(
402 &mut self,
403 lease: OrdinalBatchLease,
404 activation_epoch: u64,
405 ) -> Result<(), Tier1LeaseStartError> {
406 let validation = self.validate_lease(&lease, activation_epoch);
407 if let Err(reason) = validation {
408 return Err(Tier1LeaseStartError { reason, lease });
409 }
410
411 if self.activation_epoch != Some(activation_epoch) {
412 self.activation_epoch = Some(activation_epoch);
413 self.expected_lease_sequence = 0;
414 self.stream_identity = None;
415 }
416 self.stream_identity = Some((lease.stream_id(), lease.source_generation()));
417 let next_ordinal = lease.range().start;
418 self.active = Some(ActiveLease {
419 lease,
420 activation_epoch,
421 next_ordinal,
422 scalar_only: false,
423 ready: None,
424 });
425 Ok(())
426 }
427
428 fn validate_lease(
429 &self,
430 lease: &OrdinalBatchLease,
431 activation_epoch: u64,
432 ) -> Result<(), Tier1SimdError> {
433 if self.active.is_some() {
434 return Err(Tier1SimdError::ActiveLease);
435 }
436 if lease.input_index() != self.driving_input_index {
437 return Err(Tier1SimdError::LeaseInputMismatch {
438 expected: self.driving_input_index,
439 got: lease.input_index(),
440 });
441 }
442 if let Some(previous) = self.activation_epoch {
443 if activation_epoch < previous {
444 return Err(Tier1SimdError::ActivationWentBackwards {
445 previous,
446 got: activation_epoch,
447 });
448 }
449 if activation_epoch == previous {
450 if lease.sequence() != self.expected_lease_sequence {
451 return Err(Tier1SimdError::LeaseSequenceMismatch {
452 expected: self.expected_lease_sequence,
453 got: lease.sequence(),
454 });
455 }
456 if let Some(identity) = self.stream_identity
457 && identity != (lease.stream_id(), lease.source_generation())
458 {
459 return Err(Tier1SimdError::LeaseStreamMismatch);
460 }
461 } else if lease.sequence() != 0 {
462 return Err(Tier1SimdError::LeaseSequenceMismatch {
463 expected: 0,
464 got: lease.sequence(),
465 });
466 }
467 } else if lease.sequence() != 0 {
468 return Err(Tier1SimdError::LeaseSequenceMismatch {
469 expected: 0,
470 got: lease.sequence(),
471 });
472 }
473 Ok(())
474 }
475
476 pub fn force_scalar_recovery(&mut self) {
480 if let Some(active) = self.active.as_mut() {
481 active.ready = None;
482 active.scalar_only = true;
483 }
484 }
485
486 pub fn drain_into(&mut self, output: &mut [Value]) -> usize {
489 if output.is_empty() || self.active.is_none() {
490 return 0;
491 }
492
493 let mut written = 0;
494 while written < output.len() && self.active.is_some() {
495 let needs_packet = {
496 let active = self.active.as_ref().expect("checked above");
497 active
498 .ready
499 .as_ref()
500 .is_none_or(|ready| !ready.stamp.contains(active.next_ordinal))
501 };
502 if needs_packet {
503 self.materialize_packet();
504 }
505
506 let mut completed = false;
507 {
508 let active = self.active.as_mut().expect("packet materialized");
509 let ready = active.ready.as_ref().expect("packet materialized");
510 let lane = (active.next_ordinal - ready.stamp.base_ordinal) as usize;
511 output[written] = ready.lanes[lane].clone();
512 written += 1;
513 self.stats.values_drained += 1;
514 active.next_ordinal += 1;
515
516 if active.next_ordinal >= ready.stamp.base_ordinal + self.shape.lanes as u64 {
517 active.ready = None;
518 }
519 if active.next_ordinal >= active.lease.range().end {
520 completed = true;
521 }
522 }
523
524 if completed {
525 self.active = None;
526 self.expected_lease_sequence = self.expected_lease_sequence.wrapping_add(1);
527 self.stats.leases_completed += 1;
528 }
529 }
530 written
531 }
532
533 fn materialize_packet(&mut self) {
534 let (
535 base_ordinal,
536 range,
537 consumer_frontier,
538 scalar_only,
539 activation_epoch,
540 stream_id,
541 generation,
542 ) = {
543 let active = self.active.as_ref().expect("active lease");
544 (
545 OrdinalLaneClock::<TIER1_U64_LANES>::packet_base(active.next_ordinal),
546 active.lease.range(),
547 active.next_ordinal,
548 active.scalar_only,
549 active.activation_epoch,
550 active.lease.stream_id(),
551 active.lease.source_generation(),
552 )
553 };
554 let mut valid_mask = 0u16;
555 for lane in 0..TIER1_U64_LANES {
556 let ordinal = base_ordinal + lane as u64;
557 if ordinal >= range.start && ordinal >= consumer_frontier && ordinal < range.end {
558 valid_mask |= 1 << lane;
559 }
560 }
561
562 let full_mask = (1u16 << TIER1_U64_LANES) - 1;
563 let lanes = if valid_mask == full_mask && !scalar_only {
564 self.stats.vector_packets += 1;
565 self.eval_vector_packet(base_ordinal)
566 } else {
567 let mut lanes = [Value::U64(0), Value::U64(0)];
568 for (lane, slot) in lanes.iter_mut().enumerate() {
569 if valid_mask & (1 << lane) != 0 {
570 *slot = self.eval_scalar_ordinal(base_ordinal + lane as u64);
571 if scalar_only {
572 self.stats.scalar_recovery_lanes += 1;
573 } else {
574 self.stats.scalar_fragment_lanes += 1;
575 }
576 }
577 }
578 lanes
579 };
580
581 self.active.as_mut().expect("active lease").ready = Some(ReadyPacket {
582 stamp: OrdinalPacketStamp {
583 stream_id,
584 source_generation: generation,
585 activation_epoch,
586 dependency_epoch: 0,
587 base_ordinal,
588 lane_count: TIER1_U64_LANES as u8,
589 valid_mask,
590 },
591 lanes,
592 });
593 }
594
595 fn eval_vector_packet(&mut self, base_ordinal: u64) -> [Value; TIER1_U64_LANES] {
596 let mut coords = Vec::with_capacity(self.boundaries.len() * 2);
597 for boundary in &self.boundaries {
598 let bits = match boundary {
599 BoundaryValue::Driving => {
600 Bits128::from_lanes_i64([base_ordinal as i64, (base_ordinal + 1) as i64])
601 }
602 BoundaryValue::Broadcast { input_index, .. } => {
603 let value = self.scalar.state_ref().get_input(*input_index).as_u64();
604 Bits128::from_lanes_i64([value as i64; TIER1_U64_LANES])
605 }
606 BoundaryValue::Constant { value } => {
607 let value = value.as_u64();
608 Bits128::from_lanes_i64([value as i64; TIER1_U64_LANES])
609 }
610 };
611 coords.extend_from_slice(&bits.0);
612 }
613 self.vector.eval(&coords);
614 let bits = Bits128([
615 self.vector.get_slot(self.vector_output_slot),
616 self.vector.get_slot(self.vector_output_slot + 1),
617 ]);
618 bits.lanes_i64().map(|lane| Value::U64(lane as u64))
619 }
620
621 fn eval_scalar_ordinal(&mut self, ordinal: u64) -> Value {
622 self.scalar
623 .state()
624 .set_input(self.driving_input_index, Value::U64(ordinal));
625 self.scalar.pull(&self.descriptor.output).clone()
626 }
627}
628
629fn is_input_alias(resolved: &ResolvedDag, node_idx: usize) -> Option<usize> {
630 let node = &resolved.nodes[node_idx];
631 let meta = node.meta();
632 if !meta.name.starts_with("__port_") || meta.wire_inputs().len() != 1 || meta.outs.len() != 1 {
633 return None;
634 }
635 match resolved.wiring[node_idx].as_slice() {
636 [WireSource::Input(input_idx)] => Some(*input_idx),
637 _ => None,
638 }
639}
640
641fn is_constant_boundary(resolved: &ResolvedDag, node_idx: usize) -> bool {
642 resolved.wiring[node_idx].is_empty()
643 && resolved.nodes[node_idx].meta().wire_inputs().is_empty()
644 && resolved.nodes[node_idx].meta().outs.len() == 1
645 && resolved.nodes[node_idx].purity() == Purity::Pure
646}
647
648fn evaluate_constant_boundary(
649 resolved: &ResolvedDag,
650 node_idx: usize,
651) -> Result<Value, Tier1SimdError> {
652 let node = &resolved.nodes[node_idx];
653 let mut output = [Value::None];
654 std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
655 node.eval(&[], &mut output);
656 }))
657 .map_err(|_| Tier1SimdError::ConstantEvaluationFailed(node.meta().name.clone()))?;
658 Ok(output[0].clone())
659}
660
661fn boundary_key_for_source(resolved: &ResolvedDag, source: &WireSource) -> Option<BoundaryKey> {
662 match source {
663 WireSource::Input(input_idx) => Some(BoundaryKey::Input(*input_idx)),
664 WireSource::NodeOutput(node_idx, port) if *port == 0 => {
665 if let Some(input_idx) = is_input_alias(resolved, *node_idx) {
666 Some(BoundaryKey::Input(input_idx))
667 } else if is_constant_boundary(resolved, *node_idx) {
668 Some(BoundaryKey::Constant(*node_idx))
669 } else {
670 None
671 }
672 }
673 _ => None,
674 }
675}
676
677pub(crate) fn compile_tier1_ordinal(
679 resolved: ResolvedDag,
680 driving_input: &str,
681 output: &str,
682) -> Result<Tier1SimdExecutor, Tier1SimdError> {
683 let effective_isa = EffectiveIsa::detect().map_err(Tier1SimdError::CapabilityDetection)?;
684 let driving_input_index = resolved
685 .input_defs
686 .iter()
687 .position(|input| input.name == driving_input)
688 .ok_or_else(|| Tier1SimdError::DrivingInputNotFound(driving_input.to_string()))?;
689 let (output_node, output_port) = resolved
690 .output_map
691 .get(output)
692 .copied()
693 .ok_or_else(|| Tier1SimdError::OutputNotFound(output.to_string()))?;
694 if output_port != 0 || resolved.nodes[output_node].meta().outs.len() != 1 {
695 return Err(Tier1SimdError::OutputPortUnsupported);
696 }
697 if resolved.output_modifiers.contains_key(output) {
698 return Err(Tier1SimdError::OutputModifierUnsupported(
699 output.to_string(),
700 ));
701 }
702 if resolved.const_outputs.contains(output) {
703 return Err(Tier1SimdError::ConstOutputUnsupported(output.to_string()));
704 }
705
706 let mut members = BTreeSet::new();
707 let mut boundary_keys = BTreeSet::new();
708 let mut stack = vec![output_node];
709 while let Some(node_idx) = stack.pop() {
710 if is_input_alias(&resolved, node_idx).is_some()
711 || is_constant_boundary(&resolved, node_idx)
712 {
713 continue;
714 }
715 if !members.insert(node_idx) {
716 continue;
717 }
718 for source in &resolved.wiring[node_idx] {
719 if let Some(key) = boundary_key_for_source(&resolved, source) {
720 boundary_keys.insert(key);
721 } else if let WireSource::NodeOutput(upstream, port) = source {
722 if *port != 0 {
723 return Err(Tier1SimdError::BoundaryUnsupported {
724 node: resolved.nodes[*upstream].meta().name.clone(),
725 });
726 }
727 stack.push(*upstream);
728 }
729 }
730 }
731 if members.len() < TIER1_MIN_MEMBERS {
732 return Err(Tier1SimdError::TooFewMembers {
733 found: members.len(),
734 minimum: TIER1_MIN_MEMBERS,
735 });
736 }
737
738 let mut shape = None;
739 let mut variants = BTreeMap::new();
740 let mut member_names = Vec::with_capacity(members.len());
741 for &node_idx in &members {
742 let node = &resolved.nodes[node_idx];
743 if node.accepts_none_inputs() {
744 return Err(Tier1SimdError::NoneAwareNode(node.meta().name.clone()));
745 }
746 let validated = validate_simd_variant(node.as_ref()).map_err(|reason| {
747 Tier1SimdError::NodeIneligible {
748 node: node.meta().name.clone(),
749 reason: reason.to_string(),
750 }
751 })?;
752 if let Some(expected) = shape {
753 if expected != validated.shape {
754 return Err(Tier1SimdError::ShapeMismatch {
755 node: node.meta().name.clone(),
756 });
757 }
758 } else {
759 shape = Some(validated.shape);
760 }
761 member_names.push(format!("{node_idx}:{}", node.meta().name));
762 variants.insert(node_idx, validated);
763 }
764 let shape = shape.expect("minimum member count establishes a shape");
765 if shape.scalar != PortType::U64 {
766 return Err(Tier1SimdError::RuntimeShapeUnsupported(shape.scalar));
767 }
768
769 if !boundary_keys.contains(&BoundaryKey::Input(driving_input_index)) {
770 return Err(Tier1SimdError::DrivingInputNotUsed(
771 driving_input.to_string(),
772 ));
773 }
774
775 let mut boundary_values = Vec::with_capacity(boundary_keys.len());
776 let mut boundary_names = Vec::with_capacity(boundary_keys.len());
777 let mut boundary_to_name = BTreeMap::new();
778 let mut broadcast_inputs = Vec::new();
779 for (position, key) in boundary_keys.iter().enumerate() {
780 let vector_name = format!("__simd_boundary_{position}");
781 boundary_to_name.insert(key.clone(), vector_name.clone());
782 boundary_names.push(vector_name);
783 match key {
784 BoundaryKey::Input(input_index) => {
785 let input = &resolved.input_defs[*input_index];
786 if input.port_type != shape.scalar {
787 return Err(Tier1SimdError::BoundaryTypeMismatch {
788 boundary: input.name.clone(),
789 expected: shape.scalar,
790 });
791 }
792 if *input_index == driving_input_index {
793 boundary_values.push(BoundaryValue::Driving);
794 } else {
795 if input.kind == InputKind::ExternalWrite {
796 return Err(Tier1SimdError::MutableBroadcast(input.name.clone()));
797 }
798 broadcast_inputs.push(input.name.clone());
799 boundary_values.push(BoundaryValue::Broadcast {
800 input_index: *input_index,
801 name: input.name.clone(),
802 });
803 }
804 }
805 BoundaryKey::Constant(node_idx) => {
806 let value = evaluate_constant_boundary(&resolved, *node_idx)?;
807 if value.port_type() != shape.scalar {
808 return Err(Tier1SimdError::BoundaryTypeMismatch {
809 boundary: resolved.nodes[*node_idx].meta().name.clone(),
810 expected: shape.scalar,
811 });
812 }
813 boundary_values.push(BoundaryValue::Constant { value });
814 }
815 }
816 }
817
818 let mut vector_assembler = PolydatAssembler::new(boundary_names.clone());
819 for name in &boundary_names {
820 vector_assembler.set_input_type(name, shape.register);
821 }
822 vector_assembler.set_context(&resolved.source, "(Tier-1 SIMD register plan)");
823
824 let mut vector_node_names = HashMap::new();
825 for &node_idx in &members {
826 let validated = &variants[&node_idx];
827 let mut wires = Vec::with_capacity(resolved.wiring[node_idx].len());
828 for source in &resolved.wiring[node_idx] {
829 if let Some(key) = boundary_key_for_source(&resolved, source) {
830 wires.push(WireRef::input(
831 boundary_to_name
832 .get(&key)
833 .expect("discovered boundary has vector input"),
834 ));
835 } else if let WireSource::NodeOutput(upstream, port) = source {
836 let upstream_name = vector_node_names.get(upstream).ok_or_else(|| {
837 Tier1SimdError::BoundaryUnsupported {
838 node: resolved.nodes[*upstream].meta().name.clone(),
839 }
840 })?;
841 wires.push(WireRef::node_port(upstream_name, *port));
842 } else {
843 return Err(Tier1SimdError::VectorGraphBuild(
844 "unresolved scalar boundary".to_string(),
845 ));
846 }
847 }
848 let wire_types = vec![shape.register; wires.len()];
849 let vector_node =
850 crate::dsl::factory::build_node(validated.vector_node, &wires, &wire_types, &[])
851 .map_err(|error| Tier1SimdError::VectorGraphBuild(error.to_string()))?;
852 let name = format!("__simd_node_{node_idx}");
853 vector_assembler.add_node(&name, vector_node, wires);
854 vector_node_names.insert(node_idx, name);
855 }
856 let vector_output_node =
857 vector_node_names
858 .get(&output_node)
859 .ok_or_else(|| Tier1SimdError::BoundaryUnsupported {
860 node: resolved.nodes[output_node].meta().name.clone(),
861 })?;
862 vector_assembler.add_output(output, WireRef::node_port(vector_output_node, output_port));
863 let vector = vector_assembler
864 .try_compile_pure_jit_raw()
865 .map_err(Tier1SimdError::VectorCompilation)?;
866 let vector_output_slot = vector.resolve_output(output).ok_or_else(|| {
867 Tier1SimdError::VectorCompilation("compiled output slot is missing".to_string())
868 })?;
869
870 let selected_output_map = HashMap::from([(output.to_string(), (output_node, output_port))]);
871 let scalar_program = Arc::new(PolydatProgram::with_inputs(
872 resolved.nodes,
873 resolved.wiring,
874 resolved.input_defs,
875 resolved.coord_count,
876 selected_output_map,
877 vec![output.to_string()],
878 &resolved.source,
879 &resolved.context,
880 ));
881 let scalar = PolydatKernel::from_program(scalar_program);
882
883 Ok(Tier1SimdExecutor {
884 descriptor: Tier1SimdDescriptor {
885 output: output.to_string(),
886 driving_input: driving_input.to_string(),
887 scalar_type: shape.scalar,
888 register_type: shape.register,
889 lanes: shape.lanes,
890 member_nodes: member_names,
891 broadcast_inputs,
892 effective_isa_fingerprint: effective_isa.fingerprint(),
893 },
894 shape,
895 driving_input_index,
896 scalar,
897 vector,
898 vector_output_slot,
899 boundaries: boundary_values,
900 active: None,
901 activation_epoch: None,
902 expected_lease_sequence: 0,
903 stream_identity: None,
904 stats: Tier1SimdStats::default(),
905 })
906}