Skip to content

fix: emit ARM ARM by-element operand form for NEON FMLA/FMLS - #30

Open
mohitt31 wants to merge 1 commit into
SeisSol:masterfrom
mohitt31:fix/neon-fmla-by-element-syntax
Open

fix: emit ARM ARM by-element operand form for NEON FMLA/FMLS#30
mohitt31 wants to merge 1 commit into
SeisSol:masterfrom
mohitt31:fix/neon-fmla-by-element-syntax

Conversation

@mohitt31

Copy link
Copy Markdown

What this fixes

The NEON backend prints the by-element FMLA/FMLS multiplicand with the full
arrangement specifier:

fmla v11.2d, v1.2d, v3.2d[0]

The ARM ARM gives the instruction as

FMLA <Vd>.<T>, <Vn>.<T>, <Vm>.<Ts>[<index>]

so the third operand carries the element type, not the arrangement, and has to
be written v3.d[0].

GNU as accepts the redundant form, which is why this has gone unnoticed. The
LLVM integrated assembler rejects it:

$ echo 'int main(void){ __asm__("fmla v11.2d, v1.2d, v3.2d[0]"); }' > t.c && clang -c t.c
<inline asm>:1:27: error: invalid operand for instruction
        fmla v11.2d, v1.2d, v3.2d[0]
                                  ^
$ echo 'int main(void){ __asm__("fmla v11.2d, v1.2d, v3.d[0]"); }' > u.c && clang -c u.c
$

It affects .2d (double) and .4s (single) alike, and reproduces on both Apple
clang 21 and Homebrew clang 22.

Why it matters

Every NEON kernel fails to assemble under clang, so
HOST_ARCH=apple-m1/m2/m3/m4 builds of SeisSol do not compile on macOS — the
configuration SeisSol's own build docs recommend for Macs. SeisSol/SeisSol#963
added macOS and M1/M2 support in 2023; this is part of why it has regressed.

The change

One file, pypspamm/codegen/architectures/arm/inlineprinter.py: a small
laneOperand() helper that converts v3.2d to v3.d, used only on the
by-element path in visitFma. It is a pure syntax change; the encoded
instruction is identical.

Testing

tests/unit_test.py arm128, which checks the generated kernels against a
reference:

GNU as (gcc 13.3, binutils 2.42, aarch64 Linux) LLVM (clang)
before assembles — 630/630 does not assemble
after assembles — 630/630 assembles — 630/630

So there is no regression under GNU as and clang is unblocked.

One note on the clang column: with FMA contraction left at the default, one
single-precision case differs by ~1.2e-6 relative. That is the C reference in
the test being contracted by the compiler, not the generated kernel —
-ffp-contract=off gives 630/630. The unchanged gcc column confirms the kernels
themselves are not affected.

AI tools used

Contains AI-generated content. (model: Opus 5)

The NEON backend printed the by-element FMLA/FMLS multiplicand with the
full arrangement specifier, e.g.

    fmla v11.2d, v1.2d, v3.2d[0]

The ARM ARM gives this instruction as

    FMLA <Vd>.<T>, <Vn>.<T>, <Vm>.<Ts>[<index>]

i.e. the third operand carries the element type, not the arrangement, so
it has to be written "v3.d[0]". GNU as accepts the redundant form, which
is why this has gone unnoticed, but the LLVM integrated assembler rejects
it with "invalid operand for instruction". That makes every NEON kernel
fail to assemble under clang, including the documented
HOST_ARCH=apple-m1/m2/m3/m4 builds of SeisSol on macOS.

Emit the element-type form instead. This is a pure syntax change; the
encoded instruction is the same.

Verified with tests/unit_test.py arm128:
  - gcc 13.3 / GNU as 2.42 (aarch64): 630/630 before and after
  - clang: does not assemble before; 630/630 after (with
    -ffp-contract=off; with contraction enabled one single-precision
    case differs by ~1e-6 relative, which is the C reference being
    fused, not the generated kernel)
Contains AI-generated content. (model: Opus 5)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant