| Issue |
182427
|
| Summary |
[AArch64] Materialise constants in NEON registers using `MOVI`/`MVNI`
|
| Labels |
backend:AArch64,
missed-optimization
|
| Assignees |
|
| Reporter |
Kmeakin
|
When materialising a constant in a NEON register, LLVM prefers to first materialise the constant into a scalar register, then copy into a NEON register using `FMOV`. However, in some cases, LLVM could use [`MOVI`](https://docsmirror.github.io/A64/2023-06/movi_advsimd.html) or [`MVNI` ](https://docsmirror.github.io/A64/2023-06/mvni_advsimd.html)
# Example
https://godbolt.org/z/6vG1Kn15E
```c++
#include <arm_neon.h>
#include <bit>
using half = __fp16;
half half_movi_1() { return std::bit_cast<half, short>(1); }
half half_movi_2() { return std::bit_cast<half, short>(2); }
half half_movi_3() { return std::bit_cast<half, short>(3); }
half half_mvni_0() { return std::bit_cast<half, short>(-1); }
half half_mvni_1() { return std::bit_cast<half, short>(-2); }
half half_mvni_2() { return std::bit_cast<half, short>(-3); }
float float_movi_1() { return std::bit_cast<float, int>(1); }
float float_movi_2() { return std::bit_cast<float, int>(2); }
float float_movi_3() { return std::bit_cast<float, int>(3); }
float float_mvni_0() { return std::bit_cast<float, int>(-1); }
float float_mvni_1() { return std::bit_cast<float, int>(-2); }
float float_mvni_2() { return std::bit_cast<float, int>(-3); }
double double_mvni_0() { return std::bit_cast<double, long>(0xffffffff'ffffffff); }
double double_mvni_1() { return std::bit_cast<double, long>(0xfffffffe'fffffffe); }
double double_mvni_2() { return std::bit_cast<double, long>(0xfffffffd'fffffffd); }
```
## GCC assembly
```asm
half_movi_1():
movi v0.4h, 0x1
ret
half_movi_2():
movi v0.4h, 0x2
ret
half_movi_3():
movi v0.4h, 0x3
ret
half_mvni_0():
mvni v0.2s, 0
ret
half_mvni_1():
mvni v0.4h, 0x1
ret
half_mvni_2():
mvni v0.4h, 0x2
ret
float_movi_1():
movi v0.2s, 0x1
ret
float_movi_2():
movi v0.2s, 0x2
ret
float_movi_3():
movi v0.2s, 0x3
ret
float_mvni_0():
mvni v0.2s, 0
ret
float_mvni_1():
mvni v0.2s, 0x1
ret
float_mvni_2():
mvni v0.2s, 0x2
ret
double_mvni_0():
mvni v0.4s, 0
ret
double_mvni_1():
mvni v0.4s, 0x1
ret
double_mvni_2():
mvni v0.4s, 0x2
ret
double double_mvni_2() { return std::bit_cast<double, long>(0xfffffffd'fffffffd); }
```
## LLVM assembly
```asm
.LCPI0_0:
.hword 0x0001
half_movi_1():
adrp x8, .LCPI0_0
ldr h0, [x8, :lo12:.LCPI0_0]
ret
.LCPI1_0:
.hword 0x0002
half_movi_2():
adrp x8, .LCPI1_0
ldr h0, [x8, :lo12:.LCPI1_0]
ret
.LCPI2_0:
.hword 0x0003
half_movi_3():
adrp x8, .LCPI2_0
ldr h0, [x8, :lo12:.LCPI2_0]
ret
.LCPI3_0:
.hword 0xffff
half_mvni_0():
adrp x8, .LCPI3_0
ldr h0, [x8, :lo12:.LCPI3_0]
ret
.LCPI4_0:
.hword 0xfffe
half_mvni_1():
adrp x8, .LCPI4_0
ldr h0, [x8, :lo12:.LCPI4_0]
ret
.LCPI5_0:
.hword 0xfffd
half_mvni_2():
adrp x8, .LCPI5_0
ldr h0, [x8, :lo12:.LCPI5_0]
ret
float_movi_1():
mov w8, #1
fmov s0, w8
ret
float_movi_2():
mov w8, #2
fmov s0, w8
ret
float_movi_3():
mov w8, #3
fmov s0, w8
ret
float_mvni_0():
mov w8, #-1
fmov s0, w8
ret
float_mvni_1():
mov w8, #-2
fmov s0, w8
ret
float_mvni_2():
mov w8, #-3
fmov s0, w8
ret
double_mvni_0():
movi d0, #0xffffffffffffffff
ret
double_mvni_1():
mov x8, #-4294967298
fmov d0, x8
ret
double_mvni_2():
mov x8, #-8589934595
fmov d0, x8
ret
```
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs