[llvm] [AArch64][GISel] Recover ADDHN from OR comparison masks (PR #213925)
Harry Ramsey via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 10 02:34:01 PDT 2026
https://github.com/Harry-Ramsey updated https://github.com/llvm/llvm-project/pull/213925
>From a9cf173e649159ca41389d0de91a4f01da7b80a7 Mon Sep 17 00:00:00 2001
From: Harry Ramsey <harry.ramsey at arm.com>
Date: Tue, 4 Aug 2026 09:41:29 +0000
Subject: [PATCH] [AArch64][GISel] Recover ADDHN from OR comparison masks
Add post legalize combine for recovering G_ADDHN from the GISel pattern;
G_TRUNC(G_OR(G_ICMP/G_FCMP, G_ICMP/G_FCMP)).
---
llvm/lib/Target/AArch64/AArch64Combine.td | 13 ++++++-
.../GISel/AArch64PostLegalizerCombiner.cpp | 36 +++++++++++++++++++
llvm/test/CodeGen/AArch64/is_fpclass.ll | 3 +-
llvm/test/CodeGen/AArch64/neon-addhn.ll | 9 ++---
4 files changed, 52 insertions(+), 9 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64Combine.td b/llvm/lib/Target/AArch64/AArch64Combine.td
index 82b9cec960d89..ce612f0b769a5 100644
--- a/llvm/lib/Target/AArch64/AArch64Combine.td
+++ b/llvm/lib/Target/AArch64/AArch64Combine.td
@@ -362,6 +362,16 @@ def or_to_bsp: GICombineRule <
(apply [{ applyOrToBSP(*${root}, MRI, B, ${matchinfo}); }])
>;
+def trunc_or_to_addhn : GICombineRule <
+ (defs root:$root),
+ (match (G_OR $trunc_src, $src1, $src2),
+ (G_TRUNC $dst, $trunc_src):$root,
+ [{ return matchTruncOrToADDHN(*${root}, MRI, VT, ${dst}.getReg(),
+ ${trunc_src}.getReg(), ${src1}.getReg(),
+ ${src2}.getReg()); }]),
+ (apply (G_ADDHN $dst, $src1, $src2))
+>;
+
// Combines Mul(And(Srl(X, 15), 0x10001), 0xffff) into CMLTz
def combine_mul_cmlt : GICombineRule<
(defs root:$root, register_matchinfo:$matchinfo),
@@ -402,7 +412,8 @@ def AArch64PostLegalizerCombiner
constant_fold_binops, identity_combines,
ptr_add_immed_chain, overlapping_and,
split_store_zero_128, undef_combines,
- select_to_minmax, or_to_bsp, combine_concat_vector,
+ select_to_minmax, or_to_bsp, trunc_or_to_addhn,
+ combine_concat_vector,
combine_build_vector_of_bitcast,
commute_constant_to_rhs, extract_vec_elt_combines,
push_freeze_to_prevent_poison_from_propagating,
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp b/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp
index 49091ad9f4eb0..f8030f4a0e282 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp
@@ -385,6 +385,42 @@ void applyOrToBSP(MachineInstr &MI, MachineRegisterInfo &MRI,
MI.eraseFromParent();
}
+/// Match G_TRUNC (G_OR X, Y) => G_ADDHN X, Y when both inputs are sign
+/// extended from the result element type. The high half of the addition then
+/// equals the truncation of the OR.
+bool matchTruncOrToADDHN(MachineInstr &MI, MachineRegisterInfo &MRI,
+ GISelValueTracking *VT, Register Dst, Register Or,
+ Register Src0, Register Src1) {
+ if (!MRI.hasOneUse(Or))
+ return false;
+
+ LLT DstTy = MRI.getType(Dst);
+ LLT SrcTy = MRI.getType(Or);
+ if (!((DstTy == LLT::fixed_vector(8, 8) &&
+ SrcTy == LLT::fixed_vector(8, 16)) ||
+ (DstTy == LLT::fixed_vector(4, 16) &&
+ SrcTy == LLT::fixed_vector(4, 32)) ||
+ (DstTy == LLT::fixed_vector(2, 32) &&
+ SrcTy == LLT::fixed_vector(2, 64))))
+ return false;
+
+ // If the narrow result is immediately any-extended back to the original type,
+ // the G_OR is cheaper than G_ADDHN followed by a vector widen.
+ if (MRI.hasOneNonDBGUse(Dst)) {
+ MachineInstr &UseMI = *MRI.use_nodbg_instructions(Dst).begin();
+ if (UseMI.getOpcode() == TargetOpcode::G_ANYEXT &&
+ MRI.getType(UseMI.getOperand(0).getReg()) == SrcTy)
+ return false;
+ }
+
+ unsigned EltSize = SrcTy.getScalarSizeInBits();
+ if (VT->computeNumSignBits(Src0) != EltSize ||
+ VT->computeNumSignBits(Src1) != EltSize)
+ return false;
+
+ return true;
+}
+
// Combines Mul(And(Srl(X, 15), 0x10001), 0xffff) into CMLTz
bool matchCombineMulCMLT(MachineInstr &MI, MachineRegisterInfo &MRI,
Register &SrcReg) {
diff --git a/llvm/test/CodeGen/AArch64/is_fpclass.ll b/llvm/test/CodeGen/AArch64/is_fpclass.ll
index e2ed2d96a85de..ed47db1bd3fdd 100644
--- a/llvm/test/CodeGen/AArch64/is_fpclass.ll
+++ b/llvm/test/CodeGen/AArch64/is_fpclass.ll
@@ -617,8 +617,7 @@ define <2 x i1> @not_isfinite_v2d(<2 x double> %x) {
; CHECK-GI-NEXT: ldr q1, [x8, :lo12:.LCPI17_0]
; CHECK-GI-NEXT: cmeq v2.2d, v0.2d, v1.2d
; CHECK-GI-NEXT: cmhi v0.2d, v0.2d, v1.2d
-; CHECK-GI-NEXT: orr v0.16b, v2.16b, v0.16b
-; CHECK-GI-NEXT: xtn v0.2s, v0.2d
+; CHECK-GI-NEXT: addhn v0.2s, v2.2d, v0.2d
; CHECK-GI-NEXT: ret
;
; CHECK-NOFP-LABEL: not_isfinite_v2d:
diff --git a/llvm/test/CodeGen/AArch64/neon-addhn.ll b/llvm/test/CodeGen/AArch64/neon-addhn.ll
index 23e290195e192..34bfb7a18f889 100644
--- a/llvm/test/CodeGen/AArch64/neon-addhn.ll
+++ b/llvm/test/CodeGen/AArch64/neon-addhn.ll
@@ -14,8 +14,7 @@ define <8 x i8> @addhn_setcc_v8i16( <8 x i16> %a, <8 x i16> %b, <8 x i16> %compa
; CHECK-GI: // %bb.0:
; CHECK-GI-NEXT: cmeq v0.8h, v0.8h, v2.8h
; CHECK-GI-NEXT: cmeq v1.8h, v1.8h, v2.8h
-; CHECK-GI-NEXT: orr v0.16b, v0.16b, v1.16b
-; CHECK-GI-NEXT: xtn v0.8b, v0.8h
+; CHECK-GI-NEXT: addhn v0.8b, v0.8h, v1.8h
; CHECK-GI-NEXT: ret
%cmp.a = icmp eq <8 x i16> %a, %comparand
%cmp.b = icmp eq <8 x i16> %b, %comparand
@@ -36,8 +35,7 @@ define <4 x i16> @addhn_setcc_v4i32( <4 x i32> %a, <4 x i32> %b, <4 x i32> %comp
; CHECK-GI: // %bb.0:
; CHECK-GI-NEXT: cmeq v0.4s, v0.4s, v2.4s
; CHECK-GI-NEXT: cmeq v1.4s, v1.4s, v2.4s
-; CHECK-GI-NEXT: orr v0.16b, v0.16b, v1.16b
-; CHECK-GI-NEXT: xtn v0.4h, v0.4s
+; CHECK-GI-NEXT: addhn v0.4h, v0.4s, v1.4s
; CHECK-GI-NEXT: ret
%cmp.a = icmp eq <4 x i32> %a, %comparand
%cmp.b = icmp eq <4 x i32> %b, %comparand
@@ -58,8 +56,7 @@ define <2 x i32> @addhn_setcc_v2i64( <2 x i64> %a, <2 x i64> %b, <2 x i64> %comp
; CHECK-GI: // %bb.0:
; CHECK-GI-NEXT: cmeq v0.2d, v0.2d, v2.2d
; CHECK-GI-NEXT: cmeq v1.2d, v1.2d, v2.2d
-; CHECK-GI-NEXT: orr v0.16b, v0.16b, v1.16b
-; CHECK-GI-NEXT: xtn v0.2s, v0.2d
+; CHECK-GI-NEXT: addhn v0.2s, v0.2d, v1.2d
; CHECK-GI-NEXT: ret
%cmp.a = icmp eq <2 x i64> %a, %comparand
%cmp.b = icmp eq <2 x i64> %b, %comparand
More information about the llvm-commits
mailing list