← All docs

ARM64 Instructions

ARM64 instruction reference used by elephc.

This is a reference for the ARM64 instructions elephc uses most often, organized by category. Each entry shows the instruction, what it does, and where elephc uses it.

Arithmetic

InstructionSyntaxWhat it does
addadd x0, x1, x2x0 = x1 + x2
addsadds x0, x1, x2Add and set condition flags, used for overflow-checked integer addition
subsub x0, x1, x2x0 = x1 - x2
subssubs x0, x0, #1Subtract and set condition flags, often used when decrementing a counter before a conditional branch
mulmul x0, x1, x2x0 = x1 × x2
smulhsmulh x3, x1, x2High 64 bits of the signed 128-bit product, used to detect multiplication overflow
udivudiv x0, x1, x2x0 = x1 ÷ x2 (unsigned)
sdivsdiv x0, x1, x2x0 = x1 ÷ x2 (signed)
msubmsub x0, x1, x2, x3x0 = x3 - (x1 × x2). Used for modulo: a % b = a - (a/b)*b
negneg x0, x0x0 = -x0 (two’s complement negation)
cmncmn x0, #1Compare negative: sets flags as if adding the operand. Used for sentinel checks like -1
clzclz x0, x1Count leading zero bits
cnegcneg x0, x0, miConditionally negate a register
sxtwsxtw x0, w0Sign-extend a 32-bit value to 64 bits
uxtwuxtw x0, w0Zero-extend a 32-bit value to 64 bits

With immediates

InstructionSyntaxWhat it does
addadd x0, x0, #16x0 = x0 + 16
subsub sp, sp, #48Allocate 48 bytes on the stack

Floating-point arithmetic

InstructionSyntaxWhat it does
faddfadd d0, d1, d0d0 = d1 + d0
fsubfsub d0, d1, d0d0 = d1 - d0
fmulfmul d0, d1, d0d0 = d1 × d0
fdivfdiv d0, d1, d0d0 = d1 ÷ d0
fnegfneg d0, d0d0 = -d0
fsqrtfsqrt d0, d0d0 = √d0
fabsfabs d0, d0d0 =
fmsubfmsub d0, d1, d2, d3d0 = d3 - (d1 × d2). Float modulo
frintmfrintm d0, d0d0 = floor(d0)
frintpfrintp d0, d0d0 = ceil(d0)
frintafrinta d0, d0d0 = round(d0) using the current FP rounding rule that elephc emits for round()
frintzfrintz d0, d0d0 = round toward zero, used for truncating floating-point values
fmaxfmax d0, d0, d1d0 = max(d0, d1)
fminfmin d0, d0, d1d0 = min(d0, d1)

Load and store

These move data between registers and memory. See Introduction to ARM64 Assembly for addressing modes.

InstructionSyntaxWhat it does
ldrldr x0, [x29, #-8]Load 8 bytes from memory into x0
ldrldr w0, [x1]Load 4 bytes into the 32-bit w register
ldurldur x0, [x29, #-8]Same as ldr but for unaligned/negative offsets
strstr x0, [x29, #-8]Store x0 (8 bytes) to memory
sturstur x0, [x29, #-8]Same as str for unaligned/negative offsets
ldrbldrb w0, [x1]Load 1 byte (zero-extended to 32 bits)
ldrsbldrsb x0, [x1]Load 1 byte (sign-extended to 64 bits)
strbstrb w0, [x1]Store lowest byte of w0
ldrhldrh w0, [x1]Load 2 bytes (halfword)
strhstrh w0, [x1]Store 2 bytes
ldrswldrsw x15, [sp, x14]Load 4 bytes and sign-extend to 64 bits
stpstp x29, x30, [sp, #16]Store pair of registers (16 bytes total)
ldpldp x29, x30, [sp, #16]Load pair of registers

Floating-point load/store

InstructionSyntaxWhat it does
ldrldr d0, [x9]Load 8-byte double into float register
strstr d0, [x29, #-16]Store float register to memory

PC-relative addressing (for data section)

InstructionSyntaxWhat it does
adrpadrp x1, _str_0@PAGELoad the 4KB page address of a label
addadd x1, x1, _str_0@PAGEOFFAdd the offset within the page

These two always appear together — adrp gets the page, add gets the exact address. Used for loading string literals and float constants from the data section.

Move and immediate

InstructionSyntaxWhat it does
movmov x0, x1Copy x1 to x0
movmov x0, #42Load small constant (0-65535)
fmovfmov d0, d1Move a floating-point value (or bit pattern) between FP / GP registers
movzmovz x0, #0x1234Load 16-bit value, zero the rest
movkmovk x0, #0x5678, lsl #16Insert 16-bit value at bit position, keep the rest
movnmovn x0, #0Load bitwise NOT of immediate. movn x0, #0 = -1
mvnmvn x0, x0Bitwise NOT of register: x0 = ~x0. Used for PHP ~ operator

Loading large constants

ARM64 instructions are fixed at 32 bits, so you can’t load a 64-bit value in one instruction. Large numbers use movz + movk:

; Load 0x7FFFFFFFFFFFFFFE (the null sentinel) into x0
movz x0, #0xFFFE            ; bits  0-15
movk x0, #0xFFFF, lsl #16   ; bits 16-31
movk x0, #0xFFFF, lsl #32   ; bits 32-47
movk x0, #0x7FFF, lsl #48   ; bits 48-63

See Memory Model for why this specific value is used as the null sentinel.

Comparison and conditional

InstructionSyntaxWhat it does
cmpcmp x0, #0Compare x0 with 0 (sets condition flags)
cmpcmp x0, x1Compare x0 with x1
tsttst x0, #1Bitwise AND, set flags (but discard result)
csetcset x0, eqx0 = 1 if equal flag set, 0 otherwise
cselcsel x0, x1, x2, gtx0 = x1 if greater, x2 otherwise
csinvcsinv x0, x0, xzr, geIf condition false: x0 = ~xzr = -1, else x0 unchanged. Used for spaceship (<=>)

Floating-point comparison

InstructionSyntaxWhat it does
fcmpfcmp d0, d1Compare two doubles, set flags
fcmpfcmp d0, #0.0Compare double with zero

Condition codes

After cmp, these codes test the result:

CodeMeaningPHP operator
eqEqual==
neNot equal!=
ltLess than (signed)<
gtGreater than (signed)>
leLess or equal (signed)<=
geGreater or equal (signed)>=
miMinus (negative)Used for sign checks
csCarry setUsed after unsigned comparisons or flag-setting arithmetic

Branch (control flow)

InstructionSyntaxWhat it does
bb _labelUnconditional jump
b.eqb.eq _labelJump if equal (after cmp)
b.neb.ne _labelJump if not equal
b.ltb.lt _labelJump if less than
b.gtb.gt _labelJump if greater than
b.leb.le _labelJump if less or equal
b.geb.ge _labelJump if greater or equal
b.lob.lo _labelJump if lower (unsigned compare)
b.hsb.hs _labelJump if higher or same (unsigned compare)
b.hib.hi _labelJump if higher (unsigned compare)
b.lsb.ls _labelJump if lower or same (unsigned compare)
b.csb.cs _labelJump if carry set
cbzcbz x0, _labelJump if x0 == 0
cbnzcbnz x0, _labelJump if x0 != 0
tbnztbnz x0, #3, _labelTest one bit and jump if it is non-zero
blbl _fn_addBranch with link — call a function (saves return address in x30)
blrblr x9Branch with link to register — indirect function call through a register (used for closures and callbacks)
brbr x9Branch to the address in a register without saving a return address
brkbrk #0Trap into the debugger / terminate with a breakpoint exception
retretReturn — jump to address in x30

How branches map to PHP

See The Code Generator for full details.

if ($x > 0)     →  cmp x0, #0  /  b.le _else_1
while ($i < 10)  →  cmp x0, #10  /  b.ge _end_while_1
break            →  b _end_while_1
continue         →  b _while_1

Type conversion

InstructionSyntaxWhat it does
scvtfscvtf d0, x0Signed integer → double float
fcvtzsfcvtzs x0, d0Double float → signed integer (truncate toward zero)

Used for PHP type casting ((int)3.14, (float)42) and mixed arithmetic. See The Type Checker.

Bitwise

InstructionSyntaxWhat it does
andand x0, x0, #0xFFBitwise AND
orrorr x0, x0, x1Bitwise OR
eoreor x0, x0, x1Bitwise XOR
lsrlsr x0, x0, #4Logical shift right
lsllsl x0, x0, #3Logical shift left
asrasr x0, x0, #63Arithmetic shift right (preserves sign)

Used for PHP’s bitwise operators (&, |, ^, <<, >>) and in runtime routines for things like hex conversion, hash algorithms, and base64 encoding.

System

InstructionSyntaxWhat it does
svcsvc #0x80Supervisor call — invoke the macOS kernel

Before svc, set up: x16 = syscall number, x0-x5 = arguments.

Syscallx16ArgumentsUsed for
exit#1x0 = exit codeexit(), program termination
write#4x0 = fd, x1 = buf, x2 = lenecho, print
stat64#338path / buffer pointersfilesystem metadata helpers

Assembly directives

These aren’t CPU instructions — they’re commands to the assembler:

DirectiveExampleWhat it does
.global.global _mainMake label visible to the linker
.align.align 2Align next data to 2^2 = 4 bytes
.data.dataSwitch to data section
.text.textSwitch to code section
.ascii.ascii "hello"Emit string bytes (no null terminator)
.quad.quad 0x4028000000000000Emit 8-byte value (used for float constants)
.comm.comm _heap_buf, 1048576Reserve uninitialized memory (BSS section)