X-Code ist ein typisierter Assemblerdialekt innerhalb von BASIC. Virtuelle Register beschreiben Werte; der Compiler übernimmt ihre Zuweisung zu physischen Registern. Speicheroperationen benennen ihre Breite ausdrücklich.
X-Code ist ein typisierter Assemblerdialekt innerhalb von BASIC. Virtuelle Register beschreiben Werte; der Compiler übernimmt ihre Zuweisung zu physischen Registern. Speicheroperationen benennen ihre Breite ausdrücklich. Grafik in voller Größe öffnen

X-Code: Beispiele und Erklärung

X-Code ist ein typisierter Assemblerdialekt innerhalb von BASIC. Virtuelle Register beschreiben Werte; der Compiler übernimmt ihre Zuweisung zu physischen Registern. Speicheroperationen benennen ihre Breite ausdrücklich.

Zwölf Kurzbeispiele und ein größeres Programm. Wählen Sie ein Thema oder arbeiten Sie die Beispiele der Reihe nach durch.

Die neuen Kontrollfluss- und Registerfälle beziehen sich auf den V22-Quellstand; die finale V22-Ausführung bleibt ausstehend.

1. 1 + 2 + 3 + 4 + 5 = 15

Die Zahlen 1 bis 5 werden zu 15 addiert. Der Rückgabewert 15 wird als Prozess-Exitcode geprüft.

#COMPILE EXE
#DIM ALL
FUNCTION PBMAIN() AS LONG
    LOCAL total AS LONG
    #XCODE
        X.VREG sum:U64
        X.MOVE V(sum), 1
        X.ADD V(sum), 2
        X.ADD V(sum), 3
        X.ADD V(sum), 4
        X.ADD V(sum), 5
        X.STORE QWORD PTR [total], V(sum)
    #ENDX
    FUNCTION = total
END FUNCTION

Erwarteter Exitcode: 15

PBXB64.exe sum15-xcode.pb -O2 -o example.exe
.\example.exe
$LASTEXITCODE

Quelltext herunterladen

Nativ geprüft mit dem V22-Kandidaten vom 30.09.2026; Prüfung mit dem finalen Compiler noch ausstehend.

2. Eigenes XCODE-Makro und BASIC-Wert

Die Definitionssektion legt X.vendor.ADD5 an. PBMAIN startet host_value bei 7; das Makro addiert 5, und X.STORE schreibt 12 zurück. PBMAIN liefert host_value - 12, also 0 beim richtigen Ergebnis. X.LOCAL hält die Sprungmarke makrolokal.

' XCODE first-release integration: typed virtual registers lower to the
' existing inline-ASM stub/object pipeline and execute without XCODE text.
#COMPILE EXE
#DIM ALL
GLOBAL host_value AS LONG

#XCODE MODE=DEFINITIONS
    X.MACRO X.vendor.ADD5(INOUT dst:U32)
        X.ADD $dst, 5
        X.LOCAL done:LABEL
        X.RAW
            jmp $done
        $done:
        X.ENDRAW
    X.ENDMACRO
#ENDX

FUNCTION PBMAIN() AS LONG
    host_value = 7
    #XCODE OPT=2, SPILL=AUTO, FEATURES=AUTO
        X.VREG value:U32
        X.MOVE V(value), %host_value
        X.vendor.ADD5 V(value)
        X.STORE %host_value, V(value)
        X.RAW
            nop
        X.ENDRAW
    #ENDX
    PBMAIN = host_value - 12
END FUNCTION

Erwarteter Exitcode: 0

PBXB64.exe test_xcode.pb -O2 -o example.exe
.\example.exe
$LASTEXITCODE

Quelltext herunterladen

Kanonischer Testfall mit erwartetem Ergebnis; hier keine neue native V22-Prüfung. Finale Ausführung noch ausstehend.

3. Konstante unter Registerdruck erhalten

Der Fall vermeidet die aufgelisteten physischen Register und fordert AUTO/SPILL=AUTO an. Der Wert 7 muss trotzdem in remat_result ankommen. Der Test zielt auf sichere Konstanten-Neuerzeugung; er ist keine allgemeine Leistungszusage. Die globale LONG-Speicherstelle beginnt bei 0, DWORD schreibt ihre unteren 32 Bit.

' XCODE AUTO rematerializes a safe integer constant instead of spill traffic.
#COMPILE EXE
#DIM ALL
GLOBAL remat_result AS LONG

FUNCTION PBMAIN() AS LONG
    #XCODE REGALLOC=AUTO, SPILL=AUTO
        X.VREG constant:U32
        X.ALLOC AVOID V(constant), r10, r11, r8, r9, rax, rcx, rdx, rdi, rsi, rbx, rbp, r12, r13, r14, r15
        X.MOVE V(constant), 7
        X.STORE DWORD PTR [remat_result], V(constant)
    #ENDX
    IF remat_result <> 7 THEN
        PBMAIN = 1
        EXIT FUNCTION
    END IF
    PBMAIN = 0
END FUNCTION

Erwarteter Exitcode: 0

PBXB64.exe test_xcode_regalloc_constant.pb -O2 -o example.exe
.\example.exe
$LASTEXITCODE

Quelltext herunterladen

Kanonischer Testfall mit erwartetem Ergebnis; hier keine neue native V22-Prüfung. Finale Ausführung noch ausstehend.

4. Ein Register festlegen und ein anderes ausschließen

Ablauf Schritt für Schritt

  1. REGALLOC=MANUAL aktiviert die ausdrücklich angegebene Zuweisungspolitik.
  2. PIN verlangt r12 für acc; AVOID verhindert die Nutzung dieses Registers durch tmp.
  3. X.ZERO initialisiert beide Werte. Der DWORD-Store schreibt 32 Bit des auf 0 initialisierten LONG-Slots; Exitcode 0 prüft nur den Abschluss dieses Zuweisungsfalls.
' XCODE manual allocation policy regression.
#COMPILE EXE
#DIM ALL
GLOBAL manual_result AS LONG

FUNCTION PBMAIN() AS LONG
    #XCODE REGALLOC=MANUAL
        X.VREG acc:U64
        X.VREG tmp:U64
        X.ALLOC PIN V(acc), r12
        X.ALLOC AVOID V(tmp), r12
        X.ZERO V(acc)
        X.ZERO V(tmp)
        X.STORE DWORD PTR [manual_result], V(tmp)
    #ENDX
    PBMAIN = 0
END FUNCTION

Erwarteter Exitcode: 0

PBXB64.exe xcode-test_xcode_regalloc_manual.pb -O2 -o example.exe
.\example.exe
$LASTEXITCODE

Quelltext herunterladen

Erwartung aus dem Quelltext abgeleitet; kein aktueller registrierter Laufvertrag. Keine neue native Compilerprüfung in dieser Website-Erweiterung. Finale Ausführung mit dem freigegebenen Compiler steht aus.

5. Eine Registerpräferenz angeben

Ablauf Schritt für Schritt

  1. preferred ist ein virtueller U32-Wert.
  2. PREFER nennt r12 als bevorzugtes physisches Register; eine Präferenz ist keine allgemeine Festlegung des erzeugten Assemblers.
  3. X.ZERO und der DWORD-Store ergeben einen gespeicherten Nullwert. Das Beispiel demonstriert die Syntax der Präferenz.
' XCODE manual preference regression.
#COMPILE EXE
#DIM ALL
GLOBAL prefer_result AS LONG
FUNCTION PBMAIN() AS LONG
    #XCODE REGALLOC=MANUAL
        X.VREG preferred:U32
        X.ALLOC PREFER V(preferred), r12
        X.ZERO V(preferred)
        X.STORE DWORD PTR [prefer_result], V(preferred)
    #ENDX
    PBMAIN = 0
END FUNCTION

Erwarteter Exitcode: 0

PBXB64.exe xcode-test_xcode_regalloc_prefer.pb -O2 -o example.exe
.\example.exe
$LASTEXITCODE

Quelltext herunterladen

Erwartung aus dem Quelltext abgeleitet; kein aktueller registrierter Laufvertrag. Keine neue native Compilerprüfung in dieser Website-Erweiterung. Finale Ausführung mit dem freigegebenen Compiler steht aus.

6. Konkurrierende Registerwünsche

Ablauf Schritt für Schritt

  1. left und right sind zwei getrennte virtuelle U32-Werte, deren PIN-Wünsche dasselbe Register nennen.
  2. Beide Werte werden definiert und in X.ADD verwendet; der Compiler muss ihre logischen Werte getrennt behandeln.
  3. Das Zuweisungsprüfskript prüft Übersetzung und Zuweisungsbericht; eine native Programmausführung steht hier aus. Die konkrete physische Lösung wird nicht als optimaler Assembler belegt.
' XCODE conflicting PIN requests must be remapped safely.
#COMPILE EXE
#DIM ALL
GLOBAL remap_result AS LONG

FUNCTION PBMAIN() AS LONG
    #XCODE REGALLOC=MANUAL
        X.VREG left:U32
        X.VREG right:U32
        X.ALLOC PIN V(left), r12
        X.ALLOC PIN V(right), r12
        X.ZERO V(left)
        X.ZERO V(right)
        X.ADD V(right), V(left)
        X.STORE DWORD PTR [remap_result], V(right)
    #ENDX
    PBMAIN = 0
END FUNCTION

Erwarteter Exitcode: 0

PBXB64.exe xcode-test_xcode_regalloc_remap.pb -O2 -o example.exe
.\example.exe
$LASTEXITCODE

Quelltext herunterladen

Erwartung aus dem Quelltext abgeleitet; kein aktueller registrierter Laufvertrag. Keine neue native Compilerprüfung in dieser Website-Erweiterung. Finale Ausführung mit dem freigegebenen Compiler steht aus.

7. Eine Speicheradresse als PTR-Wert

Ablauf Schritt für Schritt

  1. address hat den Zeigertyp PTR; AVOID schränkt die angebotenen physischen Register ein.
  2. X.LEA bildet die Adresse des globalen LONG-Slots, ohne dessen Inhalt zu lesen.
  3. X.STORE QWORD schreibt die 64-Bit-Adresse in diesen acht Byte breiten Slot. Der konkrete Zahlenwert der Adresse ist bei jedem Prozesslauf variabel.
#COMPILE EXE
#DIM ALL
GLOBAL address_result AS LONG
FUNCTION PBMAIN() AS LONG
    #XCODE REGALLOC=AUTO
        X.VREG address:PTR
        X.ALLOC AVOID V(address), r10, r11, r8, r9, rax, rcx, rdx, rdi, rsi, rbx, rbp, r12, r13, r14, r15
        X.LEA V(address), BYTE PTR [address_result]
        X.STORE QWORD PTR [address_result], V(address)
    #ENDX
    PBMAIN = 0
END FUNCTION

Erwarteter Exitcode: 0

PBXB64.exe xcode-test_xcode_regalloc_address.pb -O2 -o example.exe
.\example.exe
$LASTEXITCODE

Quelltext herunterladen

Erwartung aus dem Quelltext abgeleitet; kein aktueller registrierter Laufvertrag. Keine neue native Compilerprüfung in dieser Website-Erweiterung. Finale Ausführung mit dem freigegebenen Compiler steht aus.

8. Drei virtuelle Werte in zwei Additionen

Ablauf Schritt für Schritt

  1. a, b und c sind getrennte U32-Register und werden ausdrücklich auf 0 gesetzt.
  2. X.ADD V(a), V(b) und danach X.ADD V(a), V(c) schreiben jeweils wieder nach a.
  3. Der gespeicherte Wert ist 0; das Beispiel zeigt eine Wertabhängigkeit über mehrere Anweisungen.
#COMPILE EXE
#DIM ALL
GLOBAL reference_result AS LONG
FUNCTION PBMAIN() AS LONG
    #XCODE REGALLOC=AUTO
        X.VREG a:U32
        X.VREG b:U32
        X.VREG c:U32
        X.ZERO V(a)
        X.ZERO V(b)
        X.ZERO V(c)
        X.ADD V(a), V(b)
        X.ADD V(a), V(c)
        X.STORE DWORD PTR [reference_result], V(a)
    #ENDX
    PBMAIN = 0
END FUNCTION

Erwarteter Exitcode: 0

PBXB64.exe xcode-test_xcode_regalloc_reference.pb -O2 -o example.exe
.\example.exe
$LASTEXITCODE

Quelltext herunterladen

Erwartung aus dem Quelltext abgeleitet; kein aktueller registrierter Laufvertrag. Keine neue native Compilerprüfung in dieser Website-Erweiterung. Finale Ausführung mit dem freigegebenen Compiler steht aus.

9. Ein Ergebnis aus zwei X.IF-Zweigen

Ablauf Schritt für Schritt

  1. cond und guard sind beide 0; der Gleichvergleich wählt den ersten Zweig.
  2. Jeder Zweig definiert seinen eigenen Zwischenwert und überträgt ihn in out.
  3. Nach X.ENDIF ist out im erreichten Pfad definiert und wird gespeichert. Das Beispiel zeigt, warum die Registeranalyse Kontrollfluss berücksichtigen muss.
#COMPILE EXE
#DIM ALL
GLOBAL liveness_result AS LONG
FUNCTION PBMAIN() AS LONG
    #XCODE REGALLOC=AUTO
        X.VREG cond:U32
        X.VREG guard:U32
        X.VREG left:U32
        X.VREG right:U32
        X.VREG out:U32
        X.ZERO V(cond)
        X.ZERO V(guard)
        X.IF V(cond) == V(guard)
            X.ZERO V(left)
            X.MOVE V(out), V(left)
        X.ELSE
            X.ZERO V(right)
            X.MOVE V(out), V(right)
        X.ENDIF
        X.STORE DWORD PTR [liveness_result], V(out)
    #ENDX
    PBMAIN = 0
END FUNCTION

Erwarteter Exitcode: 0

PBXB64.exe xcode-test_xcode_regalloc_liveness.pb -O2 -o example.exe
.\example.exe
$LASTEXITCODE

Quelltext herunterladen

Erwartung aus dem Quelltext abgeleitet; kein aktueller registrierter Laufvertrag. Keine neue native Compilerprüfung in dieser Website-Erweiterung. Finale Ausführung mit dem freigegebenen Compiler steht aus.

10. Einen sicheren Nullwert erneut bilden

Ablauf Schritt für Schritt

  1. REGALLOC=AUTO und SPILL=AUTO lassen den Compiler Ausweichstrategien verwenden.
  2. Die AVOID-Liste erzeugt starken Registerdruck für den virtuellen Nullwert.
  3. Ein mit X.ZERO erzeugter Wert kann sicher erneut als 0 gebildet werden. Die BASIC-Prüfung kontrolliert den gespeicherten Wert; sie misst keine Geschwindigkeit.
' XCODE AUTO rematerializes a safe zero definition instead of spill traffic.
#COMPILE EXE
#DIM ALL
GLOBAL remat_result AS LONG

FUNCTION PBMAIN() AS LONG
    #XCODE REGALLOC=AUTO, SPILL=AUTO
        X.VREG zero:U32
        X.ALLOC AVOID V(zero), r10, r11, r8, r9, rax, rcx, rdx, rdi, rsi, rbx, rbp, r12, r13, r14, r15
        X.ZERO V(zero)
        X.STORE DWORD PTR [remat_result], V(zero)
    #ENDX
    IF remat_result <> 0 THEN
        PBMAIN = 1
        EXIT FUNCTION
    END IF
    PBMAIN = 0
END FUNCTION

Erwarteter Exitcode: 0

PBXB64.exe xcode-test_xcode_regalloc_remat.pb -O2 -o example.exe
.\example.exe
$LASTEXITCODE

Quelltext herunterladen

Erwartung aus dem Quelltext abgeleitet; kein aktueller registrierter Laufvertrag. Keine neue native Compilerprüfung in dieser Website-Erweiterung. Finale Ausführung mit dem freigegebenen Compiler steht aus.

11. Eine spätere Neudefinition eines Registers

Ablauf Schritt für Schritt

  1. first und middle werden zunächst auf 0 gesetzt.
  2. Der Store verwendet middle, während first erst später erneut definiert wird.
  3. Diese Lücke ist für die Lebensdaueranalyse relevant. Das Programm zeigt den Datenfluss und prüft den erfolgreichen Abschluss.
#COMPILE EXE
#DIM ALL
GLOBAL hole_result AS LONG
FUNCTION PBMAIN() AS LONG
    #XCODE REGALLOC=AUTO
        X.VREG first:U32
        X.VREG middle:U32
        X.ZERO V(first)
        X.ZERO V(middle)
        X.STORE DWORD PTR [hole_result], V(middle)
        X.ZERO V(first)
    #ENDX
    PBMAIN = 0
END FUNCTION

Erwarteter Exitcode: 0

PBXB64.exe xcode-test_xcode_regalloc_holes.pb -O2 -o example.exe
.\example.exe
$LASTEXITCODE

Quelltext herunterladen

Erwartung aus dem Quelltext abgeleitet; kein aktueller registrierter Laufvertrag. Keine neue native Compilerprüfung in dieser Website-Erweiterung. Finale Ausführung mit dem freigegebenen Compiler steht aus.

12. Lebende Werte über einen RAW-Block erhalten

Ablauf Schritt für Schritt

  1. Sieben U32-Werte erhalten 1 bis 7; X.RAW enthält eine einzelne nop-Anweisung.
  2. Nach der Barriere werden alle Werte in a addiert. Der Compiler muss ihre Werte trotz Registerdruck erhalten.
  3. Der DWORD-Store ergibt 28. Anders als ein reiner Übersetzungstest kontrolliert die BASIC-Prüfung diesen Wert ausdrücklich.
' XCODE qualification: AUTO spilling preserves a live value across pressure.
#COMPILE EXE
#DIM ALL
GLOBAL spill_result AS LONG

FUNCTION PBMAIN() AS LONG
    #XCODE OPT=2, SPILL=AUTO, FEATURES=BASELINE
        X.VREG a:U32
        X.VREG b:U32
        X.VREG c:U32
        X.VREG d:U32
        X.VREG e:U32
        X.VREG f:U32
        X.VREG g:U32
        X.MOVE V(a), 1
        X.MOVE V(b), 2
        X.MOVE V(c), 3
        X.MOVE V(d), 4
        X.MOVE V(e), 5
        X.MOVE V(f), 6
        X.MOVE V(g), 7
        X.RAW
            nop
        X.ENDRAW
        X.ADD V(a), V(b)
        X.ADD V(a), V(c)
        X.ADD V(a), V(d)
        X.ADD V(a), V(e)
        X.ADD V(a), V(f)
        X.ADD V(a), V(g)
        X.STORE DWORD PTR [spill_result], V(a)
    #ENDX
    IF spill_result <> 28 THEN
        PBMAIN = 1
        EXIT FUNCTION
    END IF
    PBMAIN = 0
END FUNCTION

Erwarteter Exitcode: 0

PBXB64.exe xcode-test_xcode_spill_auto.pb -O2 -o example.exe
.\example.exe
$LASTEXITCODE

Quelltext herunterladen

Erwartung aus dem Quelltext abgeleitet; kein aktueller registrierter Laufvertrag. Keine neue native Compilerprüfung in dieser Website-Erweiterung. Finale Ausführung mit dem freigegebenen Compiler steht aus.

Großes Beispiel: Zwei Schleifenformen und verschachtelte Berechnungen

Ablauf Schritt für Schritt

  1. X.DO WHILE prüft vor dem Rumpf und zählt die Indizes 0, 1 und 2. X.DO mit X.LOOP UNTIL prüft danach und zählt bis 2. Getrennte XCODE-Blöcke speichern ihre Ergebnisse in passenden 32-Bit-DWORD-Variablen.
  2. Beide X.FOR-Schleifen verwenden die ausgeschlossene Endgrenze 4: outer und inner durchlaufen 1, 2 und 3. X.IF überspringt mit X.CONTINUE nur inner = 2; die äußere Schleife läuft weiter.
  3. Damit entsteht 1*(1+3) + 2*(1+3) + 3*(1+3) = 24. BASIC prüft die Ergebnisse 3, 2 und 24 und liefert bei einer Abweichung einen eigenen Fehlercode. Dies ist ein erklärtes V22-Quellbeispiel; seine neue native Ausführung steht aus.
' Tutorial: exclusive X.FOR limits and nested control flow.
' DWORD storage matches the U32 virtual registers in this example.
#COMPILE EXE
#DIM ALL
GLOBAL pre_count AS DWORD
GLOBAL post_count AS DWORD
GLOBAL nested_total AS DWORD

FUNCTION PBMAIN() AS LONG
    #XCODE OPT=2, SPILL=AUTO, FEATURES=BASELINE
        X.VREG index:U32
        X.VREG count:U32
        X.MOVE V(index), 0
        X.MOVE V(count), 0
        X.DO WHILE V(index) < 3
            X.INC V(count)
            X.INC V(index)
        X.LOOP
        X.STORE DWORD PTR [pre_count], V(count)
    #ENDX

    #XCODE OPT=2, SPILL=AUTO, FEATURES=BASELINE
        X.VREG count:U32
        X.MOVE V(count), 0
        X.DO
            X.INC V(count)
        X.LOOP UNTIL V(count) == 2
        X.STORE DWORD PTR [post_count], V(count)
    #ENDX

    #XCODE OPT=2, SPILL=AUTO, FEATURES=BASELINE
        X.VREG outer:U32
        X.VREG inner:U32
        X.VREG product:U32
        X.VREG total:U32
        X.MOVE V(total), 0
        X.FOR V(outer), 1, 4, 1
            X.FOR V(inner), 1, 4, 1
                X.IF V(inner) == 2
                    X.CONTINUE
                X.ENDIF
                X.MOVE V(product), V(outer)
                X.MUL V(product), V(inner)
                X.ADD V(total), V(product)
            X.NEXT V(inner)
        X.NEXT V(outer)
        X.STORE DWORD PTR [nested_total], V(total)
    #ENDX

    IF pre_count <> 3 THEN PBMAIN = 1 : EXIT FUNCTION
    IF post_count <> 2 THEN PBMAIN = 2 : EXIT FUNCTION
    IF nested_total <> 24 THEN PBMAIN = 3 : EXIT FUNCTION
    PBMAIN = 0
END FUNCTION

Erwarteter Exitcode: 0

PBXB64.exe xcode-xcode-workshop-loops.pb -O2 -o example.exe
.\example.exe
$LASTEXITCODE

Quelltext herunterladen

Erwartung aus dem Quelltext abgeleitet; kein aktueller registrierter Laufvertrag. Keine neue native Compilerprüfung in dieser Website-Erweiterung. Finale Ausführung mit dem freigegebenen Compiler steht aus.

Alle Quellen dieser Lernseite

Jedes Beispiel hat einen eigenen Ordner; die README nennt die jeweiligen Compileraufrufe. Enthaltene Includes behalten ihre passenden Pfade.

Alle 13 Beispiele als ZIP

Bridging

X.STORE verbindet den XCODE-Block mit einer BASIC-Speicherstelle. Für einen vollständigen LONG-Wert ist QWORD die 64-Bit-Breite; DWORD bearbeitet nur 32 Bit. Die vollständige Befehlsreferenz steht auf der XCODE-Featureseite.

Vollständige Quellenpaare ansehenAlle XCODE-Befehle