[llvm] [AArch64] materialized neon reg with movi (PR #182540)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Feb 20 09:05:25 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-aarch64
Author: Congcong Cai (HerrCai0907)
<details>
<summary>Changes</summary>
This PR adds support for materializing certain scalar FP16 constants using NEON AdvSIMD MOVI instructions on AArch64 targets. This optimization allows select FP16 immediate values to be loaded directly into registers, instead of using constant pools.
Part of #<!-- -->182427. I don't add all patterns in this PR because I am not so family with td file, If it is fine, I will all the other similar pattern later.
---
Full diff: https://github.com/llvm/llvm-project/pull/182540.diff
5 Files Affected:
- (modified) llvm/lib/Target/AArch64/AArch64ISelLowering.cpp (+9)
- (modified) llvm/lib/Target/AArch64/AArch64InstrFormats.td (+14)
- (modified) llvm/lib/Target/AArch64/AArch64InstrInfo.td (+6)
- (modified) llvm/lib/Target/AArch64/MCTargetDesc/AArch64AddressingModes.h (+8)
- (added) llvm/test/CodeGen/AArch64/fp16-movi-imm.ll (+44)
``````````diff
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 7af6db793892b..27a8557e988d1 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -13194,6 +13194,15 @@ bool AArch64TargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
(Subtarget->hasFullFP16() && AArch64_AM::getFP16Imm(ImmInt) != -1) ||
Imm.isPosZero();
+ // If NEON is available, some f16 bit patterns can be materialized using
+ // integer MOVI into a vector register and then extracted.
+ if (!IsLegal && VT == MVT::f16 && Subtarget->hasNEON()) {
+ uint64_t Enc = ImmInt.getZExtValue() & 0xffff;
+ if (Enc != 0) {
+ IsLegal = AArch64_AM::isFpImm16FittedAdvSIMDModImmType5(Enc);
+ }
+ }
+
// If we can not materialize in immediate field for fmov, check if the
// value can be encoded as the immediate operand of a logical instruction.
// The immediate value will be created with either MOVZ, MOVN, or ORR.
diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index 7d4e034ca16c8..c957463ce4661 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -1465,6 +1465,12 @@ def fpimm16XForm : SDNodeXForm<fpimm, [{
return CurDAG->getTargetConstant(Enc, SDLoc(N), MVT::i32);
}]>;
+def fpimm16SIMDModImmType5XForm : SDNodeXForm<fpimm, [{
+ uint64_t Enc = N->getValueAPF().bitcastToAPInt().getZExtValue();
+ uint32_t Imm8 = AArch64_AM::encodeFpImm16FittedAdvSIMDModImmType5(Enc);
+ return CurDAG->getTargetConstant(Imm8, SDLoc(N), MVT::i32);
+ }]>;
+
def fpimm32XForm : SDNodeXForm<fpimm, [{
uint32_t Enc = AArch64_AM::getFP32Imm(N->getValueAPF());
return CurDAG->getTargetConstant(Enc, SDLoc(N), MVT::i32);
@@ -1509,6 +1515,14 @@ def fpimm32SIMDModImmType4 : FPImmLeaf<f32, [{
}], fpimm32SIMDModImmType4XForm> {
}
+def fpimm16SIMDModImmType5 : FPImmLeaf<f16, [{
+ uint64_t Enc = Imm.bitcastToAPInt().getZExtValue();
+ if (Enc == 0)
+ return false;
+ return AArch64_AM::isFpImm16FittedAdvSIMDModImmType5(Enc);
+ }], fpimm16SIMDModImmType5XForm> {
+}
+
def fpimm64 : Operand<f64>,
FPImmLeaf<f64, [{
return AArch64_AM::getFP64Imm(Imm) != -1;
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index f69b023b201d8..f87add740a758 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -8714,6 +8714,12 @@ let Predicates = [HasNEON] in {
(EXTRACT_SUBREG (MOVIv2i32 (fpimm32SIMDModImmType4XForm f32:$in),
(i32 24)),
ssub)>;
+
+ // Using MOVI to materialize select FP16 bit patterns (where one byte is 0).
+ def : Pat<(f16 fpimm16SIMDModImmType5:$in),
+ (EXTRACT_SUBREG (MOVIv4i16 (fpimm16SIMDModImmType5XForm f16:$in),
+ (i32 0)),
+ hsub)>;
}
let Predicates = [HasNEON] in {
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AddressingModes.h b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AddressingModes.h
index 1d3f089e2130b..3594c924d87f4 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AddressingModes.h
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AddressingModes.h
@@ -523,6 +523,14 @@ static inline uint64_t decodeAdvSIMDModImmType5(uint8_t Imm) {
return (EncVal << 48) | (EncVal << 32) | (EncVal << 16) | EncVal;
}
+static inline bool isFpImm16FittedAdvSIMDModImmType5(uint16_t Imm) {
+ return (Imm & 0xffULL) == Imm;
+}
+
+static inline uint8_t encodeFpImm16FittedAdvSIMDModImmType5(uint16_t Imm) {
+ return (Imm & 0xffULL);
+}
+
// abcdefgh 0x00 abcdefgh 0x00 abcdefgh 0x00 abcdefgh 0x00
static inline bool isAdvSIMDModImmType6(uint64_t Imm) {
return ((Imm >> 32) == (Imm & 0xffffffffULL)) &&
diff --git a/llvm/test/CodeGen/AArch64/fp16-movi-imm.ll b/llvm/test/CodeGen/AArch64/fp16-movi-imm.ll
new file mode 100644
index 0000000000000..f1bc48addbe17
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/fp16-movi-imm.ll
@@ -0,0 +1,44 @@
+; NOTE: This test checks materialization of select scalar f16 constants via
+; AdvSIMD MOVI, avoiding constant pools when NEON is available.
+;
+; RUN: llc -mtriple=aarch64-unknown-linux-gnu -O3 %s -o - | FileCheck %s --check-prefix=NEON
+; RUN: llc -mtriple=aarch64-unknown-linux-gnu -mattr=-neon -O3 %s -o - | FileCheck %s --check-prefix=NONEON
+
+define half @ret_half_0001() {
+; NEON-LABEL: ret_half_0001:
+; NEON: movi v0.4h, #1
+; NEON-NEXT: ret
+;
+; NONEON-LABEL: ret_half_0001:
+; NONEON: adrp
+; NONEON: ldr h0
+; NONEON-NEXT: ret
+entry:
+ ret half 0xH0001
+}
+
+define half @ret_half_001f() {
+; NEON-LABEL: ret_half_001f:
+; NEON: movi v0.4h, #31
+; NEON-NEXT: ret
+;
+; NONEON-LABEL: ret_half_001f:
+; NONEON: adrp
+; NONEON: ldr h0
+; NONEON-NEXT: ret
+entry:
+ ret half 0xH001f
+}
+
+; special case: zero should be materialized specially
+define half @ret_half_0000() {
+; NEON-LABEL: ret_half_0000:
+; NEON: movi d0, #0000000000000000
+; NEON-NEXT: ret
+;
+; NONEON-LABEL: ret_half_0000:
+; NONEON: fmov s0, wzr
+; NONEON-NEXT: ret
+entry:
+ ret half 0xH0000
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/182540
More information about the llvm-commits
mailing list