Skip to content

cranelift: add arm32 backend#13854

Open
obeis wants to merge 18 commits into
bytecodealliance:mainfrom
obeis:arm32-isa
Open

cranelift: add arm32 backend#13854
obeis wants to merge 18 commits into
bytecodealliance:mainfrom
obeis:arm32-isa

Conversation

@obeis

@obeis obeis commented Jul 9, 2026

Copy link
Copy Markdown

some features aren't implemented yet.

I added file tests for my code.

obeis added 12 commits July 9, 2026 16:13
First step towards a 32-bit ARM backend. This wires arm32 into the meta
build, the isa::lookup path, and the codegen crate, and adds just enough
of the MachInst/ABIMachineSpec plumbing to compile and emit a trivial
function.

An iconst.i32 followed by a return now lowers to real A32 (movw + bx lr)
and is covered by filetests/isa/arm32/iconst.clif. Everything off that
path is still a stub.

Signed-off-by: Obei Sideg <obei.sideg@gmail.com>
Enough of the common instructions to lower straight-line integer code:
mov/movw/movt/mvn, ldr/str and the sub-word and push/pop forms,
add/sub/rsb in register and rotated-immediate forms, cmp/cmn, and the
branch family (b, bl, bx, and conditional b<cond>). Each comes with its
A32 encoding, operand handling, and pretty-printing.

Signed-off-by: Obei Sideg <obei.sideg@gmail.com>
Rounds out the data-processing group: the logical ops (and/orr/eor/bic
and register mvn), the shifts and rotates in both immediate and register
forms, mul/mla/umull/smull, the flag-setting arithmetic (adds/subs/adcs/
sbcs, plus the adc/sbc opcodes), and the tst/teq tests.

Signed-off-by: Obei Sideg <obei.sideg@gmail.com>
The remaining core integer operations: clz; sdiv/udiv behind a new
has_idiv ISA setting; the sxtb/sxth/uxtb/uxth extends; rev/rev16/rbit;
the mls/smlal/umlal fused multiplies; and a conditional-select pseudo
built from a mov plus a mov<cond>.

Signed-off-by: Obei Sideg <obei.sideg@gmail.com>
Adds encoders, operand handling, printing, and unit tests for the
scalar-integer instructions the backend was still missing: the bitfield
ops (bfc/bfi/sbfx/ubfx), the saturating arithmetic, sel/pkh/revsh/rrx/
udf, the full parallel add/sub family, the 16-bit and accumulating
extends, the DSP multiplies, ldm/stm, the exclusive and acquire/release
memory accesses, and the barriers.

Most of these have no CLIF opcode that maps to them yet; they are here so
the encoder is complete and the tests pin the bit patterns down.

Signed-off-by: Obei Sideg <obei.sideg@gmail.com>
A direct call to a near/colocated callee becomes a bl with an Arm32Call
relocation; call_indirect becomes a blx through a register. The call and
indirect-call instructions record the safepoint and stack map, pop the
callee's stack arguments, and load any stack-returned values.

Both forms are treated as calls by call_type/is_safepoint so the frame is
set up and lr is preserved around them -- getting that wrong for the
indirect case corrupts the return address. Far calls, return_call, and
try_call are left for later.

Signed-off-by: Obei Sideg <obei.sideg@gmail.com>
An i64 lives in a (lo, hi) pair of 32-bit registers. rc_for_type returns
two Int registers for I64, and the ABI passes 64-bit arguments in
even-aligned pairs (r0:r1 / r2:r3) per AAPCS, spilling to the 8-aligned
stack when they run out.

Lowers iconst, add/sub via the adds/adc and subs/sbc carry chains, the
bitwise ops per half, iconcat/isplit, the extends and reduce between i32
and i64, and 64-bit load/store as two word accesses. The i64 rules take
an explicit priority so ISLE doesn't have to prove them disjoint from the
fits_in_32 rules.

Signed-off-by: Obei Sideg <obei.sideg@gmail.com>
imul.i64 expands to umull plus two mla for the low 64 bits of the
product. Constant-amount ishl/ushr/sshr use a funnel sequence: for
shifts below 32 an orr of two 32-bit shifts, and for shifts of 32 or
more a single shift with a zero or sign fill. Variable-amount i64 shifts
are still unimplemented.

Signed-off-by: Obei Sideg <obei.sideg@gmail.com>
icmp on i64 operands, both as a value and fused into brif. eq/ne reduce
the halves with eor/eor/orrs; the ordering comparisons subtract the pair
with subs/sbcs and test a Z-independent condition, swapping operands for
the gt/le/hi/ls cases.

Also adds a standalone 32-bit icmp-to-bool lowering, which until now only
existed fused into brif or select. Note that icmp's controlling type is
its result type, so the rules match the operand width with value_type.

Signed-off-by: Obei Sideg <obei.sideg@gmail.com>
Introduces f32/f64 on the VFP unit. regalloc2 can't model the S/D
sub-register aliasing, so the float class is the D registers and an f32
lives in the low single half of its D register -- every value owns a
whole D register, which also keeps the encodings uniform (F32 vs F64 is
just the size bit).

D0-D7 are caller-saved, D8-D15 callee-saved; moves and spills are
class-aware (vmov.f64, vldr/vstr). The ABI is a simplified hard-float
(args in D0-D7, return in D0). Lowers the arithmetic, negate/abs/sqrt,
loads and stores, and the const materialization through GPRs.

Signed-off-by: Obei Sideg <obei.sideg@gmail.com>
fcmp emits vcmp followed by vmrs to get the flags into APSR, then tests
the mapped condition. fpromote/fdemote and the int<->float conversions
go through vcvt (only the saturating float-to-int, matching VCVT's
semantics). Bitcasts between float and integer of the same width use
vmov.

Signed-off-by: Obei Sideg <obei.sideg@gmail.com>
fmin/fmax reuse the trick of picking vminnm/vmaxnm when the inputs are
ordered and x+y (the propagated NaN) when they aren't, which needs
ARMv8. copysign is done with GPR bit twiddling on the sign bit. A
scalar-float select becomes a cmp plus a conditional vmov.

Signed-off-by: Obei Sideg <obei.sideg@gmail.com>
@obeis obeis requested review from a team as code owners July 9, 2026 16:56
@obeis obeis requested review from alexcrichton and removed request for a team July 9, 2026 16:56
obeis added 4 commits July 9, 2026 20:08
Emits a bounds check against the default target, then an
add pc, pc, index, lsl into an inline table of branches. Branch26
range covers the table so no islands are needed. br_table and the call
sequences are exempt from the per-instruction worst-case-size check.

Signed-off-by: Obei Sideg <obei.sideg@gmail.com>
atomic_rmw and atomic_cas lower to ldaex/.../stlex retry loops emitted as
single pseudo-instructions, since the register allocator can't be allowed
to split the exclusive sequence. The rmw pseudo covers all of the
operations; cas branches out on a mismatch. atomic_load/store use
lda/stl, which give seq_cst ordering on ARMv8. Only i32 for now.

Signed-off-by: Obei Sideg <obei.sideg@gmail.com>
Direct calls to a non-colocated callee had no lowering. A new
LoadExtName pseudo materializes a symbol's absolute address inline
(ldr rd, [pc]; b .+8; .word <sym>) with an Abs4 relocation, and a far
call loads the target that way and calls it indirectly. The same helper
also lowers func_addr and symbol_value.

Signed-off-by: Obei Sideg <obei.sideg@gmail.com>
Threads an access size through the exclusive instructions so they encode
the byte and halfword forms. Sub-word rmw needs no operand extension for
the plain ops (the store truncates), but min/max and cas extend their
inputs before comparing.

64-bit is trickier: ldrexd/strexd need consecutive even/odd register
pairs, which regalloc2 can't express, so the paired atomics pin every
operand to a fixed register the way aarch64 does. rmw uses the
adds/adc/subs/sbc carry chains, with min/max selecting both halves on a
Z-independent condition.

Signed-off-by: Obei Sideg <obei.sideg@gmail.com>
@alexcrichton

Copy link
Copy Markdown
Member

Before going too too much further on this, have you seen this discussion on Zulip and/or #13815?

@obeis

obeis commented Jul 9, 2026

Copy link
Copy Markdown
Author

I did not see them.

}

/// `strex{b,h,d}`/`stlex{b,h,d} rd, rt, [rn]`.
fn enc_store_ex(acquire: bool, size: AtomicSize, rd: u32, rt: u32, rn: u32) -> u32 {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this be release, not acquire?

obeis added 2 commits July 9, 2026 20:51
Signed-off-by: Obei Sideg <obei.sideg@gmail.com>
Signed-off-by: Obei Sideg <obei.sideg@gmail.com>
@github-actions github-actions Bot added cranelift Issues related to the Cranelift code generator cranelift:area:machinst Issues related to instruction selection and the new MachInst backend. cranelift:meta Everything related to the meta-language. labels Jul 9, 2026
@github-actions github-actions Bot added the isle Related to the ISLE domain-specific language label Jul 9, 2026
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

Subscribe to Label Action

cc @cfallin, @fitzgen

Details This issue or pull request has been labeled: "cranelift", "cranelift:area:machinst", "cranelift:meta", "isle"

Thus the following users have been cc'd because of the following labels:

  • cfallin: isle
  • fitzgen: isle

To subscribe or unsubscribe from this label, edit the .github/subscribe-to-label.json configuration file.

Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cranelift:area:machinst Issues related to instruction selection and the new MachInst backend. cranelift:meta Everything related to the meta-language. cranelift Issues related to the Cranelift code generator isle Related to the ISLE domain-specific language

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants