// Moved from docs/src/performance-profiling/ASM_OPTIMIZATIONS.adoc to docs/working/scratch/src/performance-profiling/ASM_OPTIMIZATIONS.adoc on 2026-06-16 (docs reorg Phase 2)
== StarForth Assembly Optimizations
:toc: left
:toc-title: Contents
:toclevels: 3
xref:../README.adoc[← Back to Documentation Index]



=== Overview

This document describes the x86_64 assembly optimizations available for
StarForth, suitable for both standard Linux environments and L4Re
microkernel deployments (StarshipOS).

=== Files

* `+include/vm_asm_opt.h+` - Basic stack and arithmetic optimizations
* `+include/vm_inner_interp_asm.h+` - Advanced direct-threaded inner
interpreter

=== Performance Impact

[width="100%",cols="28%,12%,12%,48%",options="header",]
|===
|Optimization |Impact |Speedup |Use Case
|Stack operations |EXTREME |2-3x |Every word execution
|Inner interpreter |EXTREME |3-5x |Threaded code (colon definitions)
|Arithmetic ops |HIGH |1.5-2x |Math-heavy code
|Dictionary lookup |HIGH |2-3x |Word compilation/interpretation
|String operations |MEDIUM |1.5-2x |Text processing
|===

=== Quick Start

==== 1. Enable Optimizations

Edit your `+Makefile+` or build script:

[source,makefile]
----
# Add to CFLAGS
CFLAGS += -DUSE_ASM_OPT=1 -DUSE_DIRECT_THREADING=1 -O3 -march=native

# For L4Re/StarshipOS
CFLAGS += -DUSE_ASM_OPT=1 -march=x86-64-v2 -O3
----

==== 2. Include Headers

In your `+src/stack_management.c+`:

[source,c]
----
#include "../include/vm.h"
#include "../include/vm_asm_opt.h"

void vm_push(VM *vm, cell_t value) {
#if USE_ASM_OPT
    vm_push_asm(vm, value);
#else
    // Original C implementation
    if (vm->dsp >= STACK_SIZE - 1) {
        vm->error = 1;
        return;
    }
    vm->data_stack[++vm->dsp] = value;
#endif
}

cell_t vm_pop(VM *vm) {
#if USE_ASM_OPT
    return vm_pop_asm(vm);
#else
    // Original C implementation
    if (vm->dsp < 0) {
        vm->error = 1;
        return 0;
    }
    return vm->data_stack[vm->dsp--];
#endif
}
----

==== 3. Optimize Arithmetic Words

In `+src/word_source/arithmetic_words.c+`:

[source,c]
----
#include "../../include/vm_asm_opt.h"

void arithmetic_word_plus(VM *vm) {
    if (vm->dsp < 1) {
        vm->error = 1;
        return;
    }

#if USE_ASM_OPT
    cell_t n2 = vm_pop_asm(vm);
    cell_t n1 = vm_pop_asm(vm);
    cell_t result;

    if (vm_add_check_overflow(n1, n2, &result)) {
        // Handle overflow
        log_message(LOG_ERROR, "+: Overflow detected");
        vm->error = 1;
        return;
    }

    vm_push_asm(vm, result);
#else
    // Original implementation
    cell_t n2 = vm_pop(vm);
    cell_t n1 = vm_pop(vm);
    vm_push(vm, n1 + n2);
#endif
}

void arithmetic_word_star_slash(VM *vm) {
    // n1 n2 n3 -- n4    (n1*n2/n3)
    if (vm->dsp < 2) {
        vm->error = 1;
        return;
    }

#if USE_ASM_OPT
    cell_t n3 = vm_pop_asm(vm);
    cell_t n2 = vm_pop_asm(vm);
    cell_t n1 = vm_pop_asm(vm);

    if (n3 == 0) {
        vm->error = 1;
        return;
    }

    // Use double-width multiplication
    cell_t hi, lo;
    vm_mul_double(n1, n2, &hi, &lo);

    // Now divide the 128-bit result by n3
    // (Note: Full 128-bit division requires more complex code)
    // For now, assume result fits in 64 bits:
    cell_t result = lo / n3;  // Simplified

    vm_push_asm(vm, result);
#else
    // Original implementation
    cell_t n3 = vm_pop(vm);
    cell_t n2 = vm_pop(vm);
    cell_t n1 = vm_pop(vm);
    vm_push(vm, (n1 * n2) / n3);
#endif
}
----

==== 4. Optimize Dictionary Lookup

In `+src/dictionary_management.c+`:

[source,c]
----
#include "../include/vm_asm_opt.h"

DictEntry *vm_find_word(VM *vm, const char *name, size_t len) {
    for (DictEntry *e = vm->latest; e; e = e->link) {
        if (e->name_len == len) {
#if USE_ASM_OPT
            if (vm_strcmp_asm(e->name, name, len) == 0) {
                return e;
            }
#else
            if (memcmp(e->name, name, len) == 0) {
                return e;
            }
#endif
        }
    }
    return NULL;
}
----

=== Advanced: Direct-Threaded Inner Interpreter

This is the most complex but highest-impact optimization.

==== Understanding Direct Threading

Traditional C implementation:

[source,c]
----
void execute_colon_word(VM *vm) {
    cell_t *ip = vm->ip;
    while (*ip) {
        DictEntry *word = (DictEntry*)*ip++;
        word->func(vm);  // Function call overhead!
        if (vm->exit_colon) break;
    }
}
----

Problems:

* Function call/return for EVERY word (expensive)
* Poor CPU branch prediction
* Register spilling

Direct-threaded solution:

[source,c]
----
void execute_colon_word_fast(VM *vm) {
    vm_setup_registers(vm);

    // Now IP, stacks are in registers
    // Each word does its work and jumps to NEXT
    // No function call overhead!

    vm_save_registers(vm);
}
----

==== Implementation Example

Create a new file `+src/vm_primitives_asm.c+`:

[source,c]
----
#include "../include/vm.h"
#include "../include/vm_inner_interp_asm.h"

#if USE_DIRECT_THREADING

// Each primitive word uses the PRIM_* macros and NEXT_ASM()

void forth_dup_fast(void) {
    PRIM_DUP();
    NEXT_ASM();
}

void forth_drop_fast(void) {
    PRIM_DROP();
    NEXT_ASM();
}

void forth_swap_fast(void) {
    PRIM_SWAP();
    NEXT_ASM();
}

void forth_plus_fast(void) {
    PRIM_PLUS();
    NEXT_ASM();
}

void forth_minus_fast(void) {
    PRIM_MINUS();
    NEXT_ASM();
}

void forth_star_fast(void) {
    PRIM_STAR();
    NEXT_ASM();
}

void forth_fetch_fast(void) {
    PRIM_FETCH();
    NEXT_ASM();
}

void forth_store_fast(void) {
    PRIM_STORE();
    NEXT_ASM();
}

void forth_to_r_fast(void) {
    PRIM_TO_R();
    NEXT_ASM();
}

void forth_r_from_fast(void) {
    PRIM_R_FROM();
    NEXT_ASM();
}

void forth_branch_fast(void) {
    PRIM_BRANCH();
    NEXT_ASM();
}

void forth_zbranch_fast(void) {
    PRIM_ZBRANCH();
    NEXT_ASM();
}

#endif // USE_DIRECT_THREADING
----

=== Benchmarking

==== 1. Create Test Suite

Create `+benchmarks/stack_bench.fth+`:

[source,forth]
----
: BENCH-DUP  ( n -- )
  0 DO  123 DUP DROP  LOOP ;

: BENCH-MATH ( n -- )
  0 DO  10 20 + 5 * 100 /  DROP  LOOP ;

: BENCH-STACK ( n -- )
  0 DO  1 2 3 4 5 DROP DROP DROP DROP DROP  LOOP ;

\ Run benchmarks
." Testing DUP/DROP: "
1000000 BENCH-DUP
." Done" CR

." Testing arithmetic: "
1000000 BENCH-MATH
." Done" CR

." Testing stack ops: "
1000000 BENCH-STACK
." Done" CR
----

==== 2. Measure Performance

[source,bash]
----
# Baseline (no optimizations)
make clean
make CFLAGS="-std=c99 -O2 -Iinclude"
time ./build/starforth benchmarks/stack_bench.fth

# With assembly optimizations
make clean
make CFLAGS="-std=c99 -O3 -march=native -DUSE_ASM_OPT=1 -Iinclude"
time ./build/starforth benchmarks/stack_bench.fth

# With direct threading
make clean
make CFLAGS="-std=c99 -O3 -march=native -DUSE_ASM_OPT=1 -DUSE_DIRECT_THREADING=1 -Iinclude"
time ./build/starforth benchmarks/stack_bench.fth
----

==== 3. Use perf for Detailed Analysis

[source,bash]
----
# Profile baseline
perf record -g ./build/starforth benchmarks/stack_bench.fth
perf report

# Profile optimized
perf record -g ./build/starforth_asm benchmarks/stack_bench.fth
perf report

# Compare:
perf stat -r 10 ./build/starforth benchmarks/stack_bench.fth
perf stat -r 10 ./build/starforth_asm benchmarks/stack_bench.fth
----

=== L4Re / StarshipOS Integration

==== Build for L4Re

[source,makefile]
----
# In your L4Re package Makefile
CFLAGS += -DUSE_ASM_OPT=1 -O3 -march=x86-64-v2
CFLAGS += -fno-stack-protector  # If in kernel context
CFLAGS += -mno-red-zone         # Required for kernel code

# Link with L4Re libraries
LIBS += -ll4re-util -ll4sys
----

==== Memory Management

For L4Re, use L4Re’s allocators:

[source,c]
----
#include <l4/re/c/mem_alloc.h>
#include <l4/re/c/dataspace.h>

void vm_init_l4re(VM *vm) {
    // Allocate VM memory using L4Re dataspace
    l4re_ds_t ds;
    l4_cap_idx_t ds_cap = l4re_util_cap_alloc();

    long ret = l4re_ma_alloc(VM_MEMORY_SIZE, ds_cap, 0);
    if (ret) {
        // Handle error
        return;
    }

    // Map dataspace
    ret = l4re_rm_attach(&vm->memory, VM_MEMORY_SIZE,
                         L4RE_RM_F_SEARCH_ADDR | L4RE_RM_F_RW,
                         ds_cap, 0, L4_PAGESHIFT);
    if (ret) {
        // Handle error
        return;
    }

    // Continue with normal initialization
    vm->dsp = -1;
    vm->rsp = -1;
    // ...
}
----

==== IPC Integration

For inter-VM communication:

[source,c]
----
#include <l4/sys/ipc.h>

// Send Forth data to another L4Re task
void vm_ipc_send(VM *vm, l4_cap_idx_t dest) {
    l4_msg_regs_t *mr = l4_utcb_mr();

    // Pack stack data into message registers
    mr->mr[0] = vm->dsp;
    for (int i = 0; i <= vm->dsp && i < L4_UTCB_GENERIC_DATA_SIZE; i++) {
        mr->mr[i+1] = vm->data_stack[i];
    }

    l4_msgtag_t tag = l4_msgtag(0, vm->dsp + 2, 0, 0);
    tag = l4_ipc_send(dest, l4_utcb(), tag, L4_IPC_NEVER);

    if (l4_ipc_error(tag, l4_utcb())) {
        vm->error = 1;
    }
}
----

=== Debugging

==== Disable Optimizations for Debugging

[source,makefile]
----
debug:
    $(MAKE) CFLAGS="$(BASE_CFLAGS) -O0 -g -DUSE_ASM_OPT=0" all
----

==== GDB Tips

[source,bash]
----
# Debug assembly-optimized code
gdb ./build/starforth

(gdb) break vm_push_asm
(gdb) layout asm
(gdb) stepi
(gdb) info registers r12 r13 r14 r15
----

==== Verify Correctness

Create test suite that runs in both modes:

[source,c]
----
void test_stack_ops(void) {
    VM vm_c, vm_asm;

    vm_init(&vm_c);
    vm_init(&vm_asm);

    // Test with C version
    #undef USE_ASM_OPT
    vm_push(&vm_c, 42);
    vm_push(&vm_c, 17);
    cell_t result_c = vm_pop(&vm_c);

    // Test with ASM version
    #define USE_ASM_OPT 1
    vm_push_asm(&vm_asm, 42);
    vm_push_asm(&vm_asm, 17);
    cell_t result_asm = vm_pop_asm(&vm_asm);

    assert(result_c == result_asm);
    assert(vm_c.dsp == vm_asm.dsp);
}
----

=== Platform Compatibility

[width="100%",cols="22%,15%,17%,25%,21%",options="header",]
|===
|Platform |Stack Ops |Arithmetic |Direct Threading |Notes
|Linux x86_64 |✓ |✓ |✓ |Full support
|L4Re x86_64 |✓ |✓ |✓ |Full support
|StarshipOS |✓ |✓ |✓ |Kernel & user
|ARM64 |✗ |✗ |✗ |Future work
|RISC-V |✗ |✗ |✗ |Future work
|===

=== Safety Considerations

==== Stack Overflow Protection

The assembly code checks for overflow, but for extra safety:

[source,c]
----
#if USE_ASM_OPT
// Add guard pages
mprotect(vm->data_stack + STACK_SIZE, PAGE_SIZE, PROT_NONE);
mprotect(vm->return_stack + STACK_SIZE, PAGE_SIZE, PROT_NONE);
#endif
----

==== Error Handling

Assembly code sets `+vm->error+` on overflow/underflow, but doesn’t log
(for performance). Add logging in debug builds:

[source,c]
----
#ifdef DEBUG
#define VM_ERROR_LOG(msg) log_message(LOG_ERROR, msg)
#else
#define VM_ERROR_LOG(msg) do {} while(0)
#endif
----

=== Performance Tips

[arabic]
. *Use PGO (Profile-Guided Optimization)*
+
[source,bash]
----
# Generate profile
make CFLAGS="-O3 -fprofile-generate"
./build/starforth benchmarks/typical_workload.fth

# Use profile
make clean
make CFLAGS="-O3 -fprofile-use"
----
. *Align hot structures*
+
[source,c]
----
typedef struct VM {
    // ... fields ...
} __attribute__((aligned(64))) VM;  // Cache line aligned
----
. *Prefetch dictionary entries*
+
[source,c]
----
__builtin_prefetch(vm->latest);
__builtin_prefetch(vm->latest->link);
----
. *Use huge pages for VM memory*
+
[source,c]
----
vm->memory = mmap(NULL, VM_MEMORY_SIZE,
                  PROT_READ | PROT_WRITE,
                  MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB,
                  -1, 0);
----

=== Troubleshooting

==== "`Illegal instruction`" error

* Check CPU features: `+cat /proc/cpuinfo+`
* Reduce `+-march=native+` to `+-march=x86-64-v2+`

==== Crashes in assembly code

* Check stack alignment (must be 16-byte aligned)
* Verify register clobbers are correct
* Use `+-fsanitize=address+` to catch errors

==== Performance not improving

* Profile with `+perf+` to find actual bottleneck
* Check if compiler is inlining the wrappers
* Verify optimizations are actually enabled

=== Contributing

When adding new assembly optimizations:

[arabic]
. Benchmark before and after
. Add both C and ASM versions
. Test on multiple CPUs
. Document register usage
. Add to this README

=== References

* https://www.complang.tuwien.ac.at/forth/threaded-code.html[Threaded
Code]
* https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html[GCC Inline
Assembly]
* https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-1.0.pdf[x86_64
ABI]
* https://l4re.org/doc/[L4Re Documentation]

=== License

Public domain / CC0. No warranty. Use at your own risk.
