[llvm] [Hexagon] Do not sign extend the unsigned comparison of short integers. (PR #212914)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 29 18:46:12 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-hexagon

Author: Brian Cain (androm3da)

<details>
<summary>Changes</summary>

HexagonTargetLowering::LowerSETCC widens i8/i16 SETCC operands to i32 with a sign extension when the extension is free, or when the compared constant is negative in the narrow type. That is what the compare instructions want for equality comparisons, since they can encode small negative immediates, but for unsigned comparisons a constant with the sign bit of the narrow type set becomes a large 32-bit value that has to be materialized in a register or use a constant extender. For

  %v = load i16, ptr %p
  %c = icmp ult i16 %v, 65524

we generated

  r1 = #-12
  r0 = memh(r0+#<!-- -->0)
  p0 = cmp.gtu(r1,r0)

instead of

  r0 = memuh(r0+#<!-- -->0)
  p0 = cmp.gtu(r0,##<!-- -->65523)

Restrict the transformation to equality condition codes and let the generic operand promotion pick the extension for everything else. Signed comparisons are unaffected, as the generic promotion already sign-extends them.

Note that only the quality of the generated code was affected: sign extension preserves the unsigned ordering of the values of the narrower type, so the code produced before this change was correct.

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


2 Files Affected:

- (modified) llvm/lib/Target/Hexagon/HexagonISelLowering.cpp (+12-4) 
- (added) llvm/test/CodeGen/Hexagon/cmp-extend-unsigned.ll (+40) 


``````````diff
diff --git a/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp b/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
index 0ac657f51724b..c99cdef0f47fa 100644
--- a/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
@@ -1077,9 +1077,10 @@ SDValue HexagonTargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const {
   if (ResTy.isVector())
     return Op;
 
-  // Comparisons of short integers should use sign-extend, not zero-extend,
-  // since we can represent small negative values in the compare instructions.
-  // The LLVM default is to use zero-extend arbitrarily in these cases.
+  // Equality comparisons of short integers should use sign-extend, not
+  // zero-extend, since we can represent small negative values in the compare
+  // instructions.  The LLVM default is to use zero-extend arbitrarily in
+  // these cases.
   auto isSExtFree = [this](SDValue N) {
     switch (N.getOpcode()) {
       case ISD::TRUNCATE: {
@@ -1102,7 +1103,14 @@ SDValue HexagonTargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const {
     return false;
   };
 
-  if (OpTy == MVT::i8 || OpTy == MVT::i16) {
+  // Only do this for equality comparisons.  Signed comparisons are already
+  // sign-extended by the generic operand promotion, and for unsigned
+  // comparisons a sign-extension is never profitable: it does not change the
+  // result (sign-extension preserves the unsigned ordering of the values of
+  // the narrower type), but it turns constants with the sign bit of the
+  // narrower type set into large 32-bit values, which then have to be
+  // materialized in a register or use a constant extender.
+  if ((OpTy == MVT::i8 || OpTy == MVT::i16) && ISD::isIntEqualitySetCC(CC)) {
     ConstantSDNode *C = dyn_cast<ConstantSDNode>(RHS);
     bool IsNegative = C && C->getAPIntValue().isNegative();
     if (IsNegative || isSExtFree(LHS) || isSExtFree(RHS))
diff --git a/llvm/test/CodeGen/Hexagon/cmp-extend-unsigned.ll b/llvm/test/CodeGen/Hexagon/cmp-extend-unsigned.ll
new file mode 100644
index 0000000000000..e4f7cbac441bb
--- /dev/null
+++ b/llvm/test/CodeGen/Hexagon/cmp-extend-unsigned.ll
@@ -0,0 +1,40 @@
+; RUN: llc -mtriple=hexagon < %s | FileCheck %s
+
+; Unsigned comparisons of short integers should not force a sign-extending
+; load, since sign-extending the operands only makes the compared constant
+; harder to encode.
+
+; CHECK-LABEL: f0:
+; CHECK-NOT: memh(
+; CHECK: r[[R0:[0-9]+]] = memuh(r0+#4)
+; CHECK: cmp.gtu(r[[R0]],#12)
+
+define i32 @f0(ptr %p) nounwind {
+entry:
+  %a = getelementptr inbounds i16, ptr %p, i32 2
+  %v = load i16, ptr %a, align 2
+  %c = icmp ugt i16 %v, 12
+  br i1 %c, label %exit0, label %exit1
+
+exit0:
+  ret i32 0
+
+exit1:
+  ret i32 1
+}
+
+; A constant with the sign bit of the short type set does not have to be
+; materialized in a register.
+
+; CHECK-LABEL: f1:
+; CHECK-NOT: memh(
+; CHECK: r[[R1:[0-9]+]] = memuh(r0+#0)
+; CHECK: cmp.gtu(r[[R1]],##65523)
+
+define i32 @f1(ptr %p) nounwind {
+entry:
+  %v = load i16, ptr %p, align 2
+  %c = icmp ult i16 %v, 65524
+  %r = zext i1 %c to i32
+  ret i32 %r
+}

``````````

</details>


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


More information about the llvm-commits mailing list