[llvm] f880391 - [SystemZ] Clear NW flags on an ISD::SUB when reused as comparison.

Jonas Paulsson via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 14 11:47:16 PDT 2023


Author: Jonas Paulsson
Date: 2023-03-14T19:46:41+01:00
New Revision: f8803919ad5c7e135af962efcbbe8c7c5310bbf4

URL: https://github.com/llvm/llvm-project/commit/f8803919ad5c7e135af962efcbbe8c7c5310bbf4
DIFF: https://github.com/llvm/llvm-project/commit/f8803919ad5c7e135af962efcbbe8c7c5310bbf4.diff

LOG: [SystemZ] Clear NW flags on an ISD::SUB when reused as comparison.

The SystemZ backend will try to reuse an existing subtraction of two values
whenever they are to be compared for equality. This depends on the SystemZ
subtraction instruction setting the condition code, which can also signal
overflow.

A later pass will remove the compare and reuse the CC from the subtraction
directly. However, if that subtraction has the NSW flag set it will not
include the overflow bit in the updated CC user. That was a bug which can
lead to wrong results, as shown by a csmith program.

Fixes: https://github.com/llvm/llvm-project/issues/61268

Reviewed By: nikic, uweigand

Differential Revision: https://reviews.llvm.org/D145811

Added: 
    llvm/test/CodeGen/SystemZ/int-cmp-62.ll

Modified: 
    llvm/lib/Target/SystemZ/SystemZISelLowering.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index 04ba0db75789..350819488714 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -2423,6 +2423,12 @@ static void adjustForSubtraction(SelectionDAG &DAG, const SDLoc &DL,
       if (N->getOpcode() == ISD::SUB &&
           ((N->getOperand(0) == C.Op0 && N->getOperand(1) == C.Op1) ||
            (N->getOperand(0) == C.Op1 && N->getOperand(1) == C.Op0))) {
+        // Disable the nsw and nuw flags: the backend needs to handle
+        // overflow as well during comparison elimination.
+        SDNodeFlags Flags = N->getFlags();
+        Flags.setNoSignedWrap(false);
+        Flags.setNoUnsignedWrap(false);
+        N->setFlags(Flags);
         C.Op0 = SDValue(N, 0);
         C.Op1 = DAG.getConstant(0, DL, N->getValueType(0));
         return;

diff  --git a/llvm/test/CodeGen/SystemZ/int-cmp-62.ll b/llvm/test/CodeGen/SystemZ/int-cmp-62.ll
new file mode 100644
index 000000000000..c57cf5777d0f
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/int-cmp-62.ll
@@ -0,0 +1,39 @@
+; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z15 | FileCheck %s
+;
+; Test that a CC result of a sub that can overflow is tested with the right predicate.
+
+define i32 @fun0(i32 %a, i32 %b, ptr %dest) {
+; CHECK-LABEL: fun0
+; CHECK: s %r2, 0(%r4)
+; CHECK: bner %r14
+entry:
+  %cur = load i32, ptr %dest
+  %res = sub nsw i32 %a, %cur
+  %cmp = icmp ne i32 %a, %cur
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store i32 %b, ptr %dest
+  br label %exit
+
+exit:
+  ret i32 %res
+}
+
+define i32 @fun1(i32 %a, i32 %b, ptr %dest) {
+; CHECK-LABEL: fun1
+; CHECK: s %r2, 0(%r4)
+; CHECK: bner %r14
+entry:
+  %cur = load i32, ptr %dest
+  %res = sub nuw i32 %a, %cur
+  %cmp = icmp ne i32 %a, %cur
+  br i1 %cmp, label %exit, label %store
+
+store:
+  store i32 %b, ptr %dest
+  br label %exit
+
+exit:
+  ret i32 %res
+}


        


More information about the llvm-commits mailing list