diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -20023,11 +20023,11 @@ // (CSEL l r EQ (CMP (CSEL x y cc2 cond) x)) => (CSEL l r cc2 cond) // (CSEL l r EQ (CMP (CSEL x y cc2 cond) y)) => (CSEL l r !cc2 cond) -// Where x and y are constants +// Where x and y are constants and x != y // (CSEL l r NE (CMP (CSEL x y cc2 cond) x)) => (CSEL l r !cc2 cond) // (CSEL l r NE (CMP (CSEL x y cc2 cond) y)) => (CSEL l r cc2 cond) -// Where x and y are constants +// Where x and y are constants and x != y static SDValue foldCSELOfCSEL(SDNode *Op, SelectionDAG &DAG) { SDValue L = Op->getOperand(0); SDValue R = Op->getOperand(1); @@ -20048,10 +20048,18 @@ SDValue X = CmpLHS->getOperand(0); SDValue Y = CmpLHS->getOperand(1); - if (!isa(X) || !isa(Y)) { + if (!isa(X) || !isa(Y) || X == Y) { return SDValue(); } + // If one of the constant is opaque constant, x,y sdnode is still different + // but the real value maybe the same. So check APInt here to make sure the + // code is correct. + ConstantSDNode *CX = cast(X); + ConstantSDNode *CY = cast(Y); + if (CX->getAPIntValue() == CY->getAPIntValue()) + return SDValue(); + AArch64CC::CondCode CC = static_cast(CmpLHS->getConstantOperandVal(2)); SDValue Cond = CmpLHS->getOperand(3); diff --git a/llvm/test/CodeGen/AArch64/pr59902.ll b/llvm/test/CodeGen/AArch64/pr59902.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/pr59902.ll @@ -0,0 +1,23 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=aarch64-none-linux-gnu | FileCheck %s + +; This used to miscompile because foldCSELOfCSEL function +; doesn't check const x != y +define i1 @test() { +; CHECK-LABEL: test: +; CHECK: // %bb.0: +; CHECK-NEXT: mov x8, #9007199254740990 +; CHECK-NEXT: movk x8, #65503, lsl #16 +; CHECK-NEXT: movk x8, #65407, lsl #32 +; CHECK-NEXT: cmp x8, x8 +; CHECK-NEXT: csel x9, x8, x8, gt +; CHECK-NEXT: cmp x9, x8 +; CHECK-NEXT: cset w0, eq +; CHECK-NEXT: ret + %1 = select i1 false, i64 0, i64 9006649496829950 + %2 = call i64 @llvm.smax.i64(i64 %1, i64 9006649496829950) + %3 = icmp eq i64 %2, 9006649496829950 + ret i1 %3 +} + +declare i64 @llvm.smax.i64(i64, i64)