Skip to content

[aarch64] Fix several instructions being lifted with the wrong semantics - #8699

Merged
bdash merged 7 commits into
devfrom
test_aarch64_misc_lifting_fixes
Oct 30, 2026
Merged

bdash merged 7 commits into
devfrom
test_aarch64_misc_lifting_fixes

Conversation

@bdash

@bdash bdash commented Oct 29, 2026

Copy link
Copy Markdown
Contributor
  • LDP/LDNP of W registers read through a base the first load had overwritten. LDPSW didn't sign-extend.
  • FMOV from a general register was lifted as an int-to-float conversion.
  • Unsigned FCVT*U to a general register was lifted as signed.
  • Vector ADD, SUB, UMULL, SMULL, CLZ and CLS were lifted as 128-bit scalar operations.
  • Vector ORR/BIC with an immediate didn't apply the immediate to each lane.
  • The lane-by-lane FSUB lift subtracted the wrong registers.

@bdash
bdash requested a review from zznop October 29, 2026 05:53
Comment thread arch/arm64/il.cpp Resolved
Comment thread arch/arm64/il.cpp Resolved
Comment thread arch/arm64/il.cpp Resolved
@bdash
bdash force-pushed the test_aarch64_misc_lifting_fixes branch from ec6b9e3 to 73aaec6 Compare October 29, 2026 21:42
@bdash
bdash requested a review from zznop October 29, 2026 21:46
bdash added 7 commits October 30, 2026 11:40
A 32-bit `LDP` or `LDNP` such as `ldp w2, w4, [x2]` computed the second
address from the value the first load had just written. The check for
this case compared `w2` with `x2`, so it never matched. It now compares
a W destination as its X register.

The temporary holding the second address is now read back at 8 bytes.
It was read at the load size, which truncated the address for `LDPSW`.
`LDPSW` also now sign-extends each word it loads.
`FMOV` from a general register to an FP register copies the bits, but
was lifted as `INT_TO_FLOAT`, so `fmov s1, w21` with `w21` holding 3
produced 3.0. It is now a register copy. The half-precision forms copy
the low 16 bits.

`FMOV <Vd>.D[1], <Xn>` now reads `Xn` as 64 bits rather than 128.
An ACLE intrinsic whose result went to WZR or XZR, such as
`fcvtas wzr, s20`, listed the zero register as its output. MLIL turned
that into a variable named `:0`.

The result now goes to a temporary, which discards it. This matches what
`IntrinsicToRegisters` already does for the plugin's own intrinsics.
…gned

`FCVTZU`, `FCVTMU`, `FCVTNU` and `FCVTPU` writing a general register
were lifted as signed `FLOAT_TO_INT`.

LLIL has no float to unsigned integer conversion. A W destination now
takes the low half of a 64-bit `FLOAT_TO_INT`, which holds every
in-range unsigned 32-bit result. An X destination lifts as the ACLE
intrinsic. ACLE has no intrinsic for `FCVTZU <Xd>, <Sn>, #<fbits>`, and
the one for `FCVTZU <Xd>, <Hn>, #<fbits>` takes at most 16 fraction
bits. Those forms widen the source to double and use the
double-precision intrinsic. Widening and scaling by a power of two are
exact, so the result is the same.
…tions

The vector forms of `ADD`, `SUB`, `UMULL`, `SMULL`, `CLZ` and `CLS` fell
through to the scalar lifting, which treated each vector register as one
128-bit integer. Carries crossed lanes and counts spanned the whole
register. The SME forms of `ADD` and `SUB` and the SVE forms of `CLZ`
and `CLS` fell through the same way.

The NEON forms now lift as ACLE intrinsics, like vector `MUL`. When
intrinsics are not preferred, vector `ADD` and `SUB` lift lane by lane
and the other NEON forms lift as unimplemented. The SME and SVE forms
lift as unimplemented, like the existing SVE forms of `ADD` and `SUB`.
`ORR` with an immediate wrote the immediate into each lane as if it were
`MOVI`, so `orr v0.4s, #1` set every lane to 1. `BIC` with an immediate
was one 128-bit AND with the immediate in lane 0 only, so
`bic v0.4s, #1` cleared only bit 0 of lane 0. It also set flags, which
vector `BIC` does not.

Both now apply the shifted immediate to each lane of `Vd`.
When intrinsics are not preferred, vector `FSUB` is lifted lane by lane.
That lifting read `Vd` and `Vn` instead of `Vn` and `Vm`, so
`fsub v0.4s, v1.4s, v2.4s` computed `v0 - v1`. It now computes `Vn - Vm`.
@bdash
bdash force-pushed the test_aarch64_misc_lifting_fixes branch from 73aaec6 to 68ff5f5 Compare October 30, 2026 18:51
@bdash
bdash merged commit 68ff5f5 into dev Oct 30, 2026
5 checks passed
@bdash
bdash deleted the test_aarch64_misc_lifting_fixes branch October 30, 2026 18:51
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.

2 participants