+ );
+}
+
+function AdmonitionContent({ children }: Pick) {
+ return children ? (
+
{children}
+ ) : null;
+}
+
+export default function AdmonitionLayout(props: Props): ReactNode {
+ const { type, icon, title, children, className } = props;
+ return (
+
+ {title || icon ? : null}
+ {children}
+
+ );
+}
diff --git a/docs/external/src/theme/Admonition/Layout/styles.module.css b/docs/external/src/theme/Admonition/Layout/styles.module.css
new file mode 100644
index 000000000..88df7e639
--- /dev/null
+++ b/docs/external/src/theme/Admonition/Layout/styles.module.css
@@ -0,0 +1,35 @@
+.admonition {
+ margin-bottom: 1em;
+}
+
+.admonitionHeading {
+ font: var(--ifm-heading-font-weight) var(--ifm-h5-font-size) /
+ var(--ifm-heading-line-height) var(--ifm-heading-font-family);
+ text-transform: uppercase;
+}
+
+/* Heading alone without content (does not handle fragment content) */
+.admonitionHeading:not(:last-child) {
+ margin-bottom: 0.3rem;
+}
+
+.admonitionHeading code {
+ text-transform: none;
+}
+
+.admonitionIcon {
+ display: inline-block;
+ vertical-align: middle;
+ margin-right: 0.4em;
+}
+
+.admonitionIcon svg {
+ display: inline-block;
+ height: 1.6em;
+ width: 1.6em;
+ fill: var(--ifm-alert-foreground-color);
+}
+
+.admonitionContent > :last-child {
+ margin-bottom: 0;
+}
diff --git a/docs/external/src/theme/Admonition/Type/Caution.tsx b/docs/external/src/theme/Admonition/Type/Caution.tsx
new file mode 100644
index 000000000..b570a37a9
--- /dev/null
+++ b/docs/external/src/theme/Admonition/Type/Caution.tsx
@@ -0,0 +1,32 @@
+import React, {type ReactNode} from 'react';
+import clsx from 'clsx';
+import Translate from '@docusaurus/Translate';
+import type {Props} from '@theme/Admonition/Type/Caution';
+import AdmonitionLayout from '@theme/Admonition/Layout';
+import IconWarning from '@theme/Admonition/Icon/Warning';
+
+const infimaClassName = 'alert alert--warning';
+
+const defaultProps = {
+ icon: ,
+ title: (
+
+ caution
+
+ ),
+};
+
+// TODO remove before v4: Caution replaced by Warning
+// see https://github.com/facebook/docusaurus/issues/7558
+export default function AdmonitionTypeCaution(props: Props): ReactNode {
+ return (
+
+ {props.children}
+
+ );
+}
diff --git a/docs/external/src/theme/Admonition/Type/Danger.tsx b/docs/external/src/theme/Admonition/Type/Danger.tsx
new file mode 100644
index 000000000..49901fa91
--- /dev/null
+++ b/docs/external/src/theme/Admonition/Type/Danger.tsx
@@ -0,0 +1,30 @@
+import React, {type ReactNode} from 'react';
+import clsx from 'clsx';
+import Translate from '@docusaurus/Translate';
+import type {Props} from '@theme/Admonition/Type/Danger';
+import AdmonitionLayout from '@theme/Admonition/Layout';
+import IconDanger from '@theme/Admonition/Icon/Danger';
+
+const infimaClassName = 'alert alert--danger';
+
+const defaultProps = {
+ icon: ,
+ title: (
+
+ danger
+
+ ),
+};
+
+export default function AdmonitionTypeDanger(props: Props): ReactNode {
+ return (
+
+ {props.children}
+
+ );
+}
diff --git a/docs/external/src/theme/Admonition/Type/Info.tsx b/docs/external/src/theme/Admonition/Type/Info.tsx
new file mode 100644
index 000000000..018e0a16d
--- /dev/null
+++ b/docs/external/src/theme/Admonition/Type/Info.tsx
@@ -0,0 +1,30 @@
+import React, {type ReactNode} from 'react';
+import clsx from 'clsx';
+import Translate from '@docusaurus/Translate';
+import type {Props} from '@theme/Admonition/Type/Info';
+import AdmonitionLayout from '@theme/Admonition/Layout';
+import IconInfo from '@theme/Admonition/Icon/Info';
+
+const infimaClassName = 'alert alert--info';
+
+const defaultProps = {
+ icon: ,
+ title: (
+
+ info
+
+ ),
+};
+
+export default function AdmonitionTypeInfo(props: Props): ReactNode {
+ return (
+
+ {props.children}
+
+ );
+}
diff --git a/docs/external/src/theme/Admonition/Type/Note.tsx b/docs/external/src/theme/Admonition/Type/Note.tsx
new file mode 100644
index 000000000..c99e03857
--- /dev/null
+++ b/docs/external/src/theme/Admonition/Type/Note.tsx
@@ -0,0 +1,30 @@
+import React, {type ReactNode} from 'react';
+import clsx from 'clsx';
+import Translate from '@docusaurus/Translate';
+import type {Props} from '@theme/Admonition/Type/Note';
+import AdmonitionLayout from '@theme/Admonition/Layout';
+import IconNote from '@theme/Admonition/Icon/Note';
+
+const infimaClassName = 'alert alert--secondary';
+
+const defaultProps = {
+ icon: ,
+ title: (
+
+ note
+
+ ),
+};
+
+export default function AdmonitionTypeNote(props: Props): ReactNode {
+ return (
+
+ {props.children}
+
+ );
+}
diff --git a/docs/external/src/theme/Admonition/Type/Tip.tsx b/docs/external/src/theme/Admonition/Type/Tip.tsx
new file mode 100644
index 000000000..18604a5e9
--- /dev/null
+++ b/docs/external/src/theme/Admonition/Type/Tip.tsx
@@ -0,0 +1,30 @@
+import React, {type ReactNode} from 'react';
+import clsx from 'clsx';
+import Translate from '@docusaurus/Translate';
+import type {Props} from '@theme/Admonition/Type/Tip';
+import AdmonitionLayout from '@theme/Admonition/Layout';
+import IconTip from '@theme/Admonition/Icon/Tip';
+
+const infimaClassName = 'alert alert--success';
+
+const defaultProps = {
+ icon: ,
+ title: (
+
+ tip
+
+ ),
+};
+
+export default function AdmonitionTypeTip(props: Props): ReactNode {
+ return (
+
+ {props.children}
+
+ );
+}
diff --git a/docs/external/src/theme/Admonition/Type/Warning.tsx b/docs/external/src/theme/Admonition/Type/Warning.tsx
new file mode 100644
index 000000000..61d9597b6
--- /dev/null
+++ b/docs/external/src/theme/Admonition/Type/Warning.tsx
@@ -0,0 +1,30 @@
+import React, {type ReactNode} from 'react';
+import clsx from 'clsx';
+import Translate from '@docusaurus/Translate';
+import type {Props} from '@theme/Admonition/Type/Warning';
+import AdmonitionLayout from '@theme/Admonition/Layout';
+import IconWarning from '@theme/Admonition/Icon/Warning';
+
+const infimaClassName = 'alert alert--warning';
+
+const defaultProps = {
+ icon: ,
+ title: (
+
+ warning
+
+ ),
+};
+
+export default function AdmonitionTypeWarning(props: Props): ReactNode {
+ return (
+
+ {props.children}
+
+ );
+}
diff --git a/docs/external/src/theme/Admonition/Types.tsx b/docs/external/src/theme/Admonition/Types.tsx
new file mode 100644
index 000000000..2a1001900
--- /dev/null
+++ b/docs/external/src/theme/Admonition/Types.tsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import AdmonitionTypeNote from '@theme/Admonition/Type/Note';
+import AdmonitionTypeTip from '@theme/Admonition/Type/Tip';
+import AdmonitionTypeInfo from '@theme/Admonition/Type/Info';
+import AdmonitionTypeWarning from '@theme/Admonition/Type/Warning';
+import AdmonitionTypeDanger from '@theme/Admonition/Type/Danger';
+import AdmonitionTypeCaution from '@theme/Admonition/Type/Caution';
+import type AdmonitionTypes from '@theme/Admonition/Types';
+
+const admonitionTypes: typeof AdmonitionTypes = {
+ note: AdmonitionTypeNote,
+ tip: AdmonitionTypeTip,
+ info: AdmonitionTypeInfo,
+ warning: AdmonitionTypeWarning,
+ danger: AdmonitionTypeDanger,
+};
+
+// Undocumented legacy admonition type aliases
+// Provide hardcoded/untranslated retrocompatible label
+// See also https://github.com/facebook/docusaurus/issues/7767
+const admonitionAliases: typeof AdmonitionTypes = {
+ secondary: (props) => ,
+ important: (props) => ,
+ success: (props) => ,
+ caution: AdmonitionTypeCaution,
+};
+
+export default {
+ ...admonitionTypes,
+ ...admonitionAliases,
+};
diff --git a/docs/external/src/theme/Admonition/index.tsx b/docs/external/src/theme/Admonition/index.tsx
new file mode 100644
index 000000000..8f4225da2
--- /dev/null
+++ b/docs/external/src/theme/Admonition/index.tsx
@@ -0,0 +1,21 @@
+import React, {type ComponentType, type ReactNode} from 'react';
+import {processAdmonitionProps} from '@docusaurus/theme-common';
+import type {Props} from '@theme/Admonition';
+import AdmonitionTypes from '@theme/Admonition/Types';
+
+function getAdmonitionTypeComponent(type: string): ComponentType {
+ const component = AdmonitionTypes[type];
+ if (component) {
+ return component;
+ }
+ console.warn(
+ `No admonition component found for admonition type "${type}". Using Info as fallback.`,
+ );
+ return AdmonitionTypes.info!;
+}
+
+export default function Admonition(unprocessedProps: Props): ReactNode {
+ const props = processAdmonitionProps(unprocessedProps);
+ const AdmonitionTypeComponent = getAdmonitionTypeComponent(props.type);
+ return ;
+}
diff --git a/docs/external/src/usage/_category_.yml b/docs/external/src/usage/_category_.yml
new file mode 100644
index 000000000..bb98c44f6
--- /dev/null
+++ b/docs/external/src/usage/_category_.yml
@@ -0,0 +1,4 @@
+label: Usage
+# Determines where this documentation section appears relative to other sections in the parent folder
+position: 2
+collapsed: true
diff --git a/docs/src/usage/cargo-miden.md b/docs/external/src/usage/cargo-miden.md
similarity index 88%
rename from docs/src/usage/cargo-miden.md
rename to docs/external/src/usage/cargo-miden.md
index 902999629..944da6b7d 100644
--- a/docs/src/usage/cargo-miden.md
+++ b/docs/external/src/usage/cargo-miden.md
@@ -1,3 +1,8 @@
+---
+title: As a Cargo extension
+sidebar_position: 3
+---
+
# Getting started with Cargo
As part of the Miden compiler toolchain, we provide a Cargo extension, `cargo-miden`, which provides
@@ -6,16 +11,19 @@ a template to spin up a new Miden project in Rust, and takes care of orchestrati
## Installation
-> [!WARNING]
-> Currently, `midenc` (and as a result, `cargo-miden`), requires the nightly Rust toolchain, so
-> make sure you have it installed first:
->
-> ```bash
-> rustup toolchain install nightly-2025-07-20
-> ```
->
-> NOTE: You can also use the latest nightly, but the specific nightly shown here is known to
-> work.
+:::warning
+
+Currently, `midenc` (and as a result, `cargo-miden`), requires the nightly Rust toolchain, so
+make sure you have it installed first:
+
+```bash
+rustup toolchain install nightly-2025-07-20
+```
+
+NOTE: You can also use the latest nightly, but the specific nightly shown here is known to
+work.
+
+:::
To install the extension, clone the compiler repo first:
@@ -49,6 +57,7 @@ cargo miden example --help
```
Available examples include:
+
- **basic-wallet** - A basic wallet account implementation (creates both the wallet and a paired p2id-note)
- **p2id-note** - A pay-to-ID note script (creates both the note and a paired basic-wallet)
- **counter-contract** - A simple counter contract (creates both the contract and a paired counter-note)
@@ -94,13 +103,13 @@ cargo miden build --release
This will emit the compiled artifacts to `target/miden/release/foo.masp`.
-
## Running a compiled Miden VM program
+:::warning
-> [!WARNING]
-> To run the compiled Miden VM program you need to have `midenc` installed. See [`midenc` docs](./midenc.md) for the installation instructions.
+To run the compiled Miden VM program you need to have `midenc` installed. See [`midenc` docs](./midenc.md) for the installation instructions.
+:::
The compiled Miden VM program can be run from the Miden package with the following:
@@ -110,8 +119,6 @@ midenc run target/miden/release/foo.masp --inputs some_inputs.toml
See `midenc run --help` for the inputs file format.
-
-
## Examples
Check out the [examples](https://github.com/0xMiden/compiler/tree/next/examples) for some `cargo-miden` project examples.
diff --git a/docs/src/usage/index.md b/docs/external/src/usage/index.md
similarity index 91%
rename from docs/src/usage/index.md
rename to docs/external/src/usage/index.md
index 4b111812c..10bbd762f 100644
--- a/docs/src/usage/index.md
+++ b/docs/external/src/usage/index.md
@@ -1,3 +1,8 @@
+---
+title: Usage
+sidebar_position: 1
+---
+
# Usage
The Usage section documents how to work with Miden's compiler tools. Key components include:
@@ -6,4 +11,3 @@ The Usage section documents how to work with Miden's compiler tools. Key compone
control over compilation outputs and diagnostic information
- **Cargo extension** ([`cargo-miden`](./cargo-miden.md)) - Higher-level build tool integration for
managing Miden projects within Rust's package ecosystem
-
diff --git a/docs/src/usage/midenc.md b/docs/external/src/usage/midenc.md
similarity index 60%
rename from docs/src/usage/midenc.md
rename to docs/external/src/usage/midenc.md
index 8ea28a7a8..3fdab5b19 100644
--- a/docs/src/usage/midenc.md
+++ b/docs/external/src/usage/midenc.md
@@ -1,3 +1,8 @@
+---
+title: As an Executable
+sidebar_position: 2
+---
+
# Getting started with `midenc`
The `midenc` executable is the command-line interface for the compiler driver, as well as other
@@ -11,18 +16,19 @@ hands dirty.
## Installation
+:::warning
+
+Currently, `midenc` (and as a result, `cargo-miden`), requires the nightly Rust toolchain, so
+make sure you have it installed first:
+
+```bash
+rustup toolchain install nightly-2025-07-20
+```
-> [!WARNING]
-> Currently, `midenc` (and as a result, `cargo-miden`), requires the nightly Rust toolchain, so
-> make sure you have it installed first:
->
-> ```bash
-> rustup toolchain install nightly-2025-07-20
-> ```
->
-> NOTE: You can also use the latest nightly, but the specific nightly shown here is known to
-> work.
+NOTE: You can also use the latest nightly, but the specific nightly shown here is known to
+work.
+:::
To install the `midenc`, clone the compiler repo first:
@@ -36,49 +42,49 @@ Then, run the following in your shell in the cloned repo folder:
cargo install --path midenc --locked
```
-
## Usage
Once installed, you should be able to invoke the compiler, you should see output similar to this:
- midenc help compile
- Usage: midenc compile [OPTIONS] [-- ...]
-
- Arguments:
- [INPUTS]...
- Path(s) to the source file(s) to compile.
+```bash
+midenc help compile
+Usage: midenc compile [OPTIONS] [-- ...]
- You may also use `-` as a file name to read a file from stdin.
+Arguments:
+ [INPUTS]...
+ Path(s) to the source file(s) to compile.
- Options:
- --output-dir
- Write all compiler artifacts to DIR
+ You may also use `-` as a file name to read a file from stdin.
- -W
- Modify how warnings are treated by the compiler
+Options:
+ --output-dir
+ Write all compiler artifacts to DIR
- [default: auto]
+ -W
+ Modify how warnings are treated by the compiler
- Possible values:
- - none: Disable all warnings
- - auto: Enable all warnings
- - error: Promotes warnings to errors
+ [default: auto]
- -v, --verbose
- When set, produces more verbose output during compilation
+ Possible values:
+ - none: Disable all warnings
+ - auto: Enable all warnings
+ - error: Promotes warnings to errors
- -h, --help
- Print help (see a summary with '-h')
+ -v, --verbose
+ When set, produces more verbose output during compilation
+ -h, --help
+ Print help (see a summary with '-h')
+```
The actual help output covers quite a bit more than shown here, this is just for illustrative
purposes.
The `midenc` executable supports two primary functions at this time:
-* `midenc compile` to compile one of our supported input formats to Miden Assembly
-* `midenc debug` to run a Miden program attached to an interactive debugger
-* `midenc run` to run a Miden program non-interactively, equivalent to `miden run`
+- `midenc compile` to compile one of our supported input formats to Miden Assembly
+- `midenc debug` to run a Miden program attached to an interactive debugger
+- `midenc run` to run a Miden program non-interactively, equivalent to `miden run`
## Compilation
@@ -106,23 +112,23 @@ and to add the `./masm` directory to the library search path.
Lastly, we're configuring the output:
-* We're using `--emit` to request `midenc` to dump Miden IR (`hir`) to stdout (specified via the `-`
-shorthand), in addition to the Miden package artifact (`masp`).
-* We're telling `midenc` to write the compiled output to `out.masp` in the current directory, rather
-than the default path that would have been used (`target/miden/foo.masp`).
+- We're using `--emit` to request `midenc` to dump Miden IR (`hir`) to stdout (specified via the `-`
+ shorthand), in addition to the Miden package artifact (`masp`).
+- We're telling `midenc` to write the compiled output to `out.masp` in the current directory, rather
+ than the default path that would have been used (`target/miden/foo.masp`).
## Debugging
-See [Debugging Programs](debugger.md) for details on using `midenc debug` to debug Miden programs.
+See [Debugging Programs](../guides/debugger.md) for details on using `midenc debug` to debug Miden programs.
## Next steps
We have put together two useful guides to walk through more detail on compiling Rust to WebAssembly:
1. To learn how to compile Rust to WebAssembly so that you can invoke `midenc compile` on the
-resulting Wasm module, see [this guide](../guides/rust_to_wasm.md).
+ resulting Wasm module, see [this guide](../guides/rust_to_wasm.md).
2. If you already have a WebAssembly module, or know how to produce one, and want to learn how to
-compile it to Miden Assembly, see [this guide](../guides/wasm_to_masm.md).
+ compile it to Miden Assembly, see [this guide](../guides/wasm_to_masm.md).
You may also be interested in our [basic account project template](https://github.com/0xMiden/rust-templates/tree/main/account/template),
as a starting point for your own Rust project.
diff --git a/docs/external/static/img/custom_caret.svg b/docs/external/static/img/custom_caret.svg
new file mode 100644
index 000000000..0480cf1c4
--- /dev/null
+++ b/docs/external/static/img/custom_caret.svg
@@ -0,0 +1,3 @@
+
diff --git a/docs/external/static/img/favicon.ico b/docs/external/static/img/favicon.ico
new file mode 100644
index 000000000..732d35222
Binary files /dev/null and b/docs/external/static/img/favicon.ico differ
diff --git a/docs/external/static/img/logo.png b/docs/external/static/img/logo.png
new file mode 100644
index 000000000..35e949756
Binary files /dev/null and b/docs/external/static/img/logo.png differ
diff --git a/docs/external/styles.css b/docs/external/styles.css
new file mode 100644
index 000000000..297366633
--- /dev/null
+++ b/docs/external/styles.css
@@ -0,0 +1,1046 @@
+/* Import Google Fonts */
+@import url("https://fonts.googleapis.com/css2?family=DM+Mono:ital,wght@0,300;0,400;0,500;1,300;1,400;1,500&display=swap");
+@import url("https://fonts.googleapis.com/css2?family=Geist:wght@100..900&display=swap");
+
+/* ============================
+ 0) SEMANTIC TOKENS (your brand)
+ ============================ */
+
+:root {
+ /* ---- Brand palette (LIGHT) ---- */
+ --color-brand: #ff5500; /* TODO: replace with your primary */
+ --color-brand-600: #ff6a26; /* TODO */
+ --color-brand-700: #e24c00; /* TODO */
+ --color-brand-800: #b63c00; /* TODO */
+ --color-secondary: #102445;
+
+ --color-accent: #1764a8; /* TODO secondary/accent */
+ --color-success: #00871d;
+ --color-warning: #ff5500;
+ --color-danger: #ff0000;
+
+ /* ---- Neutral & Surfaces ---- */
+ --color-bg: #ffffff;
+ --color-surface: #f9f9f9;
+ --color-elevated: color-mix(in oklab, #000 5%, transparent);
+ --color-border: color-mix(in oklab, #000 20%, transparent);
+ --color-text: #363636;
+ --color-muted: color-mix(in oklab, var(--color-text) 70%, transparent);
+ --color-link: var(--color-brand);
+
+ /* ---- Typography ---- */
+ --font-sans: "Geist", ui-sans-serif, system-ui, sans-serif,
+ "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+ --font-mono: "DM Mono", ui-monospace, SFMono-Regular, Menlo, Consolas,
+ "Liberation Mono", monospace;
+ --font-size-base: 14px;
+ --line-height-base: 150%;
+ --letter-spacing-base: 0;
+
+ /* ---- Radii & Spacing ---- */
+ --radius-xs: 5px;
+ --radius-md: 5px;
+ --radius-lg: 5px;
+ --radius-xl: 5px;
+
+ /* Design system spacing - exact pixel values */
+ --space-4px: 4px; /* Inline code padding */
+ --space-16px: 16px; /* Standard paragraph, list, heading spacing */
+ --space-24px: 24px; /* H1 to first content, H2 to large components, list indent */
+ --space-32px: 32px; /* Section breaks, major structural spacing */
+ --space-40px: 40px; /* Major structural reset (lower bound) */
+ --space-48px: 48px; /* Major structural reset (upper bound) */
+
+ /* Legacy spacing variables for compatibility */
+ --space-1: 0.25rem; /* 4px */
+ --space-2: 0.5rem; /* 8px */
+ --space-3: 0.75rem; /* 12px */
+ --space-4: 1rem; /* 16px */
+ --space-5: 1.25rem; /* 20px */
+ --space-6: 1.5rem; /* 24px */
+ --space-8: 2rem; /* 32px */
+ --space-10: 2.5rem; /* 40px */
+
+ /* ---- Shadows ---- */
+ --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.06);
+ --shadow-md: 0 6px 16px rgba(0, 0, 0, 0.08);
+ --shadow-lg: 0 12px 28px rgba(0, 0, 0, 0.12);
+
+ /* ---- Container widths ---- */
+
+ /* Common layout sizes */
+ --navbar-height: 64px;
+
+ /* Docs sidebar width */
+ --doc-sidebar-width: 250px !important;
+}
+
+/* ==========================================
+ 1) MAP SEMANTIC → INFIMA (core variables)
+ ========================================== */
+
+:root {
+ /* Brand */
+ --ifm-color-primary: var(--color-brand);
+ --ifm-color-secondary: var(--color-secondary);
+ --ifm-color-primary-dark: var(--color-brand-700);
+ --ifm-color-primary-darker: var(--color-brand-800);
+ --ifm-color-primary-darkest: var(--color-brand-800);
+ --ifm-color-primary-light: var(--color-brand-600);
+ --ifm-color-primary-lighter: var(--color-brand-600);
+ --ifm-color-primary-lightest: var(--color-brand-600);
+
+ /* Text & surfaces */
+ --ifm-color-content: var(--color-text);
+ --ifm-color-content-secondary: var(--color-muted);
+ --ifm-link-color: var(--color-link);
+ --ifm-background-color: var(--color-bg);
+ --ifm-background-surface-color: var(--color-surface);
+
+ /* Typography */
+ --ifm-font-family-base: var(--font-sans);
+ --ifm-font-family-monospace: var(--font-mono);
+ --ifm-font-size-base: var(--font-size-base);
+ --ifm-line-height-base: var(--line-height-base);
+ --ifm-font-weight-base: 400;
+ --ifm-heading-font-weight: 700;
+
+ /* Heading typography specifications */
+ --ifm-h1-font-size: 28px;
+ --ifm-h1-line-height: 32px;
+ --ifm-h2-font-size: 24px;
+ --ifm-h2-line-height: 28px;
+ --ifm-h3-font-size: 20px;
+ --ifm-h3-line-height: 24px;
+ --ifm-h4-font-size: 16px;
+ --ifm-h4-line-height: 16px;
+
+ /* Code typography specifications */
+ --ifm-code-font-size: 14px;
+ --ifm-code-line-height: 150%;
+ --ifm-code-letter-spacing: -2%;
+ --ifm-code-padding-horizontal: 4px;
+ --ifm-code-padding-vertical: 4px;
+
+ /* Layout & spacing */
+ --ifm-spacing-horizontal: var(--space-4);
+ --ifm-global-radius: var(--radius-md);
+
+ /* Component radii (Infima) */
+ --ifm-breadcrumb-border-radius: var(--radius-md);
+ --ifm-button-border-radius: var(--radius-md);
+ --ifm-card-border-radius: var(--radius-md);
+ --ifm-alert-border-radius: var(--radius-md);
+ --ifm-badge-border-radius: var(--radius-md);
+ --ifm-tabs-border-radius: var(--radius-md);
+ --ifm-table-border-radius: var(--radius-md);
+ --ifm-code-border-radius: var(--radius-md);
+
+ /* Sizes */
+ --ifm-container-width: var(--container-width);
+ --ifm-navbar-height: var(--navbar-height);
+ --ifm-menu-link-padding-horizontal: 6px;
+ --ifm-menu-link-padding-vertical: 12px;
+
+ /* Borders & shadows */
+ --ifm-border-color: var(--color-border);
+ --ifm-card-box-shadow: var(--shadow-md);
+ --ifm-global-shadow-lw: var(--shadow-sm);
+ --ifm-global-shadow-md: var(--shadow-md);
+ --ifm-global-shadow-tl: var(--shadow-lg);
+
+ /* Tables */
+ --ifm-table-cell-padding: 0.75rem;
+
+ /* Alerts */
+ --ifm-alert-background-color: var(--color-elevated);
+ --ifm-alert-border-color: var(--color-border);
+
+ /* Breadcrumbs */
+ --ifm-breadcrumb-color-active: var(--color-text);
+ --ifm-breadcrumb-item-background-active: var(--color-elevated);
+}
+
+/* ==========================================
+ 2) BASE ELEMENTS
+ ========================================== */
+
+html,
+body {
+ font-family: var(--ifm-font-family-base);
+ font-size: var(--ifm-font-size-base);
+ font-weight: var(--ifm-font-weight-base);
+ line-height: var(--ifm-line-height-base);
+ color: var(--ifm-color-content);
+ background: var(--ifm-background-color);
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+}
+
+/* Remove underlines from all links by default */
+a {
+ color: var(--ifm-link-color);
+ text-decoration: none;
+}
+
+/* Add underlines only to links within text content */
+p a,
+li a,
+blockquote a,
+.theme-doc-markdown a,
+.markdown a,
+article a,
+main a {
+ text-decoration: underline;
+ text-decoration-color: var(--ifm-link-color);
+ text-underline-offset: 0.2em;
+}
+
+/* Hover effects for text links */
+p a:hover,
+li a:hover,
+blockquote a:hover,
+.theme-doc-markdown a:hover,
+.markdown a:hover,
+article a:hover,
+main a:hover {
+ text-decoration-color: currentColor;
+}
+
+/* Ensure navigation links have no underlines */
+.navbar a,
+.theme-doc-sidebar-container a,
+.menu__link,
+.breadcrumbs__link,
+.pagination-nav__link,
+.table-of-contents a {
+ text-decoration: none !important;
+}
+
+/* Hover effects for navigation links */
+.navbar a:hover,
+.theme-doc-sidebar-container a:hover,
+.menu__link:hover,
+.breadcrumbs__link:hover,
+.pagination-nav__link:hover,
+.table-of-contents a:hover {
+ text-decoration: none !important;
+}
+
+/* Headings - exact design specifications */
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ font-family: var(--font-sans);
+ letter-spacing: 0em;
+ font-weight: bold;
+}
+
+/* H1: 28px font, 32px line height */
+h1 {
+ font-size: var(--ifm-h1-font-size);
+ line-height: var(--ifm-h1-line-height);
+}
+
+/* H2: 24px font, 28px line height */
+h2 {
+ font-size: var(--ifm-h2-font-size);
+ line-height: var(--ifm-h2-line-height);
+}
+
+/* H3: 20px font, 24px line height */
+h3 {
+ font-size: var(--ifm-h3-font-size);
+ line-height: var(--ifm-h3-line-height);
+}
+
+/* H4: 16px line height */
+h4 {
+ font-size: var(--ifm-h4-font-size);
+ line-height: var(--ifm-h4-line-height);
+}
+
+h5 {
+ font-size: 1.125rem;
+ line-height: 20px;
+}
+
+h6 {
+ font-size: 1rem;
+ text-transform: none;
+ line-height: 16px;
+}
+
+/* Bold text styling */
+strong,
+b {
+ font-weight: 600;
+ color: var(--ifm-color-content);
+}
+
+/* Body/Paragraph: 14px, 130% line height, Regular */
+p {
+ font-size: var(--ifm-font-size-base);
+ line-height: var(--line-height-base);
+ font-weight: 400;
+ letter-spacing: 0em;
+}
+
+/* Links (text): 14px, 130% line height, Semibold */
+a {
+ line-height: 130%;
+}
+
+/* List/Bulletpoints: 14-16px, 150% line height, Regular */
+ul {
+ list-style-type: disc;
+ line-height: 150%;
+}
+
+ul li::marker {
+ color: var(--color-border);
+}
+
+/* Nested unordered lists */
+ul ul {
+ list-style-type: circle;
+}
+
+ul ul ul {
+ list-style-type: square;
+}
+
+/* Ordered lists: 14-16px, 150% line height, Regular */
+ol {
+ list-style-type: decimal;
+ line-height: 150%;
+ font-size: var(--font-size-base);
+ font-weight: 400;
+}
+
+/* Nested ordered lists keep default styling */
+ol ol {
+ list-style-type: lower-alpha;
+}
+
+ol ol ol {
+ list-style-type: lower-roman;
+}
+
+/* Blockquote */
+blockquote {
+ border-left: 3px solid var(--ifm-color-primary);
+ background: var(--ifm-background-surface-color);
+ padding: var(--space-4);
+ border-radius: var(--radius-md);
+ color: var(--ifm-color-content);
+}
+
+/* Images */
+img {
+ border-radius: var(--radius-md);
+}
+
+/* ==========================================
+ 3) NAVBAR & FOOTER (scoped to stable classes)
+ ========================================== */
+
+/* ThemeClassNames.layout.navbar.container */
+.theme-layout-navbar {
+ height: var(--ifm-navbar-height);
+ backdrop-filter: saturate(1.1) blur(8px);
+ border-bottom: 1px solid var(--ifm-border-color) !important;
+ background: color-mix(in oklab, var(--ifm-background-color) 75%, transparent);
+ backdrop-filter: saturate(1.1) blur(8px);
+ box-shadow: none;
+}
+
+/* ThemeClassNames.layout.footer.container */
+.theme-layout-footer {
+ --ifm-footer-background-color: var(--color-elevated);
+ background: var(--ifm-footer-background-color);
+ color: var(--ifm-color-content);
+}
+
+/* ==========================================
+ 4) SIDEBAR (Docs)
+ ========================================== */
+
+/* ThemeClassNames.docs.docSidebarContainer */
+.theme-doc-sidebar-container {
+ border-right: 1px solid var(--ifm-border-color) !important;
+ padding: 5px;
+ font-size: 0.875rem; /* Sidebar-specific font size */
+}
+
+/* Main docs content area - wider to fill space */
+.theme-doc-markdown {
+ max-width: 100%; /* Use full available width */
+}
+
+/* ThemeClassNames.docs.docSidebarMenu */
+.theme-doc-sidebar-menu .menu__link {
+ font-family: var(--font-sans);
+ letter-spacing: -2%;
+ border-radius: var(--radius-md);
+ padding: var(--ifm-menu-link-padding-vertical)
+ var(--ifm-menu-link-padding-horizontal);
+}
+
+.theme-doc-sidebar-menu .menu__link--active {
+ color: var(--ifm-color-primary);
+ background: color-mix(
+ in oklab,
+ var(--ifm-background-surface-color) 70%,
+ transparent
+ );
+}
+.theme-doc-sidebar-menu .menu__link--active:hover {
+ background: var(--ifm-background-surface-color);
+}
+
+/* Category collapsible */
+.menu__list-item-collapsible {
+ border-radius: var(--radius-md);
+}
+
+/* ==========================================
+ 5) BREADCRUMBS
+ ========================================== */
+
+/* ThemeClassNames.docs.docBreadcrumbs */
+.theme-doc-breadcrumbs .breadcrumbs__link {
+ line-height: 150%;
+ border-radius: var(--radius-md);
+ padding: var(--ifm-menu-link-padding-horizontal)
+ var(--ifm-menu-link-padding-vertical);
+}
+
+.theme-doc-breadcrumbs .breadcrumbs__item--active .breadcrumbs__link {
+ color: var(--ifm-color-primary);
+}
+
+/* ==========================================
+ 6) BUTTONS
+ ========================================== */
+
+.button {
+ border-radius: var(--ifm-button-border-radius);
+ font-weight: 600;
+ letter-spacing: 0.01em;
+ box-shadow: 0 1px 0 rgba(0, 0, 0, 0.05);
+ line-height: 150%;
+}
+.button--outline:not(.button--link) {
+ border-color: color-mix(in oklab, var(--ifm-color-primary) 70%, transparent);
+}
+.button--link {
+ color: var(--ifm-link-color);
+}
+
+/* ==========================================
+ 7) BADGES
+ ========================================== */
+
+.badge {
+ border-radius: var(--ifm-badge-border-radius);
+ border: 1px solid var(--ifm-border-color);
+ background: var(--ifm-background-surface-color);
+}
+
+/* ==========================================
+ 8) ALERTS (Admonitions)
+ ========================================== */
+
+.theme-admonition {
+ display: flex;
+ align-items: flex-start; /* icon aligns with text top */
+ gap: 0.75rem; /* spacing between icon and text */
+ padding: 1rem 1.25rem;
+}
+
+/* ThemeClassNames.common.admonition */
+.theme-admonition.alert {
+ --ifm-alert-background-color: var(--color-elevated);
+ --ifm-alert-border-color: var(--ifm-color-primary);
+ --ifm-alert-background-color-highlight: #fff;
+
+ font-family: var(--font-mono);
+ border: 1px solid var(--color-elevated);
+ border-top: 5px solid var(--ifm-alert-border-color); /* top border accent */
+ border-left: none; /* disable default */
+ border-radius: var(--ifm-alert-border-radius);
+ box-shadow: none;
+ background: var(--ifm-alert-background-color);
+ color: var(--ifm-color-content);
+ /* padding: 1rem 1.25rem; */
+}
+
+/* NOTE */
+.theme-admonition.alert--secondary {
+ --ifm-alert-border-color: #df9f26;
+ border-top-color: #df9f26;
+}
+/* TIP */
+.theme-admonition.alert--success {
+ --ifm-alert-background-color: var(--color-elevated);
+ border-top-color: var(--ifm-color-success) !important;
+}
+/* INFO / IMPORTANT */
+.theme-admonition.alert--info {
+ --ifm-alert-border-color: #1764a8;
+ border-top-color: #1764a8;
+}
+/* WARNING */
+.theme-admonition.alert--warning {
+ --ifm-alert-border-color: var(--color-warning);
+ border-top-color: var(--color-warning);
+}
+
+/* DANGER */
+.theme-admonition.alert--danger {
+ --ifm-alert-border-color: var(--color-danger);
+ border-top-color: var(--color-danger);
+}
+
+.theme-admonition ul li::marker {
+ color: var(--ifm-color-primary);
+}
+
+/* Exclude list margins from alert blocks */
+.theme-admonition ul,
+.theme-admonition ol {
+ margin-top: 0 !important; /* Smaller margins for lists in alert blocks */
+ margin-bottom: 0 !important;
+ padding-left: 1.5rem !important; /* Standard padding for lists in alerts */
+}
+
+/* Nested lists in alert blocks should have no extra margin */
+.theme-admonition ul ul,
+.theme-admonition ol ol,
+.theme-admonition ul ol,
+.theme-admonition ol ul {
+ margin-top: 0 !important;
+ margin-bottom: 0 !important;
+}
+
+/* VERSION BANNER */
+.theme-doc-version-banner {
+ --ifm-alert-background-color: var(--color-elevated);
+ --ifm-alert-border-color: var(--color-warning);
+
+ font-family: var(--font-mono);
+ border: 1px solid var(--color-elevated);
+ border-top: 6px solid var(--ifm-alert-border-color);
+ border-left: none; /* disable default */
+ color: var(--ifm-color-content);
+}
+
+/* ==========================================
+ 9) TABS
+ ========================================== */
+
+/* ThemeClassNames.tabs.container */
+.theme-tabs-container .tabs {
+ --ifm-tabs-padding-vertical: 0.375rem;
+ --ifm-tabs-padding-horizontal: 0.75rem;
+}
+.theme-tabs-container .tabs__item {
+ border-radius: var(--ifm-tabs-border-radius);
+}
+.theme-tabs-container .tabs__item--active {
+ background: var(--ifm-background-surface-color);
+ box-shadow: inset 0 0 0 2px
+ color-mix(in oklab, var(--ifm-color-primary) 24%, transparent);
+}
+
+/* ==========================================
+ 10) CARDS
+ ========================================== */
+
+.card {
+ border-radius: var(--ifm-card-border-radius);
+ box-shadow: var(--ifm-card-box-shadow);
+ border: 1px solid var(--ifm-border-color);
+ background: var(--ifm-background-surface-color);
+}
+
+/* ==========================================
+ 11) TABLES
+ ========================================== */
+
+/* Apply border radius to the entire table */
+table {
+ border-radius: 5px; /* Adjust this value to change corner rounding */
+}
+
+tbody tr {
+ border-top: none;
+ background: var(--ifm-background-surface-color);
+}
+
+/* =========================
+ 12. Code block card + header
+ ========================= */
+
+.theme-code-block {
+ border: 1px solid var(--ifm-border-color);
+ border-radius: 5px;
+ position: relative;
+}
+
+/* Target CSS module class using attribute selector to handle hashed names */
+.theme-code-block [class*="codeBlockTitle"] {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 10px 12px;
+ font-family: var(--font-sans) !important;
+ font-size: 0.875rem !important;
+ font-weight: 500 !important;
+ letter-spacing: 0.02rem !important;
+ color: var(--color-base) !important;
+ border-bottom: 1px solid var(--ifm-border-color) !important;
+}
+
+/* Body */
+.theme-code-block pre {
+ margin: 0;
+ background: color-mix(
+ in oklab,
+ var(--color-surface) 96%,
+ var(--color-bg, #fff)
+ );
+ padding: 16px 18px;
+}
+
+/* Code text - design specifications */
+.theme-code-block code {
+ background: transparent;
+ border: 0;
+ border-radius: 0;
+ padding: 0;
+ font-family: var(--font-mono);
+ font-size: var(--ifm-code-font-size); /* 14px */
+ line-height: var(--ifm-code-line-height); /* 24px */
+ letter-spacing: var(--ifm-code-letter-spacing); /* -2% */
+ color: var(--color-text);
+}
+
+/* Inline code - design specifications */
+code {
+ font-family: var(--font-mono);
+ font-size: 12px; /* 14px */
+ line-height: 24px; /* 24px */
+ letter-spacing: var(--ifm-code-letter-spacing); /* -2% */
+ font-weight: 400;
+}
+
+/* Highlighted lines / magic comments */
+.token-line.highlighted,
+.code-block-highlighted-line {
+ background: color-mix(in oklab, var(--ifm-color-primary) 12%, transparent);
+}
+
+/* Optional: softer $ prompt tint in bash */
+.theme-code-block[data-language="bash"] pre code .token.operator {
+ opacity: 0.9;
+}
+
+/* Dark tweaks */
+[data-theme="dark"] .theme-code-block .codeBlockTitle {
+ background: color-mix(in oklab, var(--color-surface) 85%, transparent);
+}
+
+/* ==========================================
+ 12.1) DETAILS/SUMMARY (Expandable Sections) - styled like code blocks
+ ========================================== */
+
+/* Scope to docs content only */
+.theme-doc-markdown details {
+ border: 1px solid var(--ifm-border-color);
+ border-radius: 5px;
+ background: var(--ifm-background-surface-color);
+ margin: 0.75rem 0 1rem;
+ overflow: hidden; /* crisp rounded corners */
+ padding: 0;
+}
+
+/* The clickable header row */
+.theme-doc-markdown details > summary {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 10px 12px;
+ font-weight: 500;
+ text-transform: uppercase;
+ font-family: var(--font-sans);
+ line-height: 1.5;
+ cursor: pointer;
+ list-style: none;
+ user-select: none;
+ color: var(--color-text);
+ border-bottom: 1px solid transparent;
+}
+
+/* Hide native disclosure marker */
+.theme-doc-markdown details > summary::marker,
+.theme-doc-markdown details > summary::-webkit-details-marker {
+ display: none;
+ content: "";
+}
+
+/* Custom caret icon */
+.theme-doc-markdown details > summary::before {
+ content: "";
+ width: 3px;
+ height: 3px;
+ flex-shrink: 0;
+ -webkit-mask: url("/img/custom_caret.svg") no-repeat center / contain;
+ mask: url("/img/custom_caret.svg") no-repeat center / contain;
+ background: currentColor;
+ transition: transform 0.15s ease;
+ transform: rotate(0deg);
+ transform-origin: center center; /* Rotate around its own center */
+ opacity: 0.8;
+ position: relative;
+ top: 0;
+}
+
+.theme-doc-markdown details[open] > summary {
+ border-bottom-color: var(--ifm-border-color);
+}
+
+/* Rotate caret when details is open */
+.theme-doc-markdown details[open] > summary::before {
+ transform: rotate(90deg);
+ transform-origin: center center; /* Keep center rotation when open */
+}
+
+/* Body content area */
+.theme-doc-markdown details > :not(summary) {
+ padding: 1rem;
+}
+
+/* Code block inside details (optional polish) */
+.theme-doc-markdown details pre {
+ margin: 0;
+ background: color-mix(in oklab, var(--color-surface) 96%, var(--color-bg));
+ border-radius: 6px;
+}
+
+.theme-doc-markdown details > summary {
+ border-top: none !important;
+ box-shadow: none !important;
+}
+
+[class^="collapsibleContent_"],
+[class*=" collapsibleContent_"] {
+ padding-top: 0 !important;
+ border-top: none !important;
+ box-shadow: none !important;
+}
+
+[class^="collapsibleContent_"]::before,
+[class*=" collapsibleContent_"]::before {
+ display: none !important;
+ content: none !important;
+}
+
+/* ==========================================
+ 13) PAGINATION
+ ========================================== */
+
+.pagination-nav__link {
+ border: 1px solid var(--ifm-border-color);
+ border-radius: var(--radius-md);
+ box-shadow: var(--ifm-global-shadow-lw);
+ background: var(--ifm-background-surface-color);
+ transition: all 0.2s ease;
+}
+
+/* Hide "Previous" and "Next" labels */
+.pagination-nav__sublabel {
+ display: none;
+}
+
+/* Main pagination link text - uppercase */
+.pagination-nav__label {
+ text-transform: uppercase;
+ font-weight: 500;
+ letter-spacing: 0.02em;
+ font-size: 1.2rem;
+ font-family: var(--font-mono);
+ color: color-mix(in oklab, #292929bf 75%, #000);
+}
+
+/* Arrow text characters (>> and <<) */
+.pagination-nav__link--prev::before,
+.pagination-nav__link--next::after {
+ color: var(--ifm-color-primary) !important;
+ font-weight: 700 !important;
+ font-size: 1.25rem !important;
+}
+
+/* If arrows are in a separate element */
+.pagination-nav__link .pagination-nav__icon,
+.pagination-nav__link--prev .pagination-nav__icon,
+.pagination-nav__link--next .pagination-nav__icon {
+ color: var(--ifm-color-primary) !important;
+}
+
+/* ==========================================
+ 14) TOC (right sidebar)
+ ========================================== */
+
+/* TOC links styling */
+.table-of-contents {
+ font-family: var(--font-sans);
+ letter-spacing: 0.01rem;
+ border-left: 1px solid var(--ifm-border-color);
+ padding-left: var(--space-4);
+ font-size: 0.875rem;
+}
+
+.table-of-contents__link {
+ color: var(--color-text);
+ display: block;
+ padding: 4px 0;
+}
+
+.table-of-contents__link--active {
+ color: var(--ifm-color-primary);
+ font-weight: 500;
+}
+
+/* ==========================================
+ 15) VERSION INDICATOR STYLING
+ ========================================== */
+
+/* Style the version indicator that appears above page content */
+.theme-doc-version-badge {
+ font-size: 0.75rem !important;
+ font-weight: 600 !important;
+ color: var(--ifm-color-primary) !important;
+ background: color-mix(
+ in oklab,
+ var(--ifm-color-primary) 12%,
+ transparent
+ ) !important;
+ border: 1px solid
+ color-mix(in oklab, var(--ifm-color-primary) 30%, transparent) !important;
+ border-radius: var(--radius-md) !important;
+ /* line-height: 0 !important; */
+ padding-top: 0.37rem !important;
+ display: inline-block !important;
+ text-transform: uppercase !important;
+ letter-spacing: 0.05em !important;
+ margin-top: 8px !important;
+ margin-bottom: 8px !important;
+}
+
+/* ==========================================
+ 16) LOCAL SEARCH STYLING
+ ========================================== */
+
+/* Local search modal styling - integrate with design system */
+.aa-Panel {
+ border-radius: var(--radius-md);
+ box-shadow: var(--shadow-lg);
+ border: 1px solid var(--color-border);
+ background: var(--color-bg);
+}
+
+.aa-Form {
+ border-radius: var(--radius-md);
+ background: var(--color-surface);
+ border: 1px solid var(--color-border);
+}
+
+.aa-Input {
+ font-family: var(--font-sans);
+ font-size: var(--font-size-base);
+ color: var(--color-text);
+ background: transparent;
+}
+
+.aa-Item {
+ border-radius: var(--radius-md);
+ color: var(--color-text);
+}
+
+.aa-Item[aria-selected="true"] {
+ background: var(--color-surface);
+}
+
+.aa-ItemContentTitle {
+ font-family: var(--font-sans);
+ font-weight: 600;
+ color: var(--color-text);
+}
+
+.aa-ItemContentDescription {
+ font-family: var(--font-sans);
+ color: var(--color-muted);
+}
+
+/* ==========================================
+ 17) NUMERED LISTS
+ ========================================== */
+
+/* === DOCUSAURUS "VitePress-style" numbered steps === */
+.steps {
+ counter-reset: step-counter;
+ list-style: none;
+ padding-left: 1.5rem;
+ margin-left: 2.5rem; /* Space for number badges and line */
+ margin-top: 1.5rem;
+ margin-bottom: 1.5rem;
+}
+.steps > ol,
+.steps > ul {
+ list-style: none;
+ margin-left: 0;
+ padding-left: 0;
+}
+.steps li {
+ counter-increment: step-counter;
+ position: relative;
+ margin-bottom: 2rem;
+ min-height: 2rem;
+}
+
+/* Number badge - dynamically aligns with first element */
+.steps li::before {
+ content: counter(step-counter);
+ position: absolute;
+ left: -4rem; /* Align with .steps margin-left */
+ top: 0.15rem; /* Slight offset for visual centering with text baseline */
+ width: 2rem;
+ min-height: 2rem;
+ border-radius: 0px;
+ background: var(--ifm-background-surface-color);
+ color: var(--color-text);
+ font-size: 1rem;
+ font-family: var(--font-mono);
+ padding: 0.3rem 0.4rem;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ border: 1px solid var(--ifm-border-color);
+ z-index: 2;
+ flex-shrink: 0;
+ line-height: 1;
+}
+
+/* All headings inside steps get proper spacing */
+.steps li > h1,
+.steps li > h2,
+.steps li > h3,
+.steps li > h4,
+.steps li > h5,
+.steps li > h6 {
+ margin-top: 0rem !important;
+ margin-bottom: 1.5rem !important;
+ line-height: 1.3 !important;
+ padding-top: 0.7rem !important;
+} /* Specific h5 styling (most common) */
+.steps li > h5 {
+ font-size: 1.15rem !important;
+ font-weight: 600 !important;
+} /* Style for all content inside step items */
+.steps li > * {
+ margin-bottom: 1rem;
+}
+.steps li > *:last-child {
+ margin-bottom: 0;
+}
+
+/* Paragraphs right after headings - reduce space */
+.steps li > h1 + p,
+.steps li > h2 + p,
+.steps li > h3 + p,
+.steps li > h4 + p,
+.steps li > h5 + p,
+.steps li > h6 + p {
+ margin-top: -0.75rem;
+}
+
+/* First paragraph without heading */
+.steps li > p:first-child {
+ margin-top: 0;
+} /* Code blocks within steps */
+.steps li pre,
+.steps li .theme-code-block {
+ margin-top: 0.75rem;
+ margin-bottom: 0.75rem;
+}
+
+/* Lists within steps */
+.steps li ul,
+.steps li ol {
+ margin-top: 0.5rem;
+ margin-bottom: 0.5rem;
+ padding-left: 1.5rem;
+} /* Admonitions within steps */
+.steps li .theme-admonition {
+ margin-top: 0.75rem;
+ margin-bottom: 0.75rem;
+}
+
+/* ==========================================
+ 18) DESIGN SYSTEM SPACING SPECIFICATIONS
+ ========================================== */
+
+/* Apply design system spacing to documentation content */
+.theme-doc-markdown h1 {
+ margin-bottom: var(--space-24px); /* H1 → First content block: 24px */
+}
+
+.theme-doc-markdown h2 {
+ margin-top: var(
+ --space-32px
+ ); /* H2 → previous section (major section break): 32px */
+ margin-bottom: var(--space-16px); /* H2 → Paragraph below: 16px */
+}
+
+.theme-doc-markdown h3 {
+ margin-bottom: var(--space-16px); /* H3 → Paragraph below: 16px */
+}
+
+.theme-doc-markdown h4 {
+ margin-bottom: var(--space-16px); /* H4 → Paragraph below: 16px */
+}
+
+/* Paragraph spacing */
+.theme-doc-markdown p {
+ margin-bottom: var(--space-16px); /* Paragraph → Paragraph: 16px */
+}
+
+/* List spacing */
+.theme-doc-markdown ul,
+.theme-doc-markdown ol {
+ margin-top: var(--space-16px); /* Paragraph → List: 16px */
+ margin-bottom: var(--space-16px); /* List → Next Paragraph: 16px */
+ padding-left: var(--space-24px); /* List indent: 24px */
+}
+
+/* H2 to large components (images, tables, diagrams) */
+.theme-doc-markdown h2 + img,
+.theme-doc-markdown h2 + table,
+.theme-doc-markdown h2 + .theme-admonition {
+ margin-top: var(--space-24px); /* H2 → large component: 24px */
+}
+
+/* Major structural reset for dramatic transitions */
+.theme-doc-markdown > *:first-child {
+ margin-top: 0;
+}
+
+/* Section breaks - ensure consistent spacing between major sections */
+.theme-doc-markdown h1 + h2 {
+ margin-top: var(--space-32px); /* Major section break */
+}
diff --git a/docs/external/tsconfig.json b/docs/external/tsconfig.json
new file mode 100644
index 000000000..920d7a652
--- /dev/null
+++ b/docs/external/tsconfig.json
@@ -0,0 +1,8 @@
+{
+ // This file is not used in compilation. It is here just for a nice editor experience.
+ "extends": "@docusaurus/tsconfig",
+ "compilerOptions": {
+ "baseUrl": "."
+ },
+ "exclude": [".docusaurus", "build"]
+}
diff --git a/docs/internal/.gitignore b/docs/internal/.gitignore
new file mode 100644
index 000000000..4e42a1bcd
--- /dev/null
+++ b/docs/internal/.gitignore
@@ -0,0 +1 @@
+book/
\ No newline at end of file
diff --git a/docs/internal/book.toml b/docs/internal/book.toml
new file mode 100644
index 000000000..81af25ac5
--- /dev/null
+++ b/docs/internal/book.toml
@@ -0,0 +1,18 @@
+[book]
+authors = ["Miden contributors"]
+description = "Internal documentation for the Miden compiler."
+language = "en"
+multilingual = false
+title = "Miden Compiler"
+
+[output.html]
+git-repository-url = "https://github.com/0xMiden/compiler"
+
+[preprocessor.katex]
+after = ["links"]
+
+[preprocessor.alerts]
+
+[output.linkcheck]
+follow-web-links = false
+traverse-parent-directories = true
diff --git a/docs/src/design/analyses.md b/docs/internal/src/analyses.md
similarity index 92%
rename from docs/src/design/analyses.md
rename to docs/internal/src/analyses.md
index bdbea3463..5b6e3eb53 100644
--- a/docs/src/design/analyses.md
+++ b/docs/internal/src/analyses.md
@@ -4,28 +4,27 @@ This document provides an overview of some of the current analysis passes the co
All analysis passes, at the time of writing, are maintained in the `midenc-hir-analysis` crate, with the exception of two, which are part of the core `midenc-hir` crate.
-* [Dominance](#dominance)
-* [Loop Forest](#loop-forest)
-* [Dead Code](#dead-code)
-* [Sparse Constant Propagation](#sparse-constant-propagation)
-* [Liveness](#liveness)
-* [Spills](#spills)
-
+- [Dominance](#dominance)
+- [Loop Forest](#loop-forest)
+- [Dead Code](#dead-code)
+- [Sparse Constant Propagation](#sparse-constant-propagation)
+- [Liveness](#liveness)
+- [Spills](#spills)
## Dominance
Dominance analysis is responsible for computing three data structures commonly used in a compiler operating over a control flow graph in SSA form:
-* [Dominance tree](#dominance-tree)
-* [Post-dominance tree](#post-dominance-tree)
-* [Iterated dominance frontier](#iterated-dominance-frontier)
+- [Dominance tree](#dominance-tree)
+- [Post-dominance tree](#post-dominance-tree)
+- [Iterated dominance frontier](#iterated-dominance-frontier)
What does dominance refer to in this context? Quite simply, it refers to the relationship between program points in a control flow graph. If all paths to a specific program point $B$, flow through a preceding program point $A$, then it can be said that $A$ _dominates_ $B$. Further, since any program point trivially dominates itself; when $A$ dominates $B$, and $A \neq B$, then $A$ is said to _properly dominate_ $B$. This distinction is occasionally important in the use of the computed dominance analysis.
We're particularly interested in dominance as it pertains to uses and definitions of values of a program in SSA form. SSA, or _single-static assignment_ form, requires that programs adhere to the following properties:
-* Values, once defined, are immutable - hence "single-static assignment". To "reassign" a value, you must introduce a new definition representing the changed value. This doesn't account for mutating heap-allocated types where the "value" in SSA is the pointer to the data in memory, it is strictly in reference to what is encoded as an SSA value.
-* Uses of a value must always be _properly dominated_ by the definition of that value, i.e. there cannot be any path through the control flow graph that reaches a use of a value, not preceded by its definition.
+- Values, once defined, are immutable - hence "single-static assignment". To "reassign" a value, you must introduce a new definition representing the changed value. This doesn't account for mutating heap-allocated types where the "value" in SSA is the pointer to the data in memory, it is strictly in reference to what is encoded as an SSA value.
+- Uses of a value must always be _properly dominated_ by the definition of that value, i.e. there cannot be any path through the control flow graph that reaches a use of a value, not preceded by its definition.
> [!NOTE]
> Values correspond to registers in an abstract machine with infinitely many of them. Thus the type of a value must be something that has a defined lowering to whatever targets you wish to support. In practice, this is fixed-width integers up to 128 bits, single- or double-precision floating point numbers, pointers, and structs that can be represented as a very small set of scalar values. The set of allowed types of SSA values is not strictly speaking a property of SSA, but it is almost always the case that the types do not include values that require memory allocation (except as a pointer).
@@ -56,16 +55,15 @@ Iterated dominance frontiers are especially useful when one needs to introduce n
We currently use this in our spills analysis/transformation, in order to do the very thing described above for each reload of a spilled value (which represent new definitions of the spilled value). We want to ensure that uses of the original value reachable from the reload, use the reload instead, thus terminating the live range of the spilled value at the point it is spilled.
-
## Loop Forest
The loop forest represents the set of loops identified in a given CFG, as well as their components:
-* Entering blocks (loop predecessor blocks), i.e. non-loop nodes that are predecessors of the loop header. If only one such block exists, it is called the _loop pre-header_.
-* Loop _header_, i.e. the block which dominates all other loop nodes.
-* _Latch_ nodes, i.e. a loop node that has an edge back to the loop header
-* _Exiting_ blocks, i.e. blocks which have a successor outside of the loop, but are inside the loop themselves.
-* _Exit_ blocks, i.e. a non-loop block which is the successor of an exiting block.
+- Entering blocks (loop predecessor blocks), i.e. non-loop nodes that are predecessors of the loop header. If only one such block exists, it is called the _loop pre-header_.
+- Loop _header_, i.e. the block which dominates all other loop nodes.
+- _Latch_ nodes, i.e. a loop node that has an edge back to the loop header
+- _Exiting_ blocks, i.e. blocks which have a successor outside of the loop, but are inside the loop themselves.
+- _Exit_ blocks, i.e. a non-loop block which is the successor of an exiting block.
Each block may only be the header for a single loop, and thus you can identify a loop by the header block.
@@ -79,8 +77,8 @@ We currently do not make heavy use of this, except to attach some loop metadata
The dead code analysis computes the following information about the IR:
-* Whether a block is _executable_, or _live_.
-* The set of known predecessors at certain program points (successors of a control flow op, entry points of a callable region, exit points of a call op), and whether those predecessors are executable.
+- Whether a block is _executable_, or _live_.
+- The set of known predecessors at certain program points (successors of a control flow op, entry points of a callable region, exit points of a call op), and whether those predecessors are executable.
This is a fundamental analysis in our data flow analysis framework, and it coordinates with the _sparse constant propagation_ analysis to refine its results. We build on this to more precisely compute other analyses based on the liveness of a particular program point, or predecessors to that point.
diff --git a/docs/src/design/codegen.md b/docs/internal/src/codegen.md
similarity index 100%
rename from docs/src/design/codegen.md
rename to docs/internal/src/codegen.md
diff --git a/docs/src/design/data_layout.md b/docs/internal/src/data_layout.md
similarity index 100%
rename from docs/src/design/data_layout.md
rename to docs/internal/src/data_layout.md
diff --git a/docs/src/design/frontends.md b/docs/internal/src/frontends.md
similarity index 100%
rename from docs/src/design/frontends.md
rename to docs/internal/src/frontends.md
diff --git a/docs/src/design/index.md b/docs/internal/src/index.md
similarity index 54%
rename from docs/src/design/index.md
rename to docs/internal/src/index.md
index 788aba761..d127c4903 100644
--- a/docs/src/design/index.md
+++ b/docs/internal/src/index.md
@@ -2,10 +2,10 @@
This document provides an index of the various design documents for the compiler itself, and its toolchain components. If you see something missing or lacking, please let us know what improvements to these documents you'd like to see!
-* [Frontends](frontends.md)
-* [Intermediate Representation (HIR)](ir.md)
-* [Data Layout](data_layout.md)
-* [Analyses](analyses.md)
-* [Rewrites](rewrites.md)
-* [Code Generation](codegen.md)
-* [Packaging](packaging.md)
+- [Frontends](frontends.md)
+- [Intermediate Representation (HIR)](ir.md)
+- [Data Layout](data_layout.md)
+- [Analyses](analyses.md)
+- [Rewrites](rewrites.md)
+- [Code Generation](codegen.md)
+- [Packaging](packaging.md)
diff --git a/docs/src/design/ir.md b/docs/internal/src/ir.md
similarity index 89%
rename from docs/src/design/ir.md
rename to docs/internal/src/ir.md
index a48eb7555..c07638f5f 100644
--- a/docs/src/design/ir.md
+++ b/docs/internal/src/ir.md
@@ -2,43 +2,43 @@
This document describes the concepts, usage, and overall structure of the intermediate representation used by `midenc` and its various components.
-* [Core Concepts](#core-concepts)
- * [Dialects](#dialects)
- * [Operations](#operations)
- * [Regions](#regions)
- * [Blocks](#blocks)
- * [Values](#values)
- * [Operands](#operands)
- * [Immediates](#immediates)
- * [Attributes](#attributes)
- * [Traits](#traits)
- * [Interfaces](#interfaces)
- * [Symbols](#symbols)
- * [Symbol Tables](#symbol-tables)
- * [Successors and Predecessors](#successors-and-predecessors)
-* [High-Level Structure](#high-level-structure)
-* [Pass Infrastructure](#pass-infrastructure)
- * [Analysis](#analysis)
- * [Pattern Rewrites](#pattern-rewrites)
- * [Canonicalization](#canonicalization)
- * [Folding](#folding)
-* [Implementation Details](#implementation-details)
- * [Session](#session)
- * [Context](#context)
- * [Entity References](#entity-references)
- * [Entity Storage](#entity-storage)
- * [StoreableEntity](#storeableentity)
- * [ValueRange](#valuerange)
- * [Entity Lists](#entity-lists)
- * [Traversal](#traversal)
- * [Program Points](#program-points)
- * [Defining Dialects](#defining-dialects)
- * [Dialect Registration](#dialect-registration)
- * [Dialect Hooks](#dialect-hooks)
- * [Defining Operations](#defining-operations)
- * [Builders](#builders)
- * [Validation](#validation)
- * [Effects](#effects)
+- [Core Concepts](#core-concepts)
+ - [Dialects](#dialects)
+ - [Operations](#operations)
+ - [Regions](#regions)
+ - [Blocks](#blocks)
+ - [Values](#values)
+ - [Operands](#operands)
+ - [Immediates](#immediates)
+ - [Attributes](#attributes)
+ - [Traits](#traits)
+ - [Interfaces](#interfaces)
+ - [Symbols](#symbols)
+ - [Symbol Tables](#symbol-tables)
+ - [Successors and Predecessors](#successors-and-predecessors)
+- [High-Level Structure](#high-level-structure)
+- [Pass Infrastructure](#pass-infrastructure)
+ - [Analysis](#analysis)
+ - [Pattern Rewrites](#pattern-rewrites)
+ - [Canonicalization](#canonicalization)
+ - [Folding](#folding)
+- [Implementation Details](#implementation-details)
+ - [Session](#session)
+ - [Context](#context)
+ - [Entity References](#entity-references)
+ - [Entity Storage](#entity-storage)
+ - [StoreableEntity](#storeableentity)
+ - [ValueRange](#valuerange)
+ - [Entity Lists](#entity-lists)
+ - [Traversal](#traversal)
+ - [Program Points](#program-points)
+ - [Defining Dialects](#defining-dialects)
+ - [Dialect Registration](#dialect-registration)
+ - [Dialect Hooks](#dialect-hooks)
+ - [Defining Operations](#defining-operations)
+ - [Builders](#builders)
+ - [Validation](#validation)
+ - [Effects](#effects)
## Core Concepts
@@ -48,10 +48,10 @@ MLIR, and by extension, HIR, are compiler intermediate representations based on
More concretely, the above entities relate to each other as follows:
-* Operations can contain regions, operands which represent input values, and results which represent output values.
-* Regions can contain [_basic blocks_](#blocks)
-* Blocks can contain operations, and may introduce values in the form of block arguments. See the [Basic Blocks](#blocks) section for more details.
-* Values from the edges of the data flow graph, i.e. operation A depends on B, if B produces a result that A consumes as an operand.
+- Operations can contain regions, operands which represent input values, and results which represent output values.
+- Regions can contain [_basic blocks_](#blocks)
+- Blocks can contain operations, and may introduce values in the form of block arguments. See the [Basic Blocks](#blocks) section for more details.
+- Values from the edges of the data flow graph, i.e. operation A depends on B, if B produces a result that A consumes as an operand.
As noted above, [operations](#operations) can represent both high-level and low-level concepts, e.g. both a function definition, and a function call. The semantics of an operation are encoded in the form of a wide variety of [_operation traits_](#traits), e.g. whether it is commutative, or idempotent; as well as a core set of [_operation interfaces_](#interfaces), e.g. there is an interface for side effects, unstructured/structured control flow operations, and more. This allows working with operations generically, i.e. you can write a control flow analysis without needing to handle every single control flow operation explicitly - instead, you can perform the analysis against a single interface (or set of interfaces that relate to each other), and any operation that implements the interface is automatically supported by the analysis.
@@ -59,13 +59,13 @@ Operations are organized into [dialects](#dialects). A dialect can be used to re
See the following sections for more information on the concepts introduced above:
-* [Dialects](#dialects)
-* [Operations](#operations)
-* [Regions](#regions)
-* [Blocks](#blocks)
-* [Values](#values)
-* [Traits](#traits)
-* [Interfaces](#interfaces)
+- [Dialects](#dialects)
+- [Operations](#operations)
+- [Regions](#regions)
+- [Blocks](#blocks)
+- [Values](#values)
+- [Traits](#traits)
+- [Interfaces](#interfaces)
### Dialects
@@ -73,13 +73,13 @@ A _dialect_ is a logical grouping of operations, attributes, and associated anal
There are currently a limited set of dialects, comprising the set of operations we currently have defined lowerings for, or can be converted to another dialect that does:
-* `builtin`, which provides the `World`, `Component`, `Module`, `Function`, `GlobalVariable`, `Segment`, and `Ret` operations.
-* `test`, used for testing within the compiler without external dependencies.
-* `ub`, i.e. _undefined behavior_, which provides the `Poison` (and associated attribute type), and `Unreachable` operations.
-* `arith`, i.e. _arithmetic_, which provides all of the mathematical operations we currently support lowerings for. This dialect also provides the `Constant` operation for all supported numeric types.
-* `cf`, i.e. _control flow_, which provides all of the unstructured control flow or control flow-adjacent operations, i.e. `Br`, `CondBr`, `Switch`, and `Select`. The latter is not strictly speaking a control flow operation, but is semantically similar. This dialect is largely converted to the `scf` dialect before lowering, with the exception of `Select`, and limited support for `CondBr` (to handle a specific edge case of the control flow lifting transformation).
-* `scf`, i.e. _structured control flow_, which provides structured equivalents of all the control flow we support, i.e. `If`, `While` (for both while/do and do/while loops), and `IndexSwitch` (essentially equivalent to `cf.switch`, but in structured form). The `Yield` and `Condition` operations are defined in this dialect to represent control flow within (or out of) a child region of one of the previous three ops.
-* `hir` (likely to be renamed to `masm` or `vm` in the near future), which is currently used to represent the set of operations unique to the Miden VM, or correspond to compiler intrinsics implemented in Miden Assembly.
+- `builtin`, which provides the `World`, `Component`, `Module`, `Function`, `GlobalVariable`, `Segment`, and `Ret` operations.
+- `test`, used for testing within the compiler without external dependencies.
+- `ub`, i.e. _undefined behavior_, which provides the `Poison` (and associated attribute type), and `Unreachable` operations.
+- `arith`, i.e. _arithmetic_, which provides all of the mathematical operations we currently support lowerings for. This dialect also provides the `Constant` operation for all supported numeric types.
+- `cf`, i.e. _control flow_, which provides all of the unstructured control flow or control flow-adjacent operations, i.e. `Br`, `CondBr`, `Switch`, and `Select`. The latter is not strictly speaking a control flow operation, but is semantically similar. This dialect is largely converted to the `scf` dialect before lowering, with the exception of `Select`, and limited support for `CondBr` (to handle a specific edge case of the control flow lifting transformation).
+- `scf`, i.e. _structured control flow_, which provides structured equivalents of all the control flow we support, i.e. `If`, `While` (for both while/do and do/while loops), and `IndexSwitch` (essentially equivalent to `cf.switch`, but in structured form). The `Yield` and `Condition` operations are defined in this dialect to represent control flow within (or out of) a child region of one of the previous three ops.
+- `hir` (likely to be renamed to `masm` or `vm` in the near future), which is currently used to represent the set of operations unique to the Miden VM, or correspond to compiler intrinsics implemented in Miden Assembly.
See [_defining dialects_](#defining-dialects) for more information on what dialects are responsible for in HIR.
@@ -97,7 +97,7 @@ Operations may also have associated [_attributes_](#attributes). Attributes repr
### Regions
-A _region_ encapsulates a control-flow graph (CFG) of one or more [_basic blocks_](#blocks). In HIR, the contents of a region are almost always in _single-static assignment_ (SSA) form, meaning that values may only be defined once, definitions must _dominate_ uses, and operations in the CFG described by the region are executed one-by-one, from the entry block of the region, until control exits the region (e.g. via `builtin.ret` or some other terminator instruction).
+A _region_ encapsulates a control-flow graph (CFG) of one or more [_basic blocks_](#blocks). In HIR, the contents of a region are almost always in _single-static assignment_ (SSA) form, meaning that values may only be defined once, definitions must _dominate_ uses, and operations in the CFG described by the region are executed one-by-one, from the entry block of the region, until control exits the region (e.g. via `builtin.ret` or some other terminator instruction).
The order of operations in the region closely corresponds to their scheduling order, though the code generator may reschedule operations when it is safe - and more efficient - to do so.
@@ -153,7 +153,7 @@ Similarly, the ordering of operand results also correlates to the operand stack
Immediates are a built-in [_attribute_](#attributes) type, which we use to represent constants that are able to be used as "immediate" operands of machine instructions (e.g. a literal memory address, or integer value).
-The `Immediate` type provides a number of useful APIs for interacting with an immediate value, such as bitcasts, conversions, and common queries, e.g. "is this a signed integer".
+The `Immediate` type provides a number of useful APIs for interacting with an immediate value, such as bitcasts, conversions, and common queries, e.g. "is this a signed integer".
It should be noted, that this type is a convenience, it is entirely possible to represent the same information using other types, e.g. `u32` rather than `Immediate::U32`, and the IR makes no assumptions about what type is used for constants in general. We do, however, assume this type is used for constants in specific dialects of the IR, e.g. `hir`.
@@ -163,14 +163,14 @@ Attributes represent named metadata attached to an _operation_.
Attributes can be used in two primary ways:
-* A name without a value, i.e. a "marker" attribute. In this case, the presence of the attribute is significant, e.g. `#[inline]`.
-* A name with a value, i.e. a "key-value" attribute. This is the more common usage, e.g. `#[overflow = wrapping]`.
+- A name without a value, i.e. a "marker" attribute. In this case, the presence of the attribute is significant, e.g. `#[inline]`.
+- A name with a value, i.e. a "key-value" attribute. This is the more common usage, e.g. `#[overflow = wrapping]`.
Any type that implements the `AttributeValue` trait can be used as the value of a key/value-style attribute. This trait is implemented by default for all integral types, as well as a handful of IR types which have been used as attributes. There are also a few generic built-in attribute types that you may be interested in:
-* `ArrayAttr`, which can represent an array/vector-like collection of attribute values, e.g. `#[indices = [1, 2, 3]]`.
-* `SetAttr`, which represents a set-like collection of attribute values. The primary difference between this and `ArrayAttr` is that the values are guaranteed to be unique.
-* `DictAttr`, which represents a map-like collection of attribute values.
+- `ArrayAttr`, which can represent an array/vector-like collection of attribute values, e.g. `#[indices = [1, 2, 3]]`.
+- `SetAttr`, which represents a set-like collection of attribute values. The primary difference between this and `ArrayAttr` is that the values are guaranteed to be unique.
+- `DictAttr`, which represents a map-like collection of attribute values.
It should be noted that there is no guarantee that attributes are preserved by transformations, i.e. if an operation is erased/replaced, attributes _may_ be lost in the process. As such, you must not assume that they will be preserved, unless made an intrinsic part of the operation definition.
@@ -182,11 +182,11 @@ Operations can always be cast to their implementing traits, as well as queried f
There are a number of predefined traits, found in `midenc_hir::traits`, e.g.:
-* `IsolatedFromAbove`, a marker trait that indicates that regions of the operation it is attached to cannot reference items from any parents, except via [_symbols_](#symbols).
-* `Terminator`, a marker trait for operations which are valid block terminators
-* `ReturnLike`, a trait that describes behavior shared by instructions that exit from an enclosing region, "returning" the results of executing that region. The most notable of these is `builtin.ret`, but `scf.yield` used by the structured control flow ops is also return-like in nature.
-* `ConstantLike`, a marker trait for operations that produce a constant value
-* `Commutative`, a marker trait for binary operations that exhibit commutativity, i.e. the order of the operands can be swapped without changing semantics.
+- `IsolatedFromAbove`, a marker trait that indicates that regions of the operation it is attached to cannot reference items from any parents, except via [_symbols_](#symbols).
+- `Terminator`, a marker trait for operations which are valid block terminators
+- `ReturnLike`, a trait that describes behavior shared by instructions that exit from an enclosing region, "returning" the results of executing that region. The most notable of these is `builtin.ret`, but `scf.yield` used by the structured control flow ops is also return-like in nature.
+- `ConstantLike`, a marker trait for operations that produce a constant value
+- `Commutative`, a marker trait for binary operations that exhibit commutativity, i.e. the order of the operands can be swapped without changing semantics.
### Interfaces
@@ -194,13 +194,13 @@ An _interface_, in contrast to a [_trait_](#traits), represents not only that an
Some key examples:
-* `EffectOpInterface`, operations whose side effects, or lack thereof, are well-specified. `MemoryEffectOpInterface` is a specialization of this interface specifically for operations with memory effects (e.g. read/write, alloc/free). This interface allows querying what effects an operation has, what resource the effect applies to (if known), or whether an operation affects a specific resource, and by what effect(s).
-* `CallableOpInterface`, operations which are "callable", i.e. can be targets of a call-like operation. This allows querying information about the callable, such as its signature, whether it is a declaration or definition, etc.
-* `CallOpInterface`, operations which can call a callable operation. This interface provides information about the call, and its callee.
-* `SelectOpInterface`, operations which represent a selection between two values based on a boolean condition. This interface allows operating on all select-like operations without knowing what dialect they are from.
-* `BranchOpInterface`, operations which implement an unstructured control flow branch from one block to one or more other blocks. This interface provides a generic means of accessing successors, successor operands, etc.
-* `RegionBranchOpInterface`, operations which implement structured control flow from themselves (the parent), to one of their regions (the children). Much like `BranchOpInterface`, this interface provides a generic means of querying which regions are successors on entry, which regions are successors of their siblings, whether a region is "repetitive", i.e. loops, and more.
-* `RegionBranchTerminatorOpInterface`, operations which represent control flow from some region of a `RegionBranchOpInterface` op, either to the parent op (e.g. returning/yielding), or to another region of that op (e.g. branching/yielding). Such operations are always children of a `RegionBranchOpInterface`, and conversely, the regions of a `RegionBranchOpInterface` must always terminate with an op that implements this interface.
+- `EffectOpInterface`, operations whose side effects, or lack thereof, are well-specified. `MemoryEffectOpInterface` is a specialization of this interface specifically for operations with memory effects (e.g. read/write, alloc/free). This interface allows querying what effects an operation has, what resource the effect applies to (if known), or whether an operation affects a specific resource, and by what effect(s).
+- `CallableOpInterface`, operations which are "callable", i.e. can be targets of a call-like operation. This allows querying information about the callable, such as its signature, whether it is a declaration or definition, etc.
+- `CallOpInterface`, operations which can call a callable operation. This interface provides information about the call, and its callee.
+- `SelectOpInterface`, operations which represent a selection between two values based on a boolean condition. This interface allows operating on all select-like operations without knowing what dialect they are from.
+- `BranchOpInterface`, operations which implement an unstructured control flow branch from one block to one or more other blocks. This interface provides a generic means of accessing successors, successor operands, etc.
+- `RegionBranchOpInterface`, operations which implement structured control flow from themselves (the parent), to one of their regions (the children). Much like `BranchOpInterface`, this interface provides a generic means of querying which regions are successors on entry, which regions are successors of their siblings, whether a region is "repetitive", i.e. loops, and more.
+- `RegionBranchTerminatorOpInterface`, operations which represent control flow from some region of a `RegionBranchOpInterface` op, either to the parent op (e.g. returning/yielding), or to another region of that op (e.g. branching/yielding). Such operations are always children of a `RegionBranchOpInterface`, and conversely, the regions of a `RegionBranchOpInterface` must always terminate with an op that implements this interface.
### Symbol Tables
@@ -270,10 +270,10 @@ We care about this when performing inter-procedural analyses, as it dictates how
Beyond the core IR concepts introduced in the previous section, HIR also imposes some hierarchical structure to programs in form of builtin operations that are special-cased in certain respects:
-* [Worlds](#worlds)
-* [Components](#components)
-* [Modules](#modules)
-* [Functions](#functions)
+- [Worlds](#worlds)
+- [Components](#components)
+- [Modules](#modules)
+- [Functions](#functions)
In short, when compiling a program, the inputs (source program, dependencies, etc.) are represented in a single _world_ (i.e. everything we know about that program and what is needed to compile it). The input program is then translated into a single top-level _component_ of that world, and any of it's dependendencies are represented in the form of component _declarations_ (in HIR, a declaration - as opposed to a definition - consists of just the metadata about a thing, not its implementation, e.g. a function signature).
@@ -284,9 +284,9 @@ A _component_ can contain one or more _modules_, and optionally, one or more _da
The terminology and semantics of worlds and components, are based on the Web Assembly [Component Model](https://component-model.bytecodealliance.org). In particular, the following properties are key to understanding the relationships between these entities:
-* Worlds must encode everything needed by a component
-* Components represent a shared-nothing boundary, i.e. nothing outside a component can access the resources of that component (e.g. memory). We rely on this property so that we can correctly represent the interaction between Miden _contexts_ (each of which has its own memory, with no way to access the memory of other contexts).
-* Component-level exports represent the "interface" of a component, and are required to adhere to the [Canonical ABI](https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md).
+- Worlds must encode everything needed by a component
+- Components represent a shared-nothing boundary, i.e. nothing outside a component can access the resources of that component (e.g. memory). We rely on this property so that we can correctly represent the interaction between Miden _contexts_ (each of which has its own memory, with no way to access the memory of other contexts).
+- Component-level exports represent the "interface" of a component, and are required to adhere to the [Canonical ABI](https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md).
The following is a rough visual representation of the hierarchy and relationships between these concepts in HIR:
@@ -324,12 +324,12 @@ The following is a rough visual representation of the hierarchy and relationship
A few notes:
-* Dependencies between components may only exist between component-level exported functions, i.e. it is not valid to depend on a function defined in a module of another component directly.
-* Only component exports use the Canonical ABI, internally they handle lifting/lowering to the "core" ABI of the function which actually implements the behavior being exported.
-* Data segments represent data that will be written into the shared memory of a component when the component is initialized. Thus, they must be specified at component level, and may not be shared between components.
-* Global variables, representing some region of memory with a specified type, by definition cannot be shared between components, and are only visible within a component. We further restrict their definition to be within a module. Global variables _can_ be shared between modules, however.
-* Worlds, components, and modules are single-region, single-block operations, with graph-like region semantics (i.e. their block does not adhere to SSA dominance rules). They all implement the `SymbolTable` trait, and all but World implements the `Symbol` trait.
-* Functions are single-region, but that region can contain multiple blocks, and the body region is an SSA CFG region, i.e. it's blocks and operations must adhere to SSA dominance rules. The interaction with a function is determined by its _signature_, which dictates the types of its parameters and results, but these are not represented as operation operands/results, instead the function parameters are encoded as block parameters of its entry block, and function results are materialized at call sites based on the function signature. A validation rule ensures that the return-like operations in the function body return values that match the signature of the containing function.
+- Dependencies between components may only exist between component-level exported functions, i.e. it is not valid to depend on a function defined in a module of another component directly.
+- Only component exports use the Canonical ABI, internally they handle lifting/lowering to the "core" ABI of the function which actually implements the behavior being exported.
+- Data segments represent data that will be written into the shared memory of a component when the component is initialized. Thus, they must be specified at component level, and may not be shared between components.
+- Global variables, representing some region of memory with a specified type, by definition cannot be shared between components, and are only visible within a component. We further restrict their definition to be within a module. Global variables _can_ be shared between modules, however.
+- Worlds, components, and modules are single-region, single-block operations, with graph-like region semantics (i.e. their block does not adhere to SSA dominance rules). They all implement the `SymbolTable` trait, and all but World implements the `Symbol` trait.
+- Functions are single-region, but that region can contain multiple blocks, and the body region is an SSA CFG region, i.e. it's blocks and operations must adhere to SSA dominance rules. The interaction with a function is determined by its _signature_, which dictates the types of its parameters and results, but these are not represented as operation operands/results, instead the function parameters are encoded as block parameters of its entry block, and function results are materialized at call sites based on the function signature. A validation rule ensures that the return-like operations in the function body return values that match the signature of the containing function.
### Worlds
@@ -374,8 +374,8 @@ Function parameters are materialized as values in the form of entry block argume
Blocks in the function body must be terminated with one of two operations:
-* `builtin.ret`, which returns from the function to its caller. The set of operands passed to this operation must match the arity and types specified in the containing function's signature.
-* `ub.unreachable`, representing some control flow path that should never be reachable at runtime. This is translated to an abort/trap during code generation. This operation is defined in the `ub` dialect as it corresponds to undefined behavior in a program.
+- `builtin.ret`, which returns from the function to its caller. The set of operands passed to this operation must match the arity and types specified in the containing function's signature.
+- `ub.unreachable`, representing some control flow path that should never be reachable at runtime. This is translated to an abort/trap during code generation. This operation is defined in the `ub` dialect as it corresponds to undefined behavior in a program.
### Global Variables
@@ -401,9 +401,9 @@ The primary way you interact with the pass infrastructure is by:
In HIR, there are three primary types of passes:
-* DIY, i.e. anything goes. What these do is completely up to the pass author.
-* Pattern rewrites, which match against an operation by looking for some pattern, and then performing a rewrite of that operation based on that pattern. These are executed by the `GreedyPatternRewriteDriver`, and must adhere to a specific set of rules in order for the driver to be guaranteed to reach fixpoint.
-* Canonicalizations, a special case of pattern rewrite which are orchestrated by the `Canonicalizer` rewrite pass.
+- DIY, i.e. anything goes. What these do is completely up to the pass author.
+- Pattern rewrites, which match against an operation by looking for some pattern, and then performing a rewrite of that operation based on that pattern. These are executed by the `GreedyPatternRewriteDriver`, and must adhere to a specific set of rules in order for the driver to be guaranteed to reach fixpoint.
+- Canonicalizations, a special case of pattern rewrite which are orchestrated by the `Canonicalizer` rewrite pass.
### Analyses
@@ -434,9 +434,9 @@ Canonicalization is a form of [_pattern rewrite_](#pattern-rewrites) that applie
What constitutes the _canonical form_ of an operation, depends on the operation itself:
-* In some cases, this might be ensuring that if an operation has a constant operand, that it is always in the same position - thus making pattern recognition at higher levels easier, as they only need to attempt to match a single pattern.
-* In the case of control flow, the canonical form is often the simplest possible form that preserves the semantics.
-* Some operations can be simplified based on known constant operands, or reduced to a constant themselves. This process is called [_constant folding_](#folding), and is an implicit canonicalization of all operations which support folding, via the `Foldable` trait.
+- In some cases, this might be ensuring that if an operation has a constant operand, that it is always in the same position - thus making pattern recognition at higher levels easier, as they only need to attempt to match a single pattern.
+- In the case of control flow, the canonical form is often the simplest possible form that preserves the semantics.
+- Some operations can be simplified based on known constant operands, or reduced to a constant themselves. This process is called [_constant folding_](#folding), and is an implicit canonicalization of all operations which support folding, via the `Foldable` trait.
#### Folding
@@ -448,9 +448,9 @@ What about when only some of the operands are constant? That depends on the oper
A fold has three outcomes:
-* Success, i.e. the operation was able to be folded away; it can be erased and all uses of its results replaced with the fold outputs
-* In-place, the operation was able to be simplified, but not folded away/replaced. In this case, there are no fold outputs, the original operation is simply updated.
-* Failure, i.e. the operation could not be folded or simplified in any way
+- Success, i.e. the operation was able to be folded away; it can be erased and all uses of its results replaced with the fold outputs
+- In-place, the operation was able to be simplified, but not folded away/replaced. In this case, there are no fold outputs, the original operation is simply updated.
+- Failure, i.e. the operation could not be folded or simplified in any way
Operation folding can be done manually, but is largely handled via the [_canonicalization_](#canonicalization) pass, which combines folding with other pattern rewrites, as well as region simplification.
@@ -487,8 +487,8 @@ This approach is used due to the graph-like structure of the IR itself - the erg
There are two main "types" of `RawEntityRef` metadata:
-* `()`, aliased as `UnsafeEntityRef`
-* `IntrusiveLink`, aliased as `UnsafeIntrusiveEntityRef`.
+- `()`, aliased as `UnsafeEntityRef`
+- `IntrusiveLink`, aliased as `UnsafeIntrusiveEntityRef`.
In both cases, the type is aliased to reflect the underlying entity type being referenced, e.g. `BlockRef` is an `UnsafeIntrusiveEntityRef`, and `ValueRef` is an `UnsafeEntityRef`.
@@ -502,9 +502,9 @@ This refers to the `EntityStorage` type, which abstracts over the storage of
The `EntityStorage` type provides the following:
-* Lifecycle management of stored entities, via the `StoreableEntity` trait
-* Grouping of entities within storage, with relative indexing, support for insertion, removal, iteration, etc. This is used, for example, to use a single `EntityStorage` for all operands of an operation, while grouping operands semantically (e.g. group 0 are operands of the op itself, group 1 through N are operand groups for each successor of the operation).
-* Conveniences for indexing, slicing, iterating, etc.
+- Lifecycle management of stored entities, via the `StoreableEntity` trait
+- Grouping of entities within storage, with relative indexing, support for insertion, removal, iteration, etc. This is used, for example, to use a single `EntityStorage` for all operands of an operation, while grouping operands semantically (e.g. group 0 are operands of the op itself, group 1 through N are operand groups for each successor of the operation).
+- Conveniences for indexing, slicing, iterating, etc.
##### StoreableEntity
@@ -526,17 +526,17 @@ An entity list is simply a doubly-linked, intrusive list, owned by some entity,
Examples include:
-* The list of regions belonging to an operation
-* The list of blocks belonging to a region
-* The list of operations belonging to a block
-* The list of operands using a block argument/op result
-* The list of symbol users referencing a symbol
+- The list of regions belonging to an operation
+- The list of blocks belonging to a region
+- The list of operations belonging to a block
+- The list of operands using a block argument/op result
+- The list of symbol users referencing a symbol
In conjunction with the list itself, there are a set of traits which facilitate automatically maintaining the relationship between parent and child entity as items are inserted, removed, or transferred between parent lists:
-* `EntityParent`, implemented by any entity type which has some child entity of type `Child`. This provides us with the ability to map a parent/child relationship to the offset of the intrusive linked list in the parent entity, so that we can construct a reference to it. Entities can be the parent of multiple other entity types.
-* `EntityWithParent`, implemented by the child entity which has some parent type `T`, this provides the inverse of `EntityParent`, i.e. the ability for the entity list infrastructure to resolve the parent type of a child entity it stores, and given a reference to the parent entity, get the relevant intrusive list for that child. Entities with a parent may only have a single parent entity type at this time.
-* `EntityListItem`, implemented by any entity type which can be stored in an entity list. This trait provides the set of callbacks that are invoked by the entity list infrastructure when modifying the list (inserting, removing, and transferring items). This trait is public, but the entity list infra actually uses a different trait, called `EntityListTraits`, which is specialized based on whether the list items implement just `EntityListItem`, or both `EntityListItem` and `EntityWithParent`. The specialization for the latter ensures that the parent/child relationship is updated appropriately by the entity list itself, rather than requiring `EntityListItem` implementations to do so.
+- `EntityParent`, implemented by any entity type which has some child entity of type `Child`. This provides us with the ability to map a parent/child relationship to the offset of the intrusive linked list in the parent entity, so that we can construct a reference to it. Entities can be the parent of multiple other entity types.
+- `EntityWithParent`, implemented by the child entity which has some parent type `T`, this provides the inverse of `EntityParent`, i.e. the ability for the entity list infrastructure to resolve the parent type of a child entity it stores, and given a reference to the parent entity, get the relevant intrusive list for that child. Entities with a parent may only have a single parent entity type at this time.
+- `EntityListItem`, implemented by any entity type which can be stored in an entity list. This trait provides the set of callbacks that are invoked by the entity list infrastructure when modifying the list (inserting, removing, and transferring items). This trait is public, but the entity list infra actually uses a different trait, called `EntityListTraits`, which is specialized based on whether the list items implement just `EntityListItem`, or both `EntityListItem` and `EntityWithParent`. The specialization for the latter ensures that the parent/child relationship is updated appropriately by the entity list itself, rather than requiring `EntityListItem` implementations to do so.
We use intrusive linked lists for storing sets of entities that may be arbitrarily large, and where the O(1) insertion, removal, splicing and splitting makes up for the less cache-friendly iteration performance. Given a reference to an entity, we can always construct a cursor to that element of the list, and traverse the list from there, or modify the list there - this is a much more frequent operation than iterating these lists.
@@ -544,23 +544,23 @@ We use intrusive linked lists for storing sets of entities that may be arbitrari
Before we can discuss the various ways of traversing the IR, we need to clarify what aspect of the IR we're interested in traversing:
-* The data flow graph, i.e. nodes are operations, edges are formed by operands referencing values.
-* The control flow graph, i.e. nodes are either operations, blocks, or regions; and edges are formed by operations which transfer control (to the next op, to a specific set of successor blocks or regions).
-* The call graph, i.e. nodes are symbols which implement `CallableOpInterface`, and edges are formed by operations which implement `CallOpInterface`.
+- The data flow graph, i.e. nodes are operations, edges are formed by operands referencing values.
+- The control flow graph, i.e. nodes are either operations, blocks, or regions; and edges are formed by operations which transfer control (to the next op, to a specific set of successor blocks or regions).
+- The call graph, i.e. nodes are symbols which implement `CallableOpInterface`, and edges are formed by operations which implement `CallOpInterface`.
There are also a few traversal primitives which are commonly used:
-* Any `UnsafeIntrusiveEntityRef` for a type which implements `EntityListItem`, provides `next` and `prev` methods which allow navigating to the next/previous sibling item in the list, without borrowing the entity itself. In some cases, being siblings in an entity list does not mean that the items are near each other, e.g. the only thing shared in common between uses of a `Symbol`, is the symbol they refer to, but their order in the symbol use-list has no semantic meaning. In others, being siblings mean that the items are actually located next to each other in that order, e.g. operations in a block.
-* Similarly, any `UnsafeIntrusiveEntityRef` for a type which implements `EntityWithParent`, provides a `parent` method which allow navigating to the parent entity from the child, without borrowing either of them.
-* All child entities "owned" by a parent entity, are stored in either a [_entity list_](#entity-lists) or [_entity storage_](#entity-storage) attached to that entity.
+- Any `UnsafeIntrusiveEntityRef` for a type which implements `EntityListItem`, provides `next` and `prev` methods which allow navigating to the next/previous sibling item in the list, without borrowing the entity itself. In some cases, being siblings in an entity list does not mean that the items are near each other, e.g. the only thing shared in common between uses of a `Symbol`, is the symbol they refer to, but their order in the symbol use-list has no semantic meaning. In others, being siblings mean that the items are actually located next to each other in that order, e.g. operations in a block.
+- Similarly, any `UnsafeIntrusiveEntityRef` for a type which implements `EntityWithParent`, provides a `parent` method which allow navigating to the parent entity from the child, without borrowing either of them.
+- All child entities "owned" by a parent entity, are stored in either a [_entity list_](#entity-lists) or [_entity storage_](#entity-storage) attached to that entity.
These three primitives provide the core means by which one can navigate the relevant graph in any direction.
Another thing to be aware of, is that relationships between entities where there may be multiple edges between the same two entities, are typically represented using a special node type. For example:
-* `OpOperand` represents a use of a `Value` by an operation. In order to maintain the use-def graph of values, each value type, e.g. `BlockArgument`, has its own entity list for `OpOperand`s. What is stored in the relevant entity storage of the operation then, are `OpOperandRef`s. So while operands are intuitively something we think of as an intrinsic part of an operation, they are actually their own IR entity, which is then stored by reference both in the operation, and in the use-list of the value they reference.
-* `BlockOperand` represents a "use" of a `Block` by an operation as a successor. This type is responsible for forming the edges of the CFG, and so much like `OpOperand`, the `Block` type has an entity list for `BlockOperand`s, effectively the set of that block's predecessors; while the operation has entity storage for `BlockOperandRefs` (or more precisely, `SuccessorInfo`, of which `BlockOperandRef` is one part).
-* `SymbolUse` represents a use of a `Symbol` by an operation. This underpins the maintenance of the call graph. Unlike operands, symbol usage is not tracked as a fundamental part of every operation, i.e. there is no dedicated `symbols` field of the `Operation` type which provides the entity storage for `SymbolUseRef`s, nor is there a field which defines the entity list. Instead, the symbol use list of an op that implements `Symbol`, must be defined as part of the concrete operation type. Similarly, any concrete operation type that can use/reference a `Symbol` op, must determine for itself how it will store that use. For this reason, symbol maintenance is a bit less ergonomic than other entity types.
+- `OpOperand` represents a use of a `Value` by an operation. In order to maintain the use-def graph of values, each value type, e.g. `BlockArgument`, has its own entity list for `OpOperand`s. What is stored in the relevant entity storage of the operation then, are `OpOperandRef`s. So while operands are intuitively something we think of as an intrinsic part of an operation, they are actually their own IR entity, which is then stored by reference both in the operation, and in the use-list of the value they reference.
+- `BlockOperand` represents a "use" of a `Block` by an operation as a successor. This type is responsible for forming the edges of the CFG, and so much like `OpOperand`, the `Block` type has an entity list for `BlockOperand`s, effectively the set of that block's predecessors; while the operation has entity storage for `BlockOperandRefs` (or more precisely, `SuccessorInfo`, of which `BlockOperandRef` is one part).
+- `SymbolUse` represents a use of a `Symbol` by an operation. This underpins the maintenance of the call graph. Unlike operands, symbol usage is not tracked as a fundamental part of every operation, i.e. there is no dedicated `symbols` field of the `Operation` type which provides the entity storage for `SymbolUseRef`s, nor is there a field which defines the entity list. Instead, the symbol use list of an op that implements `Symbol`, must be defined as part of the concrete operation type. Similarly, any concrete operation type that can use/reference a `Symbol` op, must determine for itself how it will store that use. For this reason, symbol maintenance is a bit less ergonomic than other entity types.
We now can explore the different means by which the IR can be traversed:
@@ -579,8 +579,8 @@ This trait is currently implemented for `Region`, `Block`/`BlockRef`, and `DomTr
The `Walk` trait defines how to walk all children of a given type, which are contained within the type for which `Walk` is being implemented. For example:
-* `Walk for Region` defines how to traverse a region to visit all of the operations it contains, recursively.
-* `Walk for Operation` defines how to traverse an operation to visit all of the regions it contains, recursively.
+- `Walk for Region` defines how to traverse a region to visit all of the operations it contains, recursively.
+- `Walk for Operation` defines how to traverse an operation to visit all of the regions it contains, recursively.
The difference between `Walk` and `RawWalk`, is that `Walk` requires borrowed references to the types it is implemented for, while `RawWalk` relies on the traversal primitives we introduced at the start of this section, to avoid borrowing any of the entities being traversed, with the sole exception being to access child entity lists long enough to get a reference to the head of the list. If we are ever mutating the IR as we visit it, then we use `RawWalk`, otherwise `Walk` tends to be more ergonomic.
@@ -613,10 +613,10 @@ A _program point_ essentially represents a cursor in the CFG of a program. Speci
Program points are used in a few ways:
-* To specify where a block or operation should be inserted
-* To specify at what point a block should be split into two
-* To specify at what point a block should be merged into another
-* To anchor data flow analysis state, e.g. the state before and after an operation, or the state on entry and exit from a block.
+- To specify where a block or operation should be inserted
+- To specify at what point a block should be split into two
+- To specify at what point a block should be merged into another
+- To anchor data flow analysis state, e.g. the state before and after an operation, or the state on entry and exit from a block.
Currently, we distinguish the points representing "before" a block (i.e. at the start of the block), and "after" a block (i.e. at the end of the block), from the first and last operations in the block, respectively. Thus, even though a point referring to the start of the block, and a point referring to "before" the first operation in that block, effectively refer to the same place, we currently treat them as distinct locations. This may change in the future, but for now, it is something to be aware of.
@@ -624,7 +624,6 @@ The `ProgramPoint` type can be reified as a literal cursor into the operation li
The key thing to understand about program points has to do with the relationship between before/after (or start/end) and what location that actually refers to. The gist, is that a program point, when materialized as a cursor into an operation list, will always have the cursor positioned such that if you inserted a new operation at that point, it would be placed where you expect it to be - i.e. if "before" an operation, the insertion will place the new item immediately preceding the operation referenced by the program point. This is of particular importance if inserting multiple operations using the same point, as the order in which operations will be inserted depends on whether the position is before or after the point. For example, inserting multiple items "before" an operation, will have them appear in that same order in the containing block. However, inserting multiple items "after" an operation, will have them appear in reverse order they were inserted (i.e. the last to be inserted will appear first in the block relative to the others).
-
### Defining Dialects
Defining a new dialect is as simple as defining a struct type which implements the `Dialect` trait. For example:
@@ -646,7 +645,6 @@ impl Dialect for MyDialect {
One last thing remains before the dialect is ready to be used, and that is [_dialect registration_](#dialect-registration).
-
#### Dialect Registration
Dialect registration is the means by which a dialect and its operations are registered with the [`Context`](#context), such that operations of that dialect can be built.
@@ -682,8 +680,8 @@ Of particular use, is the `DialectInfo::register_operation_trait` method, which
We currently use dialect hooks for:
-* Attaching the `midenc_codegen_masm::Lowering` trait to all operations for which we have defined its lowering to Miden Assembly.
-* Attaching the `midenc_hir_eval::Eval` trait to all operations for which we have defined evaluation semantics, for use with the HIR evaluator.
+- Attaching the `midenc_codegen_masm::Lowering` trait to all operations for which we have defined its lowering to Miden Assembly.
+- Attaching the `midenc_hir_eval::Eval` trait to all operations for which we have defined evaluation semantics, for use with the HIR evaluator.
#### Defining Operations
@@ -737,28 +735,27 @@ impl EffectOpInterface for Add {
To summarize:
-* `dialect` specifies the dialect to which the operation will be registered
-* `traits` specifies the set of derivable traits for this operation.
-* `implements` specifies the set of traits/interfaces which will be manually implemented for this operation. If any of the listed traits/interfaces are _not_ implemented, a compiler error will be emitted.
-* The fields of the `Add` struct represent various properties of the operation. Their meaning depends on what (if any) attributes they are decorated with:
- * The `#[operand]` attribute represents an expected operand of this operation, and the field type represents the type constraint to apply to it.
- * The `#[result]` attribute represents a result produced by this operation, and the field type represents the type constraint to apply to it.
- * The `#[attr]` attribute represents a required attribute of this operation. If the `#[default]` attribute is present, it is treated as an optional attribute.
- * If a field has no attributes, or only `#[default]`, it is defined as part of the concrete operation struct, and is considered an internal detail of the op.
- * All other fields are not actually stored as part of the concrete operation type, but as part of the underlying `Operation` struct, and methods will be generated in an `impl Add` block that provide access to those fields in all the ways you'd expect.
- * The `#[operand]`, `#[attr]`, and undecorated fields are all expected, in that order, as arguments to the op builder when constructing an instance of this op.
+- `dialect` specifies the dialect to which the operation will be registered
+- `traits` specifies the set of derivable traits for this operation.
+- `implements` specifies the set of traits/interfaces which will be manually implemented for this operation. If any of the listed traits/interfaces are _not_ implemented, a compiler error will be emitted.
+- The fields of the `Add` struct represent various properties of the operation. Their meaning depends on what (if any) attributes they are decorated with:
+ - The `#[operand]` attribute represents an expected operand of this operation, and the field type represents the type constraint to apply to it.
+ - The `#[result]` attribute represents a result produced by this operation, and the field type represents the type constraint to apply to it.
+ - The `#[attr]` attribute represents a required attribute of this operation. If the `#[default]` attribute is present, it is treated as an optional attribute.
+ - If a field has no attributes, or only `#[default]`, it is defined as part of the concrete operation struct, and is considered an internal detail of the op.
+ - All other fields are not actually stored as part of the concrete operation type, but as part of the underlying `Operation` struct, and methods will be generated in an `impl Add` block that provide access to those fields in all the ways you'd expect.
+ - The `#[operand]`, `#[attr]`, and undecorated fields are all expected, in that order, as arguments to the op builder when constructing an instance of this op.
There are a variety of field attributes and options for them that are not shown here. For now, the best reference for these is looking at the set of current dialects for an operation that is similar to what you want to define. You can also look at the implementation of the `#[operation]` proc-macro in `midenc_hir_macros` as the authoritative source on what is supported and how it affects the output. In the future we will provide more comprehensive documentation for it.
-
### Builders
Constructing the IR is generally done via implementations of the `Builder` trait, which includes implementations of the `Rewriter` trait, as the former is a super-trait of the latter. Typically, this means the `OpBuilder` type.
Aside from a variety of useful APIs e.g. creating blocks, setting the insertion point of the builder, etc., most commonly you will be constructing specific operations, which is done in one of two ways:
-* The lowest level primitive, actually provided by the `BuilderExt` trait due to the need to keep `Builder` object-safe, is its `create` method. This method produces an implementation of `BuildableOp` for the specified operation type (i.e. the `T` type parameter), and signature (i.e. the `Args` type parameter, which must be a tuple type). The desired operation is then constructed by applying the necessary arguments to the `BuildableOp` as a function (because `BuildableOp` is an implementation of the `FnOnce` closure type).
-* Much more commonly however, this boilerplate will be abstracted away for you by dialect-specific extensions of the `Builder` trait, e.g. the `BuiltinOpBuilder` trait extends all `Builder` implementations with methods for constructing any of the `builtin` dialect operations, such as the `ret` method, which constructs the `builtin.return` operation. All of the dialects used by the compiler define such a trait, all that is required is to bring it into scope in order to construct the specific operations you want.
+- The lowest level primitive, actually provided by the `BuilderExt` trait due to the need to keep `Builder` object-safe, is its `create` method. This method produces an implementation of `BuildableOp` for the specified operation type (i.e. the `T` type parameter), and signature (i.e. the `Args` type parameter, which must be a tuple type). The desired operation is then constructed by applying the necessary arguments to the `BuildableOp` as a function (because `BuildableOp` is an implementation of the `FnOnce` closure type).
+- Much more commonly however, this boilerplate will be abstracted away for you by dialect-specific extensions of the `Builder` trait, e.g. the `BuiltinOpBuilder` trait extends all `Builder` implementations with methods for constructing any of the `builtin` dialect operations, such as the `ret` method, which constructs the `builtin.return` operation. All of the dialects used by the compiler define such a trait, all that is required is to bring it into scope in order to construct the specific operations you want.
> [!NOTE]
> All of the boilerplate for constructing an operation from a `Builder` is generated for you when defining an operation type with the `#[operation]` proc-macro attribute. A key piece of this underlying infrastructure, is the `OperationBuilder` type, which is used to construct the `Operation` that underlies any concrete `Op` implementation. The `OperationBuilder` is also where new operations are verified and inserted into the underlying `Builder` during construction.
@@ -776,8 +773,8 @@ Validation may also be triggered manually at any point by calling the `Operation
There are two traits which underpin the verification infrastructure:
-* `Verify` which represents the verification of `Trait` against `Self`, which is an operation type. Typically, all traits with associated verification rules, implement this trait for all `T: Op + Trait`.
-* `Verifier` which is a trait used to facilitate the generation of verification boilerplate specialized against a specific concrete operation type, without having to be aware of what operation traits/interfaces have associated `Verify` implementations. Instead, no-op verifiers are elided by the Rust compiler using `const { }` blocks. The method by which this is done is highly reliant on Rust's specialization infrastructure and type-level trickery.
+- `Verify` which represents the verification of `Trait` against `Self`, which is an operation type. Typically, all traits with associated verification rules, implement this trait for all `T: Op + Trait`.
+- `Verifier` which is a trait used to facilitate the generation of verification boilerplate specialized against a specific concrete operation type, without having to be aware of what operation traits/interfaces have associated `Verify` implementations. Instead, no-op verifiers are elided by the Rust compiler using `const { }` blocks. The method by which this is done is highly reliant on Rust's specialization infrastructure and type-level trickery.
In the future, we will likely move verification out of the `OperationBuilder`, into a dedicated pass that is run as part of a pass pipeline, and invoked on each operation via `Operation::verify`. This will enable more robust verification than is currently possible (as operations are not yet inserted in the IR at the point verification is applied currently).
@@ -787,10 +784,10 @@ Side effects are an important consideration during analysis and transformation o
The infrastructure underpinning the management and querying of effects is built on the following pieces:
-* The `Effect` trait, which is a marker trait for types which represent an effect, e.g. `MemoryEffect` which represents effects on memory, such as reading and writing, allocation and freeing.
-* The `EffectOpInterface` interface, which is implemented for any operation for which the effect `T` is specified, and provides a number of useful methods for querying effects of a specific operation instance.
-* The `Resource` trait, which represents a type of resource to which an effect can apply. In many cases, one will use `DefaultResource`, which is a catch-all resource that implies a global effect. However, it is also possible to scope effects to a specific resource, such as a specific address range in memory. This could permit operations with disjoint effects to be reordered relative to one another, when that would otherwise not be allowed if the effects were global.
-* The `EffectInstance` type, which provides metadata about a specific effect, any attributes that apply to it, the resource affected, etc.
+- The `Effect` trait, which is a marker trait for types which represent an effect, e.g. `MemoryEffect` which represents effects on memory, such as reading and writing, allocation and freeing.
+- The `EffectOpInterface` interface, which is implemented for any operation for which the effect `T` is specified, and provides a number of useful methods for querying effects of a specific operation instance.
+- The `Resource` trait, which represents a type of resource to which an effect can apply. In many cases, one will use `DefaultResource`, which is a catch-all resource that implies a global effect. However, it is also possible to scope effects to a specific resource, such as a specific address range in memory. This could permit operations with disjoint effects to be reordered relative to one another, when that would otherwise not be allowed if the effects were global.
+- The `EffectInstance` type, which provides metadata about a specific effect, any attributes that apply to it, the resource affected, etc.
It should be noted that the choice to implement `EffectOpInterface` for an operation is _not_ based on whether the operation _has_ the effect; but rather, it is based on whether the behavior of the operation with respect to that effect is _specified_ or not.
@@ -802,9 +799,9 @@ When `EffectOpInterface` is not implemented for some operation, then one must tr
The infrastructure described above can be used to represent any manner of side effect. However, the compiler is currently only largely concerned with effects on memory. For this, there are a few more specific pieces:
-* The `MemoryEffectOpInterface` trait alias, which is just an alias for `EffectOpInterface`.
-* The `MemoryEffect` type, which represents the set of memory effects we care about.
-* The `HasRecursiveMemoryEffects` trait, which should be implemented on any operation whose regions may contain operations that have memory effects.
-* The `Operation::is_memory_effect_free` method, which returns a boolean indicating whether the operation is known not to have any memory effects.
+- The `MemoryEffectOpInterface` trait alias, which is just an alias for `EffectOpInterface`.
+- The `MemoryEffect` type, which represents the set of memory effects we care about.
+- The `HasRecursiveMemoryEffects` trait, which should be implemented on any operation whose regions may contain operations that have memory effects.
+- The `Operation::is_memory_effect_free` method, which returns a boolean indicating whether the operation is known not to have any memory effects.
In most places, we're largely concerned with whether an operation is known to be memory effect free, thus allowing us to move that operation around freely. We have not started doing more sophisticated effect analysis and optimizations based on such analysis.
diff --git a/docs/src/design/packaging.md b/docs/internal/src/packaging.md
similarity index 100%
rename from docs/src/design/packaging.md
rename to docs/internal/src/packaging.md
diff --git a/docs/src/design/rewrites.md b/docs/internal/src/rewrites.md
similarity index 91%
rename from docs/src/design/rewrites.md
rename to docs/internal/src/rewrites.md
index 8914cc084..f3ea6e74a 100644
--- a/docs/src/design/rewrites.md
+++ b/docs/internal/src/rewrites.md
@@ -4,22 +4,21 @@ This document provides an overview of some of the current transformation/rewrite
Most rewrite passes, at the time of writing, are maintained in the `midenc-hir-transform` crate, with the exception of those which are either dialect-specific (i.e. canonicalization, or reliant on dialect-aware interfaces), or part of the core `midenc-hir` crate (i.e. region simplification, folding).
-* [Region Simplification](#region-simplification)
-* [Folding](#folding)
-* [Canonicalization](#canonicalization)
-* [Sparse Conditional Constant Propagation](#sparse-conditional-constant-propagation)
-* [Unstructured to Structured Control Flow Lifting](#control-flow-lifting)
-* [Control Flow Sinking](#control-flow-sinking)
-* [Spills](#spills)
-
+- [Region Simplification](#region-simplification)
+- [Folding](#folding)
+- [Canonicalization](#canonicalization)
+- [Sparse Conditional Constant Propagation](#sparse-conditional-constant-propagation)
+- [Unstructured to Structured Control Flow Lifting](#control-flow-lifting)
+- [Control Flow Sinking](#control-flow-sinking)
+- [Spills](#spills)
## Region Simplification
Region simplification is a region-local transformation which:
-* Removes redundant block arguments
-* Merges identical blocks
-* Removes unused/dead code
+- Removes redundant block arguments
+- Merges identical blocks
+- Removes unused/dead code
This transformation is exposed from the `Region` type, but is considered the responsibility of the `GreedyPatternRewriteDriver` to apply, based on the current compiler configuration.
@@ -32,9 +31,9 @@ Folding, or _constant folding_ to be more precise, is the process by which an op
Operations which can be folded must implement the `Foldable` trait, and implement the folding logic there. Folds can produce three outcomes, represented via `FoldResult`:
-* `Ok`, indicating that the operation was able to be reduced to a (possibly constant) value or set of values.
-* `InPlace`, indicating that the operation was able to rewrite itself into a simpler form, but could not be completely folded. This is commonly the case when only a subset of the operands are known-constant.
-* `Failed`, indicating that the operation could not be folded or simplified at all.
+- `Ok`, indicating that the operation was able to be reduced to a (possibly constant) value or set of values.
+- `InPlace`, indicating that the operation was able to rewrite itself into a simpler form, but could not be completely folded. This is commonly the case when only a subset of the operands are known-constant.
+- `Failed`, indicating that the operation could not be folded or simplified at all.
Folding can be done at any time, but similar to region simplification, is largely delegated to the `GreedyPatternRewriteDriver` to apply as part of canonicalization.
@@ -60,7 +59,8 @@ Because some forms of unstructured control flow cannot be fully converted into s
As an example, here's what it looks like to lift an unstructured conditional branch to a `scf.if`:
-* Before:
+- Before:
+
```
^block0(v0: i1, v1: u32, v2: u32):
cf.cond_br v0, ^block1(v1), ^block2(v2);
@@ -77,7 +77,8 @@ As an example, here's what it looks like to lift an unstructured conditional bra
builtin.ret v7
```
-* After:
+- After:
+
```
v8 = scf.if v0 {
scf.yield v1
diff --git a/docs/src/EXPORTED.md b/docs/src/EXPORTED.md
deleted file mode 100644
index 0b207eb10..000000000
--- a/docs/src/EXPORTED.md
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-# Summary
-
-- [Compiler](./getting_started.md)
- * [Usage](./usage/index.md)
- + [As an Executable](./usage/midenc.md)
- + [As a Cargo extension](./usage/cargo-miden.md)
- * [Guides](./guides/index.md)
- + [Rust To WebAssembly](./guides/rust_to_wasm.md)
- + [WebAssembly To Miden Assembly](./guides/wasm_to_masm.md)
- + [Developing Miden Programs In Rust](./guides/develop_miden_in_rust.md)
- + [Developing Miden Rollup Accounts And Note Scripts In Rust](./guides/develop_miden_rollup_accounts_and_note_scripts_in_rust.md)
- + [Debugging programs](./usage/debugger.md)
diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md
deleted file mode 100644
index e5b622f3c..000000000
--- a/docs/src/SUMMARY.md
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-# Summary
-
-[Getting Started](./getting_started.md)
-
----
-
-# Usage
-
-- [As an Executable](./usage/midenc.md)
-- [As a Cargo extension](./usage/cargo-miden.md)
-
-# Guides
-
-- [Rust To WebAssembly](./guides/rust_to_wasm.md)
-- [WebAssembly To Miden Assembly](./guides/wasm_to_masm.md)
-- [Developing Miden Programs In Rust](./guides/develop_miden_in_rust.md)
-- [Developing Miden Rollup Accounts And Note Scripts In Rust](./guides/develop_miden_rollup_accounts_and_note_scripts_in_rust.md)
-- [Debugging programs](./usage/debugger.md)
-
-# Compiler architecture
-
-- [Overview](./design/index.md)
-- [Frontends](./design/frontends.md)
-- [Intermediate Representation (HIR)](./design/ir.md)
-- [Data Layout](./design/data_layout.md)
-- [Analyses](./design/analyses.md)
-- [Rewrites](./design/rewrites.md)
-- [Code Generation](./design/codegen.md)
-- [Packaging](./design/packaging.md)
-
----
-
-# Appendices:
-
-- [Known limitations](./appendix/known-limitations.md)
-- [Calling Conventions](./appendix/calling_conventions.md)
-- [Canonical ABI vs Miden ABI](./appendix/canonabi-adhocabi-mismatch.md)
diff --git a/docs/src/appendix/calling_conventions.md b/docs/src/appendix/calling_conventions.md
deleted file mode 100644
index 24f0efe6a..000000000
--- a/docs/src/appendix/calling_conventions.md
+++ /dev/null
@@ -1,296 +0,0 @@
-# Calling conventions
-
-This document describes the various calling conventions recognized/handled by the compiler,
-including a specification for the interaction with the IR type system.
-
-There are four calling conventions represented in the compiler:
-
-- `C` aka `SystemV`, which corresponds to the C ABI commonly used for C foreign-function interfaces (FFI).
- We specifically use the System V ABI because it is well understood, documented, and straightforward.
-- `Fast`, this convention allows the compiler to follow either the `C` calling convention, or modify it
- as it sees fit on a function-by-function basis. This convention provides no guarantees about how a
- callee will expect arguments to be passed, so should not be used for functions which are expected to
- have a stable, predictable interface. This is a good choice for local functions, or functions which are
- only used within an executable/library and are not part of the public interface.
-- `Kernel`, this is a special calling convention that is used when defining kernel modules in the IR.
- Functions which are part of the kernel's public API are required to use this convention, and it is not
- possible to call a function via `syscall` if the callee is not defined with this convention. Because of
- the semantics of `syscall`, this convention is highly restrictive. In particular, it is not permitted to
- pass pointer arguments, or aggregates containing pointers, as `syscall` involves a context switch, and
- thus memory in the caller is not accessible to the callee, and vice versa.
-- `Contract`, this is a special calling convention that is used when defining smart contract functions, i.e.
- functions that can be `call`'d. The compiler will not permit you to `call` a function if the callee is not
- defined with this convention, and functions with this convention cannot be called via `exec`. Like `syscall`,
- the `call` instruction involves a context switch, however, unlike the `Kernel` convention, the `Contract`
- convention is allowed to have types in its signature that are/contain pointers, with certain caveats around
- those pointers.
-
-All four conventions above are based on the System V C ABI, tailored to the Miden VM. The only exception is
-`Fast`, which may modify the ABI arbitrarily as it sees fit, and makes no guarantees about what modifications,
-if any, it will make.
-
-## Data representation
-
-The following is a description of how the IR type system is represented in the `C` calling convention. Later,
-a description of how the other conventions extend/restrict/modify this representation will be provided.
-
-### Scalars
-
-General type | C Type | IR Type | `sizeof` | Alignment (bytes) | Miden Type
--|-|-|-|-|-
- Integer | `_Bool`/`bool` | `I1` | 1 | 1 | u32
- Integer | `char`, `signed char` | `I8` | 1 | 1 | i32[^1]
- Integer | `unsigned char` | `U8` | 1 | 1 | u32
- Integer | `short` / `signed short` | `I16` | 2 | 2 | i32[^1]
- Integer | `unsigned short` | `U16` | 2 | 2 | u32
- Integer | `int` / `signed int` / `enum` | `I32` | 4 | 4 | i32[^1][^8]
- Integer | `unsigned int` | `U32` | 4 | 4 | u32
- Integer | `long` / `signed long` | `I32` | 4 | 4 | i32[^1]
- Integer | `unsigned long` / `size_t` | `U32` | 4 | 4 | u32
- Integer | `long long` / `signed long long` | `I64` | 8 | 8 | i64[^2]
- Integer | `unsigned long long` | `U64` | 8 | 8 | u64[^3]
- Pointer | *`any-type *`* / *`any-type (*)()`* | `Ptr(_)` | 4 | 4 | u32[^6][^7]
- Floating point | `float` | `F32` | 4 | 4 | u32[^4]
- Floating point | `double` | `F64` | 8 | 8 | u64[^4]
- Floating point | `long double` | 16 | 16 | (none)[^5]
-
-[^1]: i32 is not a native Miden type, but is implemented using compiler intrinsics on top of the native u32 type
-
-[^2]: i64 is not a native Miden type, but is implemented using compiler intrinsics on top of the stdlib u64 type
-
-[^3]: u64 is not a native Miden type, but is implemented in software using two 32-bit limbs (i.e. a pair of field elements)
-
-[^4]: floating-point types are not currently supported, but will be implemented using compiler intrinsics
-
-[^5]: `long double` values correspond to 128-bit IEEE-754 quad-precision binary128 values. These are not currently
-supported, and we have no plans to support them in the near term. Should we ever provide such support, we will do
-so using compiler intrinsics.
-
-[^6]: A null pointer (for all types) always has the value zero.
-
-[^7]: Miden's linear memory is word-addressable, not byte-addressable. The `Ptr` type has an `AddressSpace` parameter,
-that by default is set to the byte-addressable address space. The compiler translates values of `Ptr` type that are in
-this address space, into the Miden-native, word-addressable address space during codegen of load/store operations. See
-the section on the memory model below for more details.
-
-[^8]: An `enum` is `i32` if all members of the enumeration can be represented by an `int`/`unsigned int`, otherwise it
-uses i64.
-
-> [!NOTE]
-> The compiler does not support scalars larger than one word (128 bits) at this time. As a result, anything that is
-> larger than that must be allocated in linear memory, or in an automatic allocation (function-local memory), and passed
-> around by reference.
-
-The native scalar type for the Miden VM is a "field element", specifically a 64-bit value representing an integer
-in the "Goldilocks" field, i.e. `0..(2^64-2^32+1)`. A number of instructions in the VM operate on field elements directly.
-However, the native integral/pointer type, i.e. a "machine word", is actually `u32`. This is because a field element
-can fully represent 32-bit integers, but not the full 64-bit integer range. Values of `u32` type are valid field element
-values, and can be used anywhere that a field element is expected (barring other constraints).
-
-Miden also has the notion of a "word", not to be confused with a "machine word" (by which we mean the native integral
-type used to represent pointers), which corresponds to a set of 4 field elements. Words are commonly used in Miden,
-particularly to represent hashes, and a number of VM instructions operate on word-sized operands. As an aside, 128-bit
-integer values are represented using a word, or two 64-bit limbs (each limb consisting of two 32-bit limbs).
-
-All integral types mentioned above, barring field elements, use two's complement encoding. Unsigned integral types
-make use of the sign bit to change the value range (i.e. 0..2^32-1, rather than -2^31..2^31-1), but the encoding follows
-two's complement rules.
-
-The Miden VM only has native support for field elements, words, and `u32`; all other types are implemented in software
-using intrinsics.
-
-### Aggregates and unions
-
-Structures and unions assume the alignment of their most strictly aligned component. Each member is assigned to the
-lowest available offset with the appropriate alignment. The size of any object is always a multiple of the object's alignment.
-An array uses the same alignment as its elements. Structure and union objects can require padding to meet size and alignment
-constraints. The contents of any padding is undefined.
-
-### Memory model
-
-Interacting with memory in Miden is quite similar to WebAssembly in some ways:
-
-* The address space is linear, with addresses starting at zero, and ranging up to 2^32-1
-* There is no memory protection per se, you either have full read/write access, or no access to a specific memory context
-* How memory is used is completely up to the program being executed
-
-This is where it begins to differ though, and takes on qualities unique to Miden (in part, or whole):
-
-* Certain regions of the address space are "reserved" for special uses, improper use of those regions may result in
-undefined behavior.
-* Miden has different types of function call instructions: `call` vs `syscall` vs `exec`. The first two
-perform a context switch when transferring control to the callee, and the callee has no access to the
-caller's memory (and the caller has no access to the callee's memory). As a result, references to memory
-cannot be passed from caller to callee in arguments, nor can they be returned from the callee to the caller.
-* Most significant of all though, is that Miden does not have byte-addressable memory, it is instead word-addressable,
-i.e. every address refers to a full word.
-* It is not possible to load a specific field element from a word in memory, unless it happens to be the first element
-of the word. Instead, one must load the full word, and drop the elements you don't need.
-
-This presents some complications, particularly:
-
-* Most languages assume a byte-oriented memory model, which is not trivially mapped to a word-oriented model
-* Simple things, such as taking the address of a field in a struct, and then dereferencing it, cannot be directly
-represented in Miden using native pointer arithmetic and `load` instruction. Operations like this must be translated
-into instruction sequences that load whole words from memory, extract the data needed, and discard the unused bits.
-This makes the choice of where in memory to store something much more important than byte-addressable memory, as
-loads of values which are not aligned to element or word boundaries can be quite inefficient in some cases.
-
-The compiler solves this by providing a byte-addressable IR, and internally translating operations in the IR to the equivalent
-sequence of Miden instructions needed to emulate that operation. This translation is done during code generation, and uses
-the following semantics to determine how a particular operation gets lowered:
-
-* A byte-addressable pointer can be emulated in Miden's word-addressable environment using three pieces of information:
- - The address of the word containing the first byte of the value, this is a "native" Miden address value
- - The index of the field element within that word containing the first byte of the value
- - The offset (in bytes) from the start of the 4 byte chunk represented by the selected element, corresponding
- to the first byte of the value. Since the chunk is represented as a u32 value, the offset is relative to the
- most-significant bit (i.e. the byte with the lowest address is found in bits 55-63, since Miden integers are little-endian)
-* This relies on us treating Miden's linear memory as an array of 16-byte chunks of raw memory (each word is 4 field elements,
-each element represents a 4-byte chunk). In short, much like translating a virtual memory address to a physical one, we must
-translate byte-addressable "virtual" pointers to "real" Miden pointers with enough metadata to be able to extract the data we're
-trying to load (or encode the data we're trying to store).
-
-Because we're essentially emulating byte-addressable memory on word-addressable memory, loads/stores can range from simple and
-straightforward, to expensive and complicated, depending on the size and alignment of the value type. The process goes as follows:
-
-* If the value type is word-aligned, it can be loaded/stored in as little as a single instruction depending on the size of the type
-* Likewise if the value type is element-aligned, and the address is word-aligned
-* Element-aligned values require some extra instructions to load a full word and drop the unused elements (or in the case of stores,
-loading the full word and replacing the element being stored)
-* Loads/stores of types with sub-element alignment depend on the alignment of the pointer itself. Element or word-aligned addresses
-are still quite efficient to load/store from, but if the first byte of the value occurs in the middle of an element, then the bytes
-of that value must be shifted into place (or unused bytes masked out). If the value crosses an element boundary, then the bytes in
-both elements must be isolated and shifted into position such that they can be bitwise-OR'd together to obtain the aligned value on
-the operand stack. If a value crosses a word boundary, then elements from both words must be loaded, irrelevant ones discarded, the
-relevant bytes isolated and shifted into position so that the resulting operand on the stack is aligned and laid out correctly.
-* Stores are further complicated by the need to preserve memory that is not being explicitly written to, so values that do not overwrite
-a full word or element, require combining bytes from the operand being stored and what currently resides in memory.
-
-The worst case scenario for an unaligned load or store involves a word-sized type starting somewhere in the last element of the first
-word. This will require loading elements from three consecutive words, plus a lot of shuffling bits around to get the final, aligned
-word-sized value on the operand stack. Luckily, such operations should be quite rare, as by default all word-sized scalar types are
-word-aligned or element-aligned, so an unaligned load or store would require either a packed struct, or a type such as an array of
-bytes starting at some arbitrary address. In practice, most loads/stores are likely to be element-aligned, so most overhead from
-emulation will come from values which cross an element or word boundary.
-
-## Function calls
-
-This section describes the conventions followed when executing a function call via `exec`, including how arguments are passed on the
-operand stack, stack frames, etc. Later, we'll cover the differences when executing calls via `call` or `syscall`.
-
-### Locals and the stack frame
-
-Miden does not have registers in the style of hardware architectures. Instead it has an operand stack, on which an arbitrary number of
-operands may be stored, and local variables. In both cases - an operand on the operand stack, or a single local variable - the value
-type is nominally a field element, but it is easier to reason about them as untyped element-sized values. The operand stack is used
-for function arguments, return values, temporary variables, and scratch space. Local variables are not always used, but are typically
-used to hold multiply-used values which you don't want to keep on the operand stack, function-scoped automatic allocations (i.e. `alloca`),
-and other such uses.
-
-Miden does not have a stack frame per se. When you call a procedure in Miden Assembly, any local variables declared by that procedure
-are allocated space in a reserved region of linear memory in a single consecutive chunk. However, there is no stack or frame pointer,
-and because Miden is a Harvard architecture machine, there are no return addresses. Instead, languages (such as C) which have the concept
-of a stack frame with implications for the semantics of say, taking the address of a local variable, will need to emit code in function
-prologues and epilogues to maintain a shadow stack in Miden's linear memory. If all you need is local variables, you can get away with
-leaning on Miden's notion of local variables without implementing a shadow stack.
-
-Because there are no registers, the notion of callee-saved or caller-saved registers does not have a direct equivalent in Miden. However,
-in its place, a somewhat equivalent set of rules defines the contract between caller and callee in terms of the state of the operand stack,
-those are described below in the section covering the operand stack.
-
-#### The shadow stack
-
-Miden is a [Harvard](https://en.wikipedia.org/wiki/Harvard_architecture) architecture; as such, code and data are not in the same memory
-space. More precisely, in Miden, code is only addressable via the hash of the MAST root of that code, which must correspond to code that
-has been loaded into the VM. The hash of the MAST root of a function can be used to call that function both directly and indirectly, but
-that is the only action you can take with it. Code can not be generated and called on the fly, and it is not stored anywhere that is
-accessible to code that is currently executing.
-
-One consequence of this is that there are no return addresses or instruction pointers visible to executing code. The runtime call stack is
-managed by the VM itself, and is not exposed to executing code in any way. This means that address-taken local C variables need to be on a
-separate stack in linear memory (which we refer to as a "shadow stack"). Not all functions necessarily require a frame in the shadow stack,
-as it cannot be used to perform unwinding, so only functions which have locals require a frame.
-
-The Miden VM actually provides some built-in support for stack frames when using Miden Assembly. Procedures which are declared with some
-number of locals, will be automatically allocated sufficient space for those locals in a reserved region of linear memory when called. If
-you use the `locaddr` instruction to get the actual address of a local, that address can be passed as an argument to callees (within the
-constraints of the callee's calling convention).
-
-Languages with more elaborate requirements with regard to the stack will need to implement their own shadow stack, and emit code in function
-prologues/epilogues to manage it.
-
-#### The operand stack
-
-The Miden virtual machine is a stack machine, not a register machine. Rather than having a fixed set of registers that are used to
-store and manipulate scalar values, the Miden VM has the operand stack, which can hold an arbitrary number of operands (where each
-operand is a single field element), of which the first 16 can be directly manipulated using special stack instructions. The operand
-stack is, as the name implies, a last-in/first-out data structure.
-
-The following are basic rules all conventions are expected to follow with regard to the operand stack:
-
-1. The state of the operand stack from the point of view of the caller should be preserved, with two exceptions:
- - The callee is expected to consume all of its arguments, and the caller will expect those operands to be gone when control is returned to it
- - If the callee signature declares a return value, the caller expects to see that on top of the stack when control is returned to it
-2. No more than 16 elements of the operand stack may be used for passing arguments. If more than that is required to represent all of the arguments,
-then one of the following must happen:
- - Spill to stack frame: in this scenario, up to 15 elements of the operand stack are used for arguments, and the remaining element is used to hold
- a pointer to a local variable in the caller's stack frame. That local variable is a struct whose fields are the spilled arguments, appearing in
- the same order as they would be passed. The callee must use the pointer it is given to compute the effective address for each spilled argument
- that it wishes to access.
- - Spill to heap: this is basically identical to the approach above, except the memory is allocated from the global heap, rather than using memory
- associated with the caller's stack frame.
- - Spill to the advice provider: in this scenario, 12 elements of the stack are used for arguments, and the remaining 4 are used to hold a hash
- which refers to the remaining arguments on the advice provider stack. The callee must arrange to fetch the spilled arguments from the advice
- provider using that hash.
-
-#### Function signatures
-
-Miden Abstract Syntax Trees (MASTs) do not have any notion of functions, and as such are not aware of parameters, return values, etc. For
-this document, that's not a useful level of abstraction to examine. Even a step higher, Miden Assembly (MASM) has functions (procedures
-in MASM parlance), but no function signature, i.e. given a MASM procedure, there is no way to know how many arguments it expects, how
-many values it returns, let alone the types of arguments/return values. Instead, we're going to specify calling conventions in terms of
-Miden IR, which has a fairly expressive type system more or less equivalent to that of LLVM, and how that translates to Miden primitives.
-
-Functions in Miden IR always have a signature, which specify the following:
-
-* The calling convention required to call the function
-* The number and types of the function arguments
-* The type of value, if any, returned by the function, and whether it is returned by value or reference
-
-The following table relates IR types to how they are expected to be passed from the caller to the callee, and vice versa:
-
-Type | Parameter | Result |
---------------------------|---------------|----------|
-scalar | direct | direct |
-empty struct or union[^1] | ignored | ignored |
-scalar struct or union[^2] | direct | direct |
-other struct or union | indirect | indirect |
-array | indirect | N/A |
-
-[^1]: Zero-sized types have no representation in memory, so they are ignored/skipped
-
-[^2]: Any struct or union that recursively (including through nested structs,
-unions, and arrays) contains just a single scalar value and is not specified to
-have greater than natural alignment.
-
-The compiler will automatically generate code that follows these rules, but if emitting MASM from your own backend, it is necessary to do so manually.
-For example, a function whose signature specifies that it returns a non-scalar struct by value, must actually be written such that it expects to receive
-a pointer to memory allocated by the caller sufficient to hold the return value, as the first parameter of the function (i.e. the parameter is prepended
-to the parameter list). When returning, the function must write the return value to that pointer, rather than returning it on the operand stack. In this
-example, the return value is returned indirectly (by reference).
-
-A universal rule is that the arguments are passed in reverse order, i.e. the first argument in the parameter list of a function will be on top of the
-operand stack. This is different than many Miden instructions which seemingly use the opposite convention, e.g. `add`, which expects the right-hand
-operand on top of the stack, so `a + b` is represented like `push a, push b, add`. If we were to implement `add` as a function, it would instead be
-`push b, push a, exec.add`. The rationale behind this is that, in general, the more frequently used arguments appear earlier in the parameter list,
-and thus we want those closer to the top of the operand stack to reduce the amount of stack manipulation we need to do.
-
-Arguments/return values are laid out on the operand stack just like they would be as if you had just loaded it from memory, so all arguments are aligned,
-but may span multiple operands on the operand stack as necessary based on the size of the type (i.e. a struct type that contains a `u32` and a `i1`
-field would require two operands to represent). If the maximum number of operands allowed for the call is reached, any remaining arguments must be
-spilled to the caller's stack frame, or to the advice provider. The former is used in the case of `exec`/`dynexec`, while the latter is used for `call`
-and `syscall`, as caller memory is not accessible to the callee with those instructions.
-
-While ostensibly 16 elements is the maximum number of operands on the operand stack that can represent function arguments, due to the way `dynexec`/`dyncall`
-work, it is actually limited to 12 elements, because at least 4 must be free to hold the hash of the function being indirectly called.
diff --git a/docs/src/assets/.gitkeep b/docs/src/assets/.gitkeep
deleted file mode 100644
index e69de29bb..000000000
diff --git a/docs/src/guides/develop_miden_rollup_accounts_and_note_scripts_in_rust.md b/docs/src/guides/develop_miden_rollup_accounts_and_note_scripts_in_rust.md
deleted file mode 100644
index 5e2145773..000000000
--- a/docs/src/guides/develop_miden_rollup_accounts_and_note_scripts_in_rust.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Developing Miden rollup accounts and note scripts in Rust
-
-This chapter walks you through how to develop Miden rollup accounts and note scripts in Rust using the Miden SDK crate.
\ No newline at end of file
diff --git a/docs/src/usage/debugger.md b/docs/src/usage/debugger.md
deleted file mode 100644
index e943a894d..000000000
--- a/docs/src/usage/debugger.md
+++ /dev/null
@@ -1,222 +0,0 @@
-# Debugging programs
-
-A very useful tool in the Miden compiler suite, is its TUI-based interactive debugger, accessible
-via the `midenc debug` command.
-
-> [!WARNING]
-> The debugger is still quite new, and while very useful already, still has a fair number of
-> UX annoyances. Please report any bugs you encounter, and we'll try to get them patched ASAP!
-
-## Getting started
-
-The debugger is launched by executing `midenc debug`, and giving it a path to a program compiled
-by `midenc compile`. See [Program Inputs](#program-inputs) for information on how to provide inputs
-to the program you wish to debug. Run `midenc help debug` for more detailed usage documentation.
-
-The debugger may also be used as a library, but that is left as an exercise for the reader for now.
-
-## Example
-
-```shell
-# Compile a program to MAST from a rustc-generated Wasm module
-midenc compile foo.wasm -o foo.masl
-
-# Load that program into the debugger and start executing it
-midenc debug foo.masl
-```
-
-## Program inputs
-
-To pass arguments to the program on the operand stack, or via the advice provider, you have two
-options, depending on the needs of the program:
-
-1. Pass arguments to `midenc debug` in the same order you wish them to appear on the stack. That
- is, the first argument you specify will be on top of the stack, and so on.
-2. Specify a configuration file from which to load inputs for the program, via the `--inputs` option.
-
-### Via command line
-
-To specify the contents of the operand stack, you can do so following the raw arguments separator `--`.
-Each operand must be a valid field element value, in either decimal or hexadecimal format. For example:
-
-```shell
-midenc debug foo.masl -- 1 2 0xdeadbeef
-```
-
-If you pass arguments via the command line in conjunction with `--inputs`, then the command line arguments
-will be used instead of the contents of the `inputs.stack` option (if set). This lets you specify a baseline
-set of inputs, and then try out different arguments using the command line.
-
-### Via inputs config
-
-While simply passing operands to the `midenc debug` command is useful, it only allows you to specify
-inputs to be passed via operand stack. To provide inputs via the advice provider, you will need to use
-the `--inputs` option. The configuration file expected by `--inputs` also lets you tweak the execution
-options for the VM, such as the maximum and expected cycle counts.
-
-An example configuration file looks like so:
-
-```toml
-# This section is used for execution options
-[options]
-max_cycles = 5000
-expected_cycles = 4000
-
-# This section is the root table for all inputs
-[inputs]
-# Specify elements to place on the operand stack, leftmost element will be on top of the stack
-stack = [1, 2, 0xdeadbeef]
-
-# This section contains input options for the advice provider
-[inputs.advice]
-# Specify elements to place on the advice stack, leftmost element will be on top
-stack = [1, 2, 3, 4]
-
-# The `inputs.advice.map` section is a list of advice map entries that should be
-# placed in the advice map before the program is executed. Entries with duplicate
-# keys are handled on a last-write-wins basis.
-[[inputs.advice.map]]
-# The key for this entry in the advice map
-digest = '0x3cff5b58a573dc9d25fd3c57130cc57e5b1b381dc58b5ae3594b390c59835e63'
-# The values to be stored under this key
-values = [1, 2, 3, 4]
-
-[[inputs.advice.map]]
-digest = '0x20234ee941e53a15886e733cc8e041198c6e90d2a16ea18ce1030e8c3596dd38''
-values = [5, 6, 7, 8]
-```
-
-## Usage
-
-Once started, you will be dropped into the main debugger UI, stopped at the first cycle of
-the program. The UI is organized into pages and panes, with the main/home page being the
-one you get dropped into when the debugger starts. The home page contains the following panes:
-
-* Source Code - displays source code for the current instruction, if available, with
- the relevant line and span highlighted, with syntax highlighting (when available)
-* Disassembly - displays the 5 most recently executed VM instructions, and the current
- cycle count
-* Stack Trace - displays a stack trace for the current instruction, if the program was
- compiled with tracing enabled. If frames are unavailable, this pane may be empty.
-* Operand Stack - displays the contents of the operand stack and its current depth
-* Breakpoints - displays the set of current breakpoints, along with how many were hit
- at the current instruction, when relevant
-
-### Keyboard shortcuts
-
-On the home page, the following keyboard shortcuts are available:
-
-Shortcut | Mnemonic | Description |
----------|----------------|---------------|
-`q` | quit | exit the debugger |
-`h` | next pane | cycle focus to the next pane |
-`l` | prev pane | cycle focus to the previous pane |
-`s` | step | advance the VM one cycle |
-`n` | step next | advance the VM to the next instruction |
-`c` | continue | advance the VM to the next breakpoint, else to completion |
-`e` | exit frame | advance the VM until we exit the current call frame, a breakpoint is triggered, or execution terminates |
-`d` | delete | delete an item (where applicable, e.g. the breakpoints pane) |
-`:` | command prompt | bring up the command prompt (see below for details) |
-
-When various panes have focus, additional keyboard shortcuts are available, in any pane
-with a list of items, or multiple lines (e.g. source code), `j` and `k` (or the up and
-down arrows) will select the next item up and down, respectively. As more features are
-added, I will document their keyboard shortcuts below.
-
-### Commands
-
-From the home page, typing `:` will bring up the command prompt in the footer pane.
-
-You will know the prompt is active because the keyboard shortcuts normally shown there will
-no longer appear, and instead you will see the prompt, starting with `:`. It supports any
-of the following commands:
-
-Command | Aliases | Action | Description |
--------------|--------------|-------------------|---------------|
-`quit` | `q` | quit | exit the debugger |
-`debug` | | show debug log | display the internal debug log for the debugger itself |
-`reload` | | reload program | reloads the program from disk, and resets the UI (except breakpoints) |
-`breakpoint` | `break`, `b` | create breakpoint | see [Breakpoints](#breakpoints) |
-`read` | `r` | read memory | inspect linear memory (see [Reading Memory](#reading-memory) |
-
-## Breakpoints
-
-One of the most common things you will want to do with the debugger is set and manage breakpoints.
-Using the command prompt, you can create breakpoints by typing `b` (or `break` or `breakpoint`),
-followed by a space, and then the desired breakpoint expression to do any of the following:
-
-* Break at an instruction which corresponds to a source file (or file and line) whose name/path
- matches a pattern
-* Break at the first instruction which causes a call frame to be pushed for a procedure whose name
- matches a pattern
-* Break any time a specific opcode is executed
-* Break at the next instruction
-* Break after N cycles
-* Break at CYCLE
-
-The syntax for each of these can be found below, in the same order (shown using `b` as the command):
-
-Expression | Description |
---------------------|---------------|
-`b FILE[:LINE]` | Break when an instruction with a source location in `FILE` (a glob pattern) _and_ that occur on `LINE` (literal, if provided) are hit. |
-`b in NAME` | Break when the glob pattern `NAME` matches the fully-qualified procedure name containing the current instruction |
-`b for OPCODE` | Break when the an instruction with opcode `OPCODE` is exactly matched (including immediate values) |
-`b next` | Break on the next instruction |
-`b after N` | Break after `N` cycles |
-`b at CYCLE` | Break when the cycle count reaches `CYCLE`. If `CYCLE` has already occurred, this has no effect |
-
-When a breakpoint is hit, it will be highlighted, and the breakpoint window will display the number
-of hit breakpoints in the lower right.
-
-After a breakpoint is hit, it expires if it is one of the following types:
-
-* Break after N
-* Break at CYCLE
-* Break next
-
-When a breakpoint expires, it is removed from the breakpoint list on the next cycle.
-
-## Reading memory
-
-Another useful diagnostic task is examining the contents of linear memory, to verify that expected
-data has been written. You can do this via the command prompt, using `r` (or `read`), followed by
-a space, and then the desired memory address and options:
-
-The format for read expressions is `:r ADDR [OPTIONS..]`, where `ADDR` is a memory address in
-decimal or hexadecimal format (the latter requires the `0x` prefix). The `read` command supports
-the following for `OPTIONS`:
-
-Option | Alias | Values | Default | Description |
-----------------|-------|-----------------|---------|--------------|
-`-mode MODE` | `-m` |
| `decimal` | Specify the format used to print integral values |
-`-count N` | `-c` | | `1` | Specify the number of units to read |
-`-type TYPE` | `-t` | See [Types](#types) | `word` | Specify the type of value to read This also has the effect of modifying the default `-format` and unit size for `-count` |
-
-Any invalid combination of options, or invalid syntax, will display an error in the status bar.
-
-### Types
-
-Type | Description |
---------|--------------|
-`iN` | A signed integer of `N` bits |
-`uN` | An unsigned integer of `N` bits |
-`felt` | A field element |
-`word` | A Miden word, i.e. an array of four field elements |
-`ptr` or `pointer` | A 32-bit memory address (implies `-format hex`) |
-
-## Roadmap
-
-The following are some features planned for the near future:
-
-* **Watchpoints**, i.e. cause execution to break when a memory store touches a specific address
-* **Conditional breakpoints**, i.e. only trigger a breakpoint when an expression attached to it
- evaluates to true
-* More DYIM-style breakpoints, i.e. when breaking on first hitting a match for a file or
- procedure, we probably shouldn't continue to break for every instruction to which that
- breakpoint technically applies. Instead, it would make sense to break and then temporarily
- disable that breakpoint until something changes that would make breaking again useful.
- This will rely on the ability to disable breakpoints, not delete them, which we don't yet
- support.
-* More robust type support in the `read` command
-* Display procedure locals and their contents in a dedicated pane