Skip to content

Commit 79939d3

Browse files
committed
[AArch64] Signed comparison using CMN is safe when the subtraction is nsw
nsw means no signed wrap, and 0 - INT_MIN is a signed wrap. Now, this is going to be a point I need to get out of the way: So is it okay to always transform a > -b into cmn if it is a signed comparison, even if b is INT_MIN because -INT_MIN is undefined, at least in C. Taking advantage of UB doesn't introduce bugs. But, this could change behavior in programs with UB.
1 parent cf30d69 commit 79939d3

File tree

2 files changed

+18
-8
lines changed

2 files changed

+18
-8
lines changed

llvm/lib/Target/AArch64/AArch64ISelLowering.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3375,8 +3375,20 @@ bool isLegalCmpImmed(APInt C) {
33753375
return isLegalArithImmed(C.abs().getZExtValue());
33763376
}
33773377

3378-
static bool cannotBeIntMin(SDValue CheckedVal, SelectionDAG &DAG) {
3379-
KnownBits KnownSrc = DAG.computeKnownBits(CheckedVal);
3378+
static bool isSafeSignedCMN(SDValue Op, SelectionDAG &DAG) {
3379+
// 0 - INT_MIN sign wraps, so no signed wrap means cmn is safe.
3380+
if (Op->getFlags().hasNoSignedWrap())
3381+
return true;
3382+
3383+
// We can still figure out if the second operand is safe to use
3384+
// in a CMN instruction by checking if it is known to be not the minimum
3385+
// signed value. If it is not, then we can safely use CMN.
3386+
// FIXME: Can we can remove this check and simply rely on
3387+
// Op->getFlags().hasNoSignedWrap() once SelectionDAG/ISelLowering never
3388+
// creates subtract nodes, or SelectionDAG/ISelLowering consistently sets them
3389+
// appropiately when making said nodes?
3390+
3391+
KnownBits KnownSrc = DAG.computeKnownBits(Op.getOperand(1));
33803392
return !KnownSrc.getSignedMinValue().isMinSignedValue();
33813393
}
33823394

@@ -3385,7 +3397,7 @@ static bool cannotBeIntMin(SDValue CheckedVal, SelectionDAG &DAG) {
33853397
// can be set differently by this operation. It comes down to whether
33863398
// "SInt(~op2)+1 == SInt(~op2+1)" (and the same for UInt). If they are then
33873399
// everything is fine. If not then the optimization is wrong. Thus general
3388-
// comparisons are only valid if op2 != 0.
3400+
// comparisons are only valid if op2 != 0 and op2 != INT_MIN.
33893401
//
33903402
// So, finally, the only LLVM-native comparisons that don't mention C or V
33913403
// are the ones that aren't unsigned comparisons. They're the only ones we can
@@ -3394,7 +3406,7 @@ static bool isCMN(SDValue Op, ISD::CondCode CC, SelectionDAG &DAG) {
33943406
return Op.getOpcode() == ISD::SUB && isNullConstant(Op.getOperand(0)) &&
33953407
(isIntEqualitySetCC(CC) ||
33963408
(isUnsignedIntSetCC(CC) && DAG.isKnownNeverZero(Op.getOperand(1))) ||
3397-
(isSignedIntSetCC(CC) && cannotBeIntMin(Op.getOperand(1), DAG)));
3409+
(isSignedIntSetCC(CC) && isSafeSignedCMN(Op, DAG)));
33983410
}
33993411

34003412
static SDValue emitStrictFPComparison(SDValue LHS, SDValue RHS, const SDLoc &dl,

llvm/test/CodeGen/AArch64/cmp-to-cmn.ll

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -606,8 +606,7 @@ define i1 @almost_immediate_neg_ugt_64(i64 %x) {
606606
define i1 @cmn_nsw(i32 %a, i32 %b) {
607607
; CHECK-LABEL: cmn_nsw:
608608
; CHECK: // %bb.0:
609-
; CHECK-NEXT: neg w8, w1
610-
; CHECK-NEXT: cmp w0, w8
609+
; CHECK-NEXT: cmn w0, w1
611610
; CHECK-NEXT: cset w0, gt
612611
; CHECK-NEXT: ret
613612
%sub = sub nsw i32 0, %b
@@ -618,8 +617,7 @@ ret i1 %cmp
618617
define i1 @cmn_nsw_64(i64 %a, i64 %b) {
619618
; CHECK-LABEL: cmn_nsw_64:
620619
; CHECK: // %bb.0:
621-
; CHECK-NEXT: neg x8, x1
622-
; CHECK-NEXT: cmp x0, x8
620+
; CHECK-NEXT: cmn x0, x1
623621
; CHECK-NEXT: cset w0, gt
624622
; CHECK-NEXT: ret
625623
%sub = sub nsw i64 0, %b

0 commit comments

Comments
 (0)