Expand/Shrink

inline assembly

Should you want to learn (the Phix subset of) ARM/x86 assembly, you are probably better off searching builtins\ for "#ilASM", most of what follows is likely and in fact deliberately intended to make much more sense within such a context, specifically when faced with (say) "ermah du,da,de", pressing F1 with the cursor on that should give you some kind of hint. Note there is an ARM bias to F1 help, so eg "lea" goes to the ARM pseudo-instruction, rather than the x86 real instruction, though the former should have a suitable back-link.

    #ilASM{ e_all
        jmp :fin    -- or:
//      jmp :!opCallOnceYeNot
        [32] -- shorthand for [PE32,ELF32]
            -- 32-bit x86 code goes here
        [64] -- shorthand for [PE64,ELF64]
            -- 64-bit x86 code goes here
        [PE32]
            -- PE32-specific code goes here
        [ARM]
            -- ARM code goes here
        [] -- shorthand for [PE32,PE64,ELF32,ELF64,ARM]
            -- generic code goes here, eg
            call :%puts1
        ::fin
          }
Picking through that line-by-line:

The e_all directive, if present, informs the compiler that significant side effects may occur.
Used in call_func(), c_func(), and task_yield(), which is (alas) perhaps the best I can really say about that, but I’ll try:
At a push I might say the compiler’s localtypes, that it builds from hll code analysis, are no longer trustworthy and it has to emit full generic/defensive code immediately following the #ilASM [e_all] statement, at least until it has built up some new (and irrefutable) localtype info.
As an example of localtype info, after `object s = "string"`, the compiler knows that s is a string, and it cannot be unassigned, so it can inline say length(s) as a single machine instruction, rather than invoke the more generic :%opLen, which is slower and contains all the standard "variable %s has not been assigned" and "length of an ATOM is not defined" handling. The e_all directive may also cover other subtleties, for instance in pure hll the compiler may (be confident enough to) omit parameter type checking code, but if a routine is being invoked via call_func/proc [aka is a possible target of routine_id], then it simply cannot (be confident enough to do that).

Sometimes you may want to jump over the code, or invoke opCallOnceYeNot. Of course there is no problem putting #ilASM{} inside a routine, however any fundamental opcodes must be defined at the top-level.

Various "guards" allow a single #ilASM construct to contain the code for different architectures, and obviously the compiler does not emit any binary for those it is not currently targetting, and of course there are no jumps over any "not me" branches. Specifically, an earlier "format ELF32" explicitly tells the compiler what to do when it finds a #ilASM statement, whereas the interpreter implicitly determines that from itself, for instance a 64-bit binary on Windows obviously selects/compiles [PE64]. To be clear, a "format" directive is only honoured when compiling, and is ignored when interpreting, with sometimes the latter instead relying on a requires() statement. It is also quite normal, but not mandatory, for format statements to be in completely separate files, which are used purely for packaging purposes, for instance see Phix/p32.exu and Phix/p64.exu.
Note that for historic reasons [32] and [64] are exclusively Intel x86 and x64 respectively.
At the moment, only 32-bit ARM is being targetted, at some future date [ARM] may become shorthand for [ARM32,ARM64] but right now neither of those exist, nor does anything like [THUMB].