blaise/docs
Graeme Geldenhuys 0396ed7b1c feat(lang): inline assembler blocks (asm … end routine bodies)
A routine body may now be written as inline assembly:

    function GetSelf: Pointer; assembler; nostackframe;
    asm
        movq %rdi, %rax
        ret
    end;

The block is opaque GNU/AT&T assembly: the lexer captures the whole asm … end
as one tkAsmBlock token (verbatim text, never tokenised as Pascal), the parser
wraps it in a TAsmStmt, the semantic pass treats it as a black box, and the
native backend emits it verbatim into the assembly stream where the existing
internal/external assembler parses it.  `nostackframe` suppresses the compiler
prologue/epilogue so the asm body owns the whole frame.  asm routines mix
freely with ordinary Pascal routines in a standard .pas unit (no .inc needed).

This is the FPC model (rtl/linux/x86_64/si_c.inc) and the path to retiring the
hand-written runtime/src/main/asm/*.s files (assembled by `cc -c` today) — once
each body moves into an asm routine the RTL builds with no external assembler.

Design follows ports-and-adapters: x86-64 knowledge stays at the backend/
assembler edge, the portable core never interprets the block.  The QBE backend
rejects asm bodies (it emits no assembly text); native is the inline-asm target
and the default.  TAsmStmt round-trips through the .bif unit cache.

Pipeline: lexer (tkAsmBlock + ReadAsmBody raw capture), uAST (TAsmStmt,
TMethodDecl.NoStackFrame), parser (nostackframe directive + asm-body path),
semantic (opaque no-op), native codegen (verbatim emit + nostackframe null-frame
guard), QBE rejection, uUnitInterfaceIO encode/decode, bif-coverage entry.
`asm` becomes a reserved word (one local var named Asm renamed in a test).

Fixes a native sret-Result field-read codegen bug the feature exposed: reading a
field of an sret function's Result at offset 0 (e.g. `Result.Kind` in a record-
returning function) read the Result frame slot DIRECTLY instead of dereferencing
the caller-buffer pointer it holds, so `Result.Field = const` was always false.
The offset-0 fast path in the integer field-read leaf now routes through
EmitLocalRecordBase like the offset>0 path, so the sret indirection happens in
both.  QBE was already correct; this was a native-only divergence.

Tests: lexer raw-capture (3), native verbatim-body/no-prologue IR test (1),
internal-assembler e2e returns-value + adds-two-args (2).  All four fixpoints
and both QBE- and native-built test runners pass (3764 tests).

Design note: docs/inline-asm-design.adoc; grammar + rationale updated.
2026-06-25 01:01:41 +01:00
..
benchmark.txt docs(benchmark): add QBE 1.3 measurement entry 2026-06-02 17:17:54 +01:00
bif-format.adoc docs: .bif file format reference 2026-06-03 19:40:08 +01:00
design.adoc refactor: rename uCodeGen/uCodeGenQBE to blaise.codegen/blaise.codegen.qbe 2026-06-10 12:12:14 +01:00
extending-ast.adoc refactor: rename uCodeGen/uCodeGenQBE to blaise.codegen/blaise.codegen.qbe 2026-06-10 12:12:14 +01:00
future-improvements.adoc feat(stdlib): add Numerics.Money — currency-aware TMoney 2026-06-20 10:33:35 +01:00
grammar.ebnf feat(lang): inline assembler blocks (asm … end routine bodies) 2026-06-25 01:01:41 +01:00
inline-asm-design.adoc feat(lang): inline assembler blocks (asm … end routine bodies) 2026-06-25 01:01:41 +01:00
internal-linker-design.adoc docs: mark internal linker Phases C and D as implemented 2026-06-19 10:51:09 +01:00
language-rationale.adoc feat(lang): inline assembler blocks (asm … end routine bodies) 2026-06-25 01:01:41 +01:00
name-mangling.adoc refactor: rename uCodeGen/uCodeGenQBE to blaise.codegen/blaise.codegen.qbe 2026-06-10 12:12:14 +01:00
native-const-arg-arc-port.adoc docs: native const-arg ARC port design — mark implemented 2026-06-11 07:36:13 +01:00
self-contained-start-design.adoc fix(linker): ship own _start; drop system CRT startup objects (#142) 2026-06-24 23:39:11 +01:00
testing-strategy.adoc refactor: rename uCodeGen/uCodeGenQBE to blaise.codegen/blaise.codegen.qbe 2026-06-10 12:12:14 +01:00