Skip to main content

polydat_core/library/
register_view.rs

1// Copyright 2024-2026 Jonathan Shook
2// SPDX-License-Identifier: Apache-2.0
3
4//! The register view retag adapter the assembler inserts between
5//! register ports of different lane typings, and the register-port
6//! predicate it keys on (type_system_alignment.md §8.4 layer 2).
7
8use crate::ast::{NodeMeta, PolydatNode, Port, PortType, RegLanes, Slot, Value};
9
10/// Pass-through guard that retags a register word's view. The
11/// bits are untouched — this is the materialized form of "views
12/// are free bitcasts" for intra-graph wires whose producer and
13/// consumer declare different lane typings. Auto-inserted by
14/// `compile::assembly::auto_adapter` for every reg→reg pair;
15/// rarely instantiated by hand.
16pub struct RegView {
17    meta: NodeMeta,
18    to: RegLanes,
19}
20
21impl RegView {
22    /// A view of a register word as the given register type.
23    pub fn new(to: PortType) -> Self {
24        let (name, view) = match to {
25            PortType::Reg128 => ("__reg_view_raw", RegLanes::Raw),
26            PortType::RegI8x16 => ("__reg_view_i8x16", RegLanes::I8x16),
27            PortType::RegI16x8 => ("__reg_view_i16x8", RegLanes::I16x8),
28            PortType::RegI32x4 => ("__reg_view_i32x4", RegLanes::I32x4),
29            PortType::RegI64x2 => ("__reg_view_i64x2", RegLanes::I64x2),
30            PortType::RegF16x8 => ("__reg_view_f16x8", RegLanes::F16x8),
31            PortType::RegF32x4 => ("__reg_view_f32x4", RegLanes::F32x4),
32            PortType::RegF64x2 => ("__reg_view_f64x2", RegLanes::F64x2),
33            other => panic!("RegView::new: {other:?} is not a register PortType"),
34        };
35        Self {
36            meta: NodeMeta {
37                name: name.into(),
38                outs: vec![Port::new("output", to)],
39                // The input port type is nominal — any register
40                // view satisfies it (free-bitcast rule in
41                // `Value::satisfies_slot`).
42                ins: vec![Slot::Wire(Port::new("input", PortType::Reg128))],
43            },
44            to: view,
45        }
46    }
47}
48
49impl PolydatNode for RegView {
50    fn meta(&self) -> &NodeMeta {
51        &self.meta
52    }
53
54    fn eval(&self, inputs: &[Value], outputs: &mut [Value]) {
55        outputs[0] = Value::Reg128(inputs[0].as_reg_bits(), self.to);
56    }
57
58    /// In compiled buffers a view retag is a two-slot copy — the
59    /// lane typing is a static property of the consuming slot, so
60    /// the bits pass through verbatim (truly free at P2; at P3
61    /// it will be elided entirely).
62    fn compiled_u64(&self) -> Option<polydat::ast::CompiledU64Op> {
63        Some(Box::new(|inputs: &[u64], outputs: &mut [u64]| {
64            outputs[0] = inputs[0];
65            outputs[1] = inputs[1];
66        }))
67    }
68}
69
70/// `true` when `t` is any register-plane PortType.
71pub fn is_reg_port(t: PortType) -> bool {
72    matches!(
73        t,
74        PortType::Reg128
75            | PortType::RegI8x16
76            | PortType::RegI16x8
77            | PortType::RegI32x4
78            | PortType::RegI64x2
79            | PortType::RegF16x8
80            | PortType::RegF32x4
81            | PortType::RegF64x2
82    )
83}