cranelift: add arm32 backend - #13854
Conversation
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>
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>
|
Before going too too much further on this, have you seen this discussion on Zulip and/or #13815? |
|
I did not see them. |
Signed-off-by: Obei Sideg <obei.sideg@gmail.com>
Signed-off-by: Obei Sideg <obei.sideg@gmail.com>
Subscribe to Label ActionDetailsThis 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:
To subscribe or unsubscribe from this label, edit the |
|
Apologies @obeis I forgot this was assigned to me after this week's Cranelift meeting. For review of this I'm going to mostly defer to @cfallin and @fitzgen who are the primary maintainers of Cranelift's backends and probably have more insight into various pieces here than I do. One thing I can provide some review on though is the CI infrastructure. Currently this doesn't add anything new which means that the filetests are executed but there aren't, for example, any runtests nor QEMU emulation. This means that we're never actually executing any of the generated code here which is a gap we'll either want to close in this PR or very shortly thereafter. Would you be interested in integrating the QEMU/execution side into this PR as well? For example enabling any |
|
No problem, I will add the QEMU execution. |
some features aren't implemented yet.
I added file tests for my code.