[llvm] 848dfb9 - [Hexagon] Do not sign extend the unsigned comparison of short integers. (#212914)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 6 07:26:11 PDT 2026
Author: Brian Cain
Date: 2026-08-06T14:26:05Z
New Revision: 848dfb98225281d68e9682e9eebc658ad7a4ff2c
URL: https://github.com/llvm/llvm-project/commit/848dfb98225281d68e9682e9eebc658ad7a4ff2c
DIFF: https://github.com/llvm/llvm-project/commit/848dfb98225281d68e9682e9eebc658ad7a4ff2c.diff
LOG: [Hexagon] Do not sign extend the unsigned comparison of short integers. (#212914)
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.
Co-authored-by: Sumanth Gundapaneni <sgundapa at quicinc.com>
Added:
llvm/test/CodeGen/Hexagon/cmp-extend-unsigned.ll
Modified:
llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp b/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
index 0e1b4d72eb03f..47e8a556df6ef 100644
--- a/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonISelLowering.cpp
@@ -1116,9 +1116,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: {
@@ -1141,7 +1142,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
+}
More information about the llvm-commits
mailing list