[llvm] [AArch64][GISel] Recover ADDHN from OR comparison masks (PR #213925)

via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 4 05:48:00 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-aarch64

Author: Harry Ramsey (Harry-Ramsey)

<details>
<summary>Changes</summary>

Add post legalize combine for recovering G_ADDHN from the GISel pattern; G_TRUNC(G_OR(G_ICMP/G_FCMP, G_ICMP/G_FCMP)).

---
Full diff: https://github.com/llvm/llvm-project/pull/213925.diff


5 Files Affected:

- (modified) llvm/lib/Target/AArch64/AArch64Combine.td (+11-3) 
- (modified) llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp (+44) 
- (modified) llvm/test/CodeGen/AArch64/is_fpclass.ll (+1-2) 
- (modified) llvm/test/CodeGen/AArch64/neon-addhn.ll (+3-6) 
- (modified) llvm/test/CodeGen/AArch64/setcc-redundant-cmlt.ll (+4-1) 


``````````diff
diff --git a/llvm/lib/Target/AArch64/AArch64Combine.td b/llvm/lib/Target/AArch64/AArch64Combine.td
index 82b9cec960d89..ea5f65898295b 100644
--- a/llvm/lib/Target/AArch64/AArch64Combine.td
+++ b/llvm/lib/Target/AArch64/AArch64Combine.td
@@ -362,6 +362,13 @@ def or_to_bsp: GICombineRule <
   (apply [{ applyOrToBSP(*${root}, MRI, B, ${matchinfo}); }])
 >;
 
+def trunc_or_to_addhn : GICombineRule <
+  (defs root:$root, simplify_uaddo_matchinfo:$matchinfo),
+  (match (G_TRUNC $dst, $src):$root,
+         [{ return matchTruncOrToADDHN(*${root}, MRI, VT, ${matchinfo}); }]),
+  (apply [{ applyTruncOrToADDHN(*${root}, MRI, B, ${matchinfo}); }])
+>;
+
 // Combines Mul(And(Srl(X, 15), 0x10001), 0xffff) into CMLTz
 def combine_mul_cmlt : GICombineRule<
   (defs root:$root, register_matchinfo:$matchinfo),
@@ -387,9 +394,9 @@ def AArch64PostLegalizerLowering
 // Post-legalization combines which are primarily optimizations.
 def AArch64PostLegalizerCombiner
     : GICombiner<"AArch64PostLegalizerCombinerImpl",
-                       [copy_prop, cast_of_cast_combines, constant_fold_fp_ops, 
+                       [copy_prop, cast_of_cast_combines, constant_fold_fp_ops,
                         buildvector_of_truncate, integer_of_truncate,
-                        mutate_anyext_to_zext, combines_for_extload, 
+                        mutate_anyext_to_zext, combines_for_extload,
                         combine_indexed_load_store, sext_trunc_sextload,
                         hoist_logic_op_with_same_opcode_hands,
                         redundant_and, xor_of_and_with_same_reg,
@@ -402,7 +409,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..6638a9c3a975a 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64PostLegalizerCombiner.cpp
@@ -385,6 +385,50 @@ 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,
+                         std::pair<Register, Register> &MatchInfo) {
+  assert(MI.getOpcode() == TargetOpcode::G_TRUNC && VT);
+
+  Register Dst = MI.getOperand(0).getReg();
+  Register Or = MI.getOperand(1).getReg();
+  MachineInstr *OrMI = getOpcodeDef(TargetOpcode::G_OR, Or, MRI);
+  if (!OrMI || !MRI.hasOneNonDBGUse(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;
+
+  Register Src0 = OrMI->getOperand(1).getReg();
+  Register Src1 = OrMI->getOperand(2).getReg();
+  unsigned EltSize = SrcTy.getScalarSizeInBits();
+  if (VT->computeNumSignBits(Src0) != EltSize ||
+      VT->computeNumSignBits(Src1) != EltSize)
+    return false;
+
+  MatchInfo = {Src0, Src1};
+  return true;
+}
+
+void applyTruncOrToADDHN(MachineInstr &MI, MachineRegisterInfo &MRI,
+                         MachineIRBuilder &B,
+                         std::pair<Register, Register> &MatchInfo) {
+  B.setInstrAndDebugLoc(MI);
+  B.buildInstr(AArch64::G_ADDHN, {MI.getOperand(0).getReg()},
+               {MatchInfo.first, MatchInfo.second});
+  MI.eraseFromParent();
+}
+
 // 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
diff --git a/llvm/test/CodeGen/AArch64/setcc-redundant-cmlt.ll b/llvm/test/CodeGen/AArch64/setcc-redundant-cmlt.ll
index fe4f35b9a3527..6a499acf58c82 100644
--- a/llvm/test/CodeGen/AArch64/setcc-redundant-cmlt.ll
+++ b/llvm/test/CodeGen/AArch64/setcc-redundant-cmlt.ll
@@ -390,7 +390,10 @@ define <4 x i32> @or_setcc(<4 x i32> %a, <4 x i32> %b, <4 x i32> %c, <4 x i32> %
 ; CHECK-GI:       // %bb.0:
 ; CHECK-GI-NEXT:    cmgt v0.4s, v1.4s, v0.4s
 ; CHECK-GI-NEXT:    cmgt v1.4s, v3.4s, v2.4s
-; CHECK-GI-NEXT:    orr v0.16b, v0.16b, v1.16b
+; CHECK-GI-NEXT:    addhn v0.4h, v0.4s, v1.4s
+; CHECK-GI-NEXT:    ushll v0.4s, v0.4h, #0
+; CHECK-GI-NEXT:    shl v0.4s, v0.4s, #31
+; CHECK-GI-NEXT:    cmlt v0.4s, v0.4s, #0
 ; CHECK-GI-NEXT:    cmlt v0.4s, v0.4s, #0
 ; CHECK-GI-NEXT:    bsl v0.16b, v4.16b, v5.16b
 ; CHECK-GI-NEXT:    ret

``````````

</details>


https://github.com/llvm/llvm-project/pull/213925


More information about the llvm-commits mailing list