====== 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