====== Lyx – Attribute & Pragmas (@-Referenz) ======
Attribute (auch Pragmas genannt) sind Compiler-Anweisungen, die mit ''@'' beginnen und vor einer Deklaration stehen. Sie steuern Optimierungen, Sicherheits-Verifikation, Speicherlayout und FFI-Verhalten. Attribute verändern nie die Semantik des Programms für korrekte Eingaben — sie sind Zusatzinformationen für den Compiler, nicht für den Laufzeit-Interpreter.
→ [[lyx_-_programmiersprache:tools:compiler-parameter|Compiler-Flags (CLI)]] · [[lyx_-_programmiersprache:guides:do-178c|DO-178C Compliance]] · [[lyx_-_programmiersprache:guides:das-energy-aware-programmiermodell|Energy-Aware Modell]] · [[lyx_-_programmiersprache:sprache:ffi|FFI – C-Interop]]
----
===== Übersicht =====
Alle Attribute auf einen Blick:
^ Attribut ^ Ziel ^ Kategorie ^ Beschreibung ^
| ''@dal(A–D)'' | Unit, Fn | Safety | Design Assurance Level nach DO-178C |
| ''@flight_crit'' | Unit, Fn | Safety | Strikte Luftfahrt-Regeln (kein Heap, kein FP-Opt) |
| ''@integrity(...)'' | Unit, Fn | Safety | Memory Scrubbing oder Software Lockstep |
| ''@redundant'' | Variable | Safety | Triple Modular Redundancy (TMR) |
| ''@stack_limit(N)'' | Fn | Safety | Maximaler Stack-Verbrauch in Bytes |
| ''@wcet(N)'' | Fn | Safety | Worst-Case Execution Time in Zyklen |
| ''@energy(1–5)'' | Unit, Fn | Performance | Energy-Aware-Backend-Level |
| ''@inline'' | Fn | Performance | Inlining erzwingen |
| ''@noinline'' | Fn | Performance | Inlining verbieten |
| ''@no_opt'' | Fn | Performance | Alle IR-Optimierungen deaktivieren |
| ''@parallel'' | Loop, Array | Performance | SIMD-Vektorisierung erlauben |
| ''@section("name")'' | Fn, Var | Layout | ELF-Sektion explizit setzen |
| ''@packed'' | Struct | Layout | Struct-Padding unterdrücken |
| ''@at(N)'' | Struct-Feld | Layout | Explizites Byte-Offset eines Struct-Felds |
| ''@big_endian'' | Struct-Feld | Layout | Mehrbyte-Feld als Big-Endian interpretieren |
| ''@volatile'' | Variable | FFI | Speicherzugriff nicht wegoptimieren |
| ''@extern'' | Fn | FFI | Externe C/Assembly-Funktion deklarieren |
| ''@export'' | Fn, Var | FFI | Symbol in Shared Library exportieren |
| ''@stdcall'' | Fn | FFI | Windows-Aufrufkonvention (''__stdcall'') |
| ''@variadic'' | Fn | FFI | C-varargs-Funktion wrappen |
| ''@allow_unsafe'' | Fn, Block | Safety | ''unsafe''-Blöcke in DAL-gesichertem Code erlauben |
----
===== Safety-Attribute =====
Attribute für sicherheitskritischen und zertifizierungspflichtigen Code:
==== @dal(A–D) ====
Legt das **Design Assurance Level** nach DO-178C fest. Beeinflusst, welche Lint-Prüfungen aktiv sind und ob bestimmte Sprachfeatures verboten werden.
@dal(A)
unit flight_control;
@dal(B)
fn ProcessSensorData(raw: int64): int64 { ... }
^ Level ^ Bedeutung ^ Einschränkungen ^
| ''@dal(A)'' | Katastrophaler Ausfall möglich | Kein ''unsafe'', kein unbounded loop, exhaustive match, kein ''default'' im Enum-match |
| ''@dal(B)'' | Gefährlicher Ausfall möglich | Kein ''unsafe'', unbounded loops mit Warnung |
| ''@dal(C)'' | Größerer Ausfall möglich | Empfehlungen, keine harten Verbote |
| ''@dal(D)'' | Geringfügiger Ausfall möglich | Nur Dokumentation, keine Compiler-Einschränkungen |
----
==== @flight_crit ====
Aktiviert den strengsten Kompilierungsmodus für sicherheitskritische Funktionen:
@flight_crit
@dal(A)
@stack_limit(512)
fn ComputeFlightPath(state: ^FlightState): FlightCommands { ... }
Impliziert automatisch:
* ''@energy(1)'' — kein aggressives Unrolling, keine SIMD-Spekulation
* ''--no-fp-fold'' für diese Funktion — keine FPU-Optimierungen
* Verbot von ''new''/''alloc'' im Rumpf
* Verbot von Rekursion ohne ''@stack_limit''
* Exhaustive ''match'' über alle Enum-Werte (kein ''default'' in DAL-A)
Kompatibel mit ''@energy(2)'' wenn explizit annotiert (zulässig für DAL-B):
@flight_crit
@energy(2) // energy-Barriere: überschreibt das implizite @energy(1)
@dal(B)
fn FilterAltitude(raw: f64): f64 { ... }
----
==== @integrity(...) ====
Aktiviert Laufzeit-Integritätsprüfung. Zwei Modi:
// Modus 1: Memory Scrubbing (periodischer CRC32-Sweep des Code-Segments)
@integrity(mode: scrubbed, interval: 100)
unit nav.core;
// Modus 2: Software Lockstep (duplizierte ALU-Operationen, Vergleich vor Return)
@integrity(mode: software_lockstep)
@dal(A)
fn ComputeHeading(imu: ^IMUData): f64 { ... }
^ Parameter ^ Typ ^ Beschreibung ^
| ''mode: scrubbed'' | – | CRC32-Sweep des Code-Segments alle ''interval'' ms |
| ''mode: software_lockstep'' | – | Berechnungen doppelt ausführen, Ergebnis vergleichen |
| ''interval: N'' | int (ms) | Sweep-Intervall für ''scrubbed''-Modus |
→ Details: [[lyx_-_programmiersprache:guides:do-178c:memory-scrubbing|Memory Scrubbing]] · [[lyx_-_programmiersprache:guides:do-178c:software-lockstep|Software Lockstep]]
----
==== @redundant ====
Speichert eine Variable dreifach im RAM (Sektionen ''.tmr_a'', ''.tmr_b'', ''.tmr_c''). Jeder Lesezugriff führt einen Mehrheitsentscheid durch; ein korrumpiertes Exemplar wird automatisch repariert.
@redundant
var flight_mode: int64 := 0;
@redundant
var altitude_m: f64 := 0.0;
* Nur für globale und Unit-Level-Variablen; Stack-Variablen werden vom Compiler abgelehnt
* Speicherbedarf: 3× Variablengröße plus Alignment
* Prüfbar mit ''--verify-tmr''
→ Details: [[lyx_-_programmiersprache:guides:do-178c:triple_modular_redundancy|TMR]]
----
==== @stack_limit(N) ====
Setzt ein hartes Limit für den maximalen Stack-Verbrauch einer Funktion in Bytes (inklusive aller transitiv aufgerufenen Funktionen). Wird mit ''--stack-check'' statisch verifiziert.
@stack_limit(2048)
fn ParsePacket(buf: pchar, len: int64): bool { ... }
@stack_limit(128)
@flight_crit
fn SysTick_Handler(): void { ... } // ISR: sehr wenig Stack erlaubt
* Bei Überschreitung: Compiler-Fehler (kein Laufzeitfehler)
* Rekursion ohne nachweisbare Schranke → automatischer Fehler
----
==== @wcet(N) ====
Gibt die maximal erlaubte **Worst-Case Execution Time** in CPU-Zyklen an. Wird mit ''--wcet'' analysiert.
@wcet(200)
@dal(A)
fn ReadIMU(buf: ^IMUBuffer): void { ... }
@wcet(500)
fn FilterAltitude(raw: f64): f64 { ... }
* Der Compiler schätzt die WCET über Loop-Bounds und Call-Graph
* Software-Lockstep verdoppelt die effektive WCET (~2×)
* Ergebnis im ''--wcet''-Report: geschätzter Wert vs. annotiertes Limit
----
==== @allow_unsafe ====
Erlaubt ''unsafe''-Blöcke in Funktionen, die unter ''@dal(A/B)'' stehen. Normalerweise ist ''unsafe'' in DAL-A/B-Modulen ein Compiler-Fehler.
@allow_unsafe
@dal(B)
fn WriteMappedRegister(addr: int64, val: int64): void {
unsafe {
poke64(addr, val); // Direkte Hardware-Registerschreibung
}
}
* Jede Verwendung erscheint im ''--provenance''-Log als Sicherheitsausnahme
* Anforderung im DO-178C-Prozess: schriftliche Begründung im Review
----
===== Performance-Attribute =====
Attribute zur Steuerung von Optimierungen und Code-Generierung:
==== @energy(1–5) ====
Steuert das Energy-Aware-Backend für diese Funktion. Überschreibt das globale ''--target-energy''-Level und erzeugt eine **Energy-Barriere** — inlinierte Aufrufer übernehmen das Level dieser Funktion nicht.
@energy(1)
fn IdleSensor(): void { ... } // Batterie-optimiert
@energy(5)
fn MatMulKernel(a: int64, b: int64, out: int64): void { ... } // Max-Performance
→ Details und Level-Tabelle: [[lyx_-_programmiersprache:guides:das-energy-aware-programmiermodell|Energy-Aware Modell]]
----
==== @inline ====
Erzwingt das Inlining der Funktion an jedem Aufrufpunkt. Der Compiler ersetzt den Aufruf durch den Funktionskörper.
@inline
fn Clamp(v: int64, lo: int64, hi: int64): int64 {
return if (v < lo) { lo } else if (v > hi) { hi } else { v };
}
* Nützlich für sehr kleine Funktionen, die in Hot-Paths aufgerufen werden
* Vergrößert den Code bei häufigem Aufruf
* In ''@integrity(mode: software_lockstep)''-Funktionen: nicht erlaubt (Lockstep erfordert definierte Call-Grenzen)
----
==== @noinline ====
Verhindert das automatische Inlining durch den Compiler. Nützlich für Funktionen, die im Call-Graph sichtbar bleiben müssen (''--call-graph'', Stack-Analyse) oder für stabile ABI-Grenzen.
@noinline
fn VerifyChecksum(buf: pchar, len: int64): bool { ... }
----
==== @no_opt ====
Deaktiviert alle IR-Optimierungen für diese Funktion: kein Constant Folding, kein Dead Code Elimination, kein Loop Unrolling, kein Register Coalescing.
@no_opt
fn BusyWait(cycles: int64): void {
var i: int64 := 0;
while (i < cycles) limit(1000000) {
i := i + 1;
}
}
Einsatz: Timing-kritische Treiber-Funktionen, bei denen der Compiler Instruktionen nicht umordnen darf; Debugging.
----
==== @parallel ====
Signalisiert dem Compiler, dass eine Schleife oder ein Array-Ausdruck sicher für **SIMD-Vektorisierung** ist — keine Abhängigkeiten zwischen Iterationen.
fn AddArrays(a: pchar, b: pchar, out: pchar, n: int64): void {
var i: int64 := 0;
@parallel
while (i < n) limit(1000000) {
poke8(out + i, peek8(a + i) + peek8(b + i));
i := i + 1;
}
}
* Auf x86_64: SSE2/AVX2; auf ARM64: NEON/SVE (je nach ''--target-energy'')
* Voraussetzung: keine Pointer-Aliasing zwischen ''a'', ''b'' und ''out''
* Kann mit ''@energy(4/5)'' kombiniert werden für maximalen Durchsatz
----
===== Layout-Attribute =====
Attribute für explizite Kontrolle über Speicherplatzierung und Struct-Layout:
==== @section("name") ====
Platziert eine Funktion oder Variable in eine benannte ELF-Sektion. Notwendig für Linker-Skripte (Bare-Metal, Flash/RAM-Aufteilung) und Interrupt-Vektoren.
@section(".isr_vector")
@no_opt
fn SysTick_Handler(): void {
scrub_tick := scrub_tick + 1;
}
@section(".fast_ram")
var dsp_buffer: int64 := 0; // In schnellem SRAM ablegen
@section(".slow_mem")
fn ColdInitRoutine(): void { ... } // In langsamem Flash
* Sektionsname muss im Linker-Skript definiert sein
* Typische Namen: ''.isr_vector'', ''.fast_ram'', ''.slow_mem'', ''.ccmram'', ''.backup_sram''
----
==== @packed ====
Unterdrückt Alignment-Padding in einer Struct-Definition. Felder folgen ohne Lücken aufeinander. Notwendig für Hardware-Register-Maps, Netzwerk-Paket-Header, binäre Protokolle.
@packed
class EthernetHeader {
var dst_mac: int64; // 6 Bytes
var src_mac: int64; // 6 Bytes
var ethertype: int64; // 2 Bytes
// Gesamt: exakt 14 Bytes — kein Padding
}
@packed
class CANFrame {
var id: int64; // 4 Bytes (11-Bit-ID + Flags)
var dlc: int64; // 1 Byte (Data Length Code)
var data: int64; // 8 Bytes (Nutzdaten)
}
* Unaligned-Zugriffe können auf manchen Architekturen (ARM Cortex-M0) Faults auslösen
* Auf x86_64 immer sicher, auf ARM64 mit LDUR/STUR
----
==== @at(N) ====
Setzt das **explizite Byte-Offset** eines Struct-Felds innerhalb der Struktur. Ermöglicht präzises Mapping auf binäre Protokoll-Header oder Memory-Mapped-Register-Layouts, ohne sich auf implizites Padding zu verlassen.
type BRRConfig = struct {
@at(0) var mantissa: u16;
@at(8) var fraction: u8;
@at(16) var reserved: u8;
}
type MixedMap = struct {
@at(0) var flags: u8;
@at(4) var counter: u32;
@at(8) var payload: u64;
}
Der Compiler überprüft drei Invarianten:
^ Prüfung ^ Fehler wenn … ^
| Konstanter Ausdruck | N ist kein zur Compile-Zeit auswertbarer Wert |
| Monotonie | Offset ≤ Offset des vorherigen Felds |
| Kein Overlap | Offset + sizeof(Feld) > Offset des nächsten Felds |
Unterstützte Feldtypen: ''u8'', ''u16'', ''u32'', ''u64'', ''i8'', ''i16'', ''i32'', ''i64'', ''f32'', ''f64'', ''bool'', ''pchar''.
* Kann mit ''@packed'' kombiniert werden — ''@packed'' entfernt implizites Padding; ''@at'' setzt dann absolute Positionen
* Felder ohne ''@at'' dürfen in derselben Struct **nicht** gemischt werden — entweder alle Felder haben ''@at'' oder keines
----
==== @big_endian ====
Markiert ein Struct-Feld als **Big-Endian** (Network Byte Order). Lese- und Schreibzugriffe auf das Feld erzeugen automatisch Byte-Swap-Instruktionen (''bswap'' auf x86_64, ''rev'' auf ARM64).
type EthernetHeader = struct {
@at(0) @big_endian var ethertype: u16; // z. B. 0x0800 für IPv4
@at(2) @big_endian var total_len: u16;
@at(4) @big_endian var ident: u16;
@at(6) @big_endian var frag_off: u16;
@at(8) var ttl: u8;
@at(9) var protocol: u8;
@at(10) @big_endian var checksum: u16;
}
* Nur sinnvoll für Felder ≥ 2 Bytes (''u8''/''i8'' sind byteorder-neutral)
* Erfordert ''@at(N)'' auf demselben Feld — freischwebendes ''@big_endian'' ohne Offset-Angabe ist ein Compiler-Fehler
* Kein Overhead auf Plattformen mit nativer Big-Endian-Unterstützung (der Compiler optimiert den Swap weg)
----
===== FFI-Attribute =====
Attribute für die Interoperabilität mit externen Bibliotheken und C-Code:
==== @extern ====
Deklariert eine Funktion, die außerhalb von Lyx (in C, C++ oder Assembly) definiert ist. Der Linker löst den Verweis auf.
@extern
fn malloc(size: int64): int64;
@extern
fn printf(fmt: pchar): int64;
@extern
fn clock_gettime(clk_id: int64, tp: int64): int64;
* Kein Funktionskörper — nur Signatur
* ABI: Standard-C-Aufrufkonvention (System V AMD64 auf Linux, AAPCS64 auf ARM64)
* Für Windows-API: kombinieren mit ''@stdcall''
→ Details: [[lyx_-_programmiersprache:sprache:ffi|FFI – C-Interop]]
----
==== @export ====
Exportiert ein Symbol in eine Shared Library (''.so''/DLL). Ohne ''@export'' sind Symbole in Shared Libraries standardmäßig nicht sichtbar (''visibility=hidden'').
@export
fn PluginInit(config: pchar): bool { ... }
@export
fn PluginProcess(data: int64, len: int64): int64 { ... }
@export
var plugin_version: int64 := 3;
* Benötigt ''--shared'' beim Compile
* Erzeugt einen Eintrag in der ''.dynsym''-Tabelle des ELF
----
==== @volatile ====
Verhindert, dass der Compiler Lese- und Schreibzugriffe auf eine Variable wegoptimiert, zwischenspeichert oder umordnet. Essentiell für Memory-Mapped I/O und ISR-Kommunikation.
@volatile var uart_data_reg: int64 := 0x40011004; // UART-Datenregister-Adresse
@volatile var isr_flag: int64 := 0; // Gesetzt von ISR, gelesen von Main
fn WaitForData(): void {
while (isr_flag = 0) limit(1000000) { } // Ohne @volatile würde der Compiler dieses Loop wegoptimieren
isr_flag := 0;
}
----
==== @stdcall ====
Erzwingt die Windows-''__stdcall''-Aufrufkonvention. Der Aufgerufene bereinigt den Stack (nicht der Aufrufer). Notwendig für Windows-API-Funktionen und COM-Interfaces.
@extern
@stdcall
fn MessageBoxA(hwnd: int64, text: pchar, caption: pchar, utype: int64): int64;
@extern
@stdcall
fn CreateFileA(lpFileName: pchar, dwAccess: int64, dwShare: int64,
lpSecurity: int64, dwCreation: int64, dwFlags: int64,
hTemplate: int64): int64;
----
==== @variadic ====
Markiert eine Funktion als C-varargs-Wrapper. Ermöglicht die Weitergabe variabler Argumentlisten an externe C-Funktionen.
@extern
@variadic
fn printf(fmt: pchar): int64;
@extern
@variadic
fn snprintf(buf: pchar, size: int64, fmt: pchar): int64;
* Lyx selbst hat keine variadischen Funktionen — ''@variadic'' ist ausschließlich für ''@extern''-Deklarationen
* Typunsicher: Argumente werden nicht vom Compiler geprüft
----
===== Kombinations-Regeln =====
Nicht alle Attribute sind kompatibel. Hier die wichtigsten Einschränkungen:
^ Kombination ^ Erlaubt? ^ Hinweis ^
| ''@flight_crit'' + ''@energy(1)'' | ✅ | ''@energy(1)'' ist implizit, explizit redundant aber harmlos |
| ''@flight_crit'' + ''@energy(2)'' | ✅ | Erfordert ''@dal(B)'' oder explizite ''@allow_unsafe''-Begründung |
| ''@flight_crit'' + ''@energy(4/5)'' | ❌ | Compiler-Fehler: widerspricht der No-Speculation-Anforderung |
| ''@integrity(lockstep)'' + ''@inline'' | ❌ | Lockstep erfordert definierte Call-Grenzen |
| ''@integrity(lockstep)'' + ''@extern'' | ❌ | Externe Funktionen können nicht dupliziert werden |
| ''@redundant'' auf Stack-Variable | ❌ | Nur für global/Unit-Level |
| ''@parallel'' + ''@no_opt'' | ❌ | ''@no_opt'' deaktiviert SIMD-Vektorisierung |
| ''@dal(A)'' + ''unsafe'' (ohne ''@allow_unsafe'') | ❌ | Compiler-Fehler |
| ''@packed'' + ''@section'' | ✅ | Häufige Kombination für Hardware-Register-Structs |
| ''@at(N)'' + ''@packed'' | ✅ | ''@packed'' entfernt implizites Padding; ''@at'' legt Positionen absolut fest |
| ''@at(N)'' + ''@big_endian'' | ✅ | Standardkombination für Netzwerk-Header-Felder |
| ''@big_endian'' ohne ''@at(N)'' | ❌ | Compiler-Fehler: Offset-Angabe fehlt |
| ''@at(N)'' + Feld ohne ''@at'' in derselben Struct | ❌ | Compiler-Fehler: gemischtes Layout nicht erlaubt |
| ''@volatile'' + ''@no_opt'' | ✅ | Maximale Garantie gegen Compiler-Umordnung |
| ''@extern'' + ''@stdcall'' | ✅ | Standard für Windows-API |
| ''@extern'' + ''@variadic'' | ✅ | Standard für printf-Familie |
----
===== Weiterführende Seiten =====
* [[lyx_-_programmiersprache:tools:compiler-parameter|Compiler-Parameter – alle CLI-Flags (--stack-check, --wcet, --lint, …)]]
* [[lyx_-_programmiersprache:guides:do-178c|DO-178C – @dal, @flight_crit, @wcet im Zertifizierungskontext]]
* [[lyx_-_programmiersprache:guides:das-energy-aware-programmiermodell|Energy-Aware Programmiermodell – @energy im Detail]]
* [[lyx_-_programmiersprache:sprache:ffi|FFI – @extern, @stdcall, @variadic mit C-Bibliotheken]]
* [[lyx_-_programmiersprache:guides:do-178c:triple_modular_redundancy|TMR – @redundant im Detail]]
* [[lyx_-_programmiersprache:guides:do-178c:software-lockstep|Software Lockstep – @integrity(lockstep) im Detail]]
Letzte Aktualisierung: 2026-06-06