Skip to content

Commit d59fa9b

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 1786f3b commit d59fa9b

File tree

2 files changed

+10
-7
lines changed

2 files changed

+10
-7
lines changed

llvm/lib/Target/AArch64/AArch64ISelLowering.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3337,8 +3337,13 @@ static bool isLegalArithImmed(uint64_t C) {
33373337
return IsLegal;
33383338
}
33393339

3340-
static bool cannotBeIntMin(SDValue CheckedVal, SelectionDAG &DAG) {
3341-
KnownBits KnownSrc = DAG.computeKnownBits(CheckedVal);
3340+
static bool isSafeSignedCMN(SDValue Op, SelectionDAG &DAG) {
3341+
// 0 - INT_MIN sign wraps, so no signed wrap means cmn.
3342+
if (Op->getFlags().hasNoSignedWrap())
3343+
return true;
3344+
3345+
// Maybe nsw was not set here...
3346+
KnownBits KnownSrc = DAG.computeKnownBits(Op.getOperand(1));
33423347
return !KnownSrc.getSignedMinValue().isMinSignedValue();
33433348
}
33443349

@@ -3356,7 +3361,7 @@ static bool isCMN(SDValue Op, ISD::CondCode CC, SelectionDAG &DAG) {
33563361
return Op.getOpcode() == ISD::SUB && isNullConstant(Op.getOperand(0)) &&
33573362
(isIntEqualitySetCC(CC) ||
33583363
(isUnsignedIntSetCC(CC) && DAG.isKnownNeverZero(Op.getOperand(1))) ||
3359-
(isSignedIntSetCC(CC) && cannotBeIntMin(Op.getOperand(1), DAG)));
3364+
(isSignedIntSetCC(CC) && isSafeSignedCMN(Op, DAG)));
33603365
}
33613366

33623367
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
@@ -434,8 +434,7 @@ entry:
434434
define i1 @cmn_nsw(i32 %a, i32 %b) {
435435
; CHECK-LABEL: cmn_nsw:
436436
; CHECK: // %bb.0:
437-
; CHECK-NEXT: neg w8, w1
438-
; CHECK-NEXT: cmp w0, w8
437+
; CHECK-NEXT: cmn w0, w1
439438
; CHECK-NEXT: cset w0, gt
440439
; CHECK-NEXT: ret
441440
%sub = sub nsw i32 0, %b
@@ -446,8 +445,7 @@ ret i1 %cmp
446445
define i1 @cmn_nsw_64(i64 %a, i64 %b) {
447446
; CHECK-LABEL: cmn_nsw_64:
448447
; CHECK: // %bb.0:
449-
; CHECK-NEXT: neg x8, x1
450-
; CHECK-NEXT: cmp x0, x8
448+
; CHECK-NEXT: cmn x0, x1
451449
; CHECK-NEXT: cset w0, gt
452450
; CHECK-NEXT: ret
453451
%sub = sub nsw i64 0, %b

0 commit comments

Comments
 (0)