Fabric MLIR is LOOM's hardware architecture IR. It describes the modules, containers, routing resources, and memory endpoints that form the ADG.
LOOM retains the overall Fabric role from the legacy design, but changes the internal PE and switch model substantially.
fabric.spatial_peandfabric.temporal_pecontain explicitfabric.function_unitinstances.fabric.function_unitmay contain a configurable internal DAG viafabric.mux.fabric.spatial_swmay be decomposable, so routing may operate at sub-lane granularity.fabric.spatial_swmay also carry tagged payloads, but tagged spatial routing remains tag-agnostic and may not be decomposable.- DFG-domain exploration replaces the older pragma-centric control model.
| Family | Operations |
|---|---|
| Top level | fabric.module, fabric.instance, fabric.yield |
| Compute containers | fabric.spatial_pe, fabric.temporal_pe |
| Compute bodies | fabric.function_unit, fabric.mux |
| Routing | fabric.spatial_sw, fabric.temporal_sw, fabric.fifo |
| Tag boundary | fabric.add_tag, fabric.map_tag, fabric.del_tag |
| Memory | fabric.memory, fabric.extmemory, and related memory resources |
At module boundaries and inter-module connections, LOOM uses structural bit types, not native arithmetic types.
Typical rules:
- module and switch ports use
!fabric.bits<N> fabric.spatial_swmay also use!fabric.tagged<!fabric.bits<N>, iK>when routing itself does not depend on tag- tagged temporal routing uses
!fabric.tagged<!fabric.bits<N>, iK> - native types such as
i32,f32,index, andnonelive insidefunction_unitboundaries - when
indexis lowered to a concrete integer width for hardware-facing behavior, LOOM uses one centrally configured bit width - the default Fabric index width is
32 - the preset width family is
32,48,57, or64 - the process-wide environment variable
LOOM_INDEX_WIDTHmay override the default with any decimal integer in the inclusive range32..64
For tagged Fabric ports, two concepts must stay separate:
- hardware tag parameters:
whether a port is tagged at all, and if so, its
tagWidth - runtime tag values: the concrete tag numbers carried by one mapped software flow or written into one runtime-config structure
Hardware tag parameters come directly from the ADG's port types. They are not inferred by the mapper. The mapper only validates compatibility and computes runtime tag values where configuration requires them.
LOOM hardware connections allow width mismatch as long as tag-kind matches:
- non-tagged may connect to non-tagged
- tagged may connect to tagged
- non-tagged may not connect directly to tagged
When widths differ on one hardware connection:
- value bits remain LSB-aligned at the physical connection boundary
- value payloads may therefore be truncated or zero-extended according to the usual wide-to-narrow or narrow-to-wide Fabric rule
- tag fields may be carried between different tagged widths structurally, but a mapped concrete runtime tag must remain representable at every tagged port on the routed path
- LOOM must not rely on implicit tag truncation or implicit tag zero-extension that would change the concrete runtime tag value seen by later hardware resources
Only three Fabric operations may intentionally change tagged shape at a port boundary:
fabric.add_tagfabric.map_tagfabric.del_tag
All other Fabric operations are structural carriers or routers. They may route tagged values, but they do not create, remove, or resize the tag field.
Therefore, a tagged-to-tagged hardware connection with different declared tag widths is only semantically usable for one mapped flow when that flow's concrete runtime tag value fits every tagged port type along the path without changing value.
For fabric.map_tag, the value payload type must remain unchanged. map_tag
may rewrite runtime tag values and may also change the tag width between its
input and result tagged types.
LOOM distinguishes named definitions from inline instantiations by structural syntax, not by whether an op happens to have SSA results on the left-hand side.
For module-level Fabric components:
- a named definition has no operand list and contributes reusable structure to its host scope
- an inline instantiation carries an operand list and contributes one graph
node directly to the enclosing
fabric.module
Current parser and verifier materialize this distinction through the
operation-local inline_instantiation marker. This is an implementation detail,
but the normative semantic distinction is:
- definitions establish symbols
- inline instantiations do not establish instantiable definition targets
- a
fabric.function_unitdefinition may appear directly inside:- the top-level
builtin.module fabric.modulefabric.spatial_pefabric.temporal_pe
- the top-level
fabric.function_unitmay only be instantiated inside:fabric.spatial_pefabric.temporal_pe
- inside one PE, a function unit may be provided either:
- by a direct local
fabric.function_unitbody - by
fabric.instancetargeting a visiblefabric.function_unit
- by a direct local
An instance inside one PE must target fabric.function_unit, and it must not
carry SSA operands or SSA results. PE-local function-unit binding is structural,
not a routed Fabric edge.
fabric.muxmay appear only directly insidefabric.function_unit- it is inline-only and is not instantiable through
fabric.instance
The following operations are module-level Fabric components:
fabric.spatial_pefabric.temporal_pefabric.spatial_swfabric.temporal_swfabric.memoryfabric.extmemoryfabric.fifo
For these operations:
- named definitions may appear directly inside:
- the top-level
builtin.module fabric.module
- the top-level
- inline instantiations may appear directly only inside
fabric.module fabric.instancetargeting one of these definitions may appear directly only insidefabric.module
The following operations are inline-only graph nodes:
fabric.add_tagfabric.map_tagfabric.del_tag
They may appear directly only inside fabric.module.
Named definitions are resolved lexically by host scope. The relevant host scopes are:
- the top-level
builtin.module fabric.modulefabric.spatial_pefabric.temporal_pe
Two named definitions in the same host scope may not share the same name, even
if they have different Fabric operation kinds. This conflict space is shared
across module types so that fabric.instance resolution remains unambiguous.
All named Fabric definitions that are emitted as MLIR symbols must also use valid MLIR symbol names. Human-facing identifiers that include punctuation or other symbol-unsafe characters must be canonicalized before export so that the resulting ADG parses without local text rewriting.
Each operation separates:
- hardware parameters: physical structure, fixed for an instance
- runtime configuration: values programmed by the mapper
For LOOM, this split is especially important for:
spatial_swconnectivity versus route tablesspatial_pestructure versus opcode, mux, demux, and FU config selectionsfunction_unitstatic structure versus selectedmuxsettings
When an ADG is given to the mapper, pre-populated runtime-config fields are treated as hints unless a more specific spec says otherwise. The mapping output is the authoritative source of final runtime configuration.
LOOM follows one textual convention across the Fabric dialect:
- hardware parameters are serialized in square brackets
[...] - runtime-configurable state is serialized in braces, either as bare
attribute-dict braces
{...}or asattributes {...}for ops with custom assembly forms
Examples:
fabric.function_unit ... [latency = 1, interval = 1]fabric.mux ... {sel = 0 : i64, discard = false, disconnect = false}fabric.temporal_pe ... [num_register = 0 : i64, num_instruction = 4 : i64, reg_fifo_depth = 0 : i64] attributes {instruction_mem = [...] }fabric.map_tag ... [table_size = 4 : i64] attributes {table = [[1, 0, 3], ...] }fabric.memoryorfabric.extmemoryuse[]for fixed memory-interface structure andattributes {}for region programming such asaddr_offset_table
Structural attributes are not part of this split. Names and type metadata such
as sym_name, module symbol references, and function_type remain part of
the operation's structural syntax.
One additional structural attribute is currently standardized for visualization:
fabric.modulemay carryattributes {viz_file = "..."}to reference a sidecar JSON file that provides explicit visualization layout metadata
viz_file is neither a hardware parameter nor runtime configuration. It is a
structural pointer consumed by visualization tooling.