[llvm] d1fc8f7 - [X86] Prevent infinite loop in SelectionDAG when lowering negations

Simon Pilgrim via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 13 04:20:58 PDT 2023


Author: Maurice Heumann
Date: 2023-07-13T12:20:44+01:00
New Revision: d1fc8f7211b12fd044a5f46d452fc505144a4f82

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

LOG: [X86] Prevent infinite loop in SelectionDAG when lowering negations

In certain cases, lowering negations can cause an infinite loop in SelectionDAG on X86.

The following snippet shows that behaviour:
https://godbolt.org/z/5hP45T4hY

What happens is that ADD(XOR(..., -1), 1) is detected as the two's complement and transformed into SUB(0, ...)
However, immediates can not be encoded as the LHS of a SUB on X86.
Therefore it is transformed back into an ADD/XOR pair, which is then again transformed into a SUB and so on.

In that specific case, I still think it is valid to display this as a SUB(0,...) , because it should eventually be lowered as a NEG.
Which seems better than an ADD/XOR pair.

Adding an exception to the X86 specific handling for SUBs with 0 LHS operand fixes this infinite loop.

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

Added: 
    llvm/test/CodeGen/X86/select-neg.ll

Modified: 
    llvm/lib/Target/X86/X86ISelLowering.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 8e79f5ea86a110..43b5a20006ba78 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -56734,9 +56734,11 @@ static SDValue combineSub(SDNode *N, SelectionDAG &DAG,
   // X86 can't encode an immediate LHS of a sub. See if we can push the
   // negation into a preceding instruction. If the RHS of the sub is a XOR with
   // one use and a constant, invert the immediate, saving one register.
+  // However, ignore cases where C1 is 0, as those will become a NEG.
   // sub(C1, xor(X, C2)) -> add(xor(X, ~C2), C1+1)
   if (Op1.getOpcode() == ISD::XOR && IsNonOpaqueConstant(Op0) &&
-      IsNonOpaqueConstant(Op1.getOperand(1)) && Op1->hasOneUse()) {
+      !isNullConstant(Op0) && IsNonOpaqueConstant(Op1.getOperand(1)) &&
+      Op1->hasOneUse()) {
     SDLoc DL(N);
     EVT VT = Op0.getValueType();
     SDValue NewXor = DAG.getNode(ISD::XOR, SDLoc(Op1), VT, Op1.getOperand(0),

diff  --git a/llvm/test/CodeGen/X86/select-neg.ll b/llvm/test/CodeGen/X86/select-neg.ll
new file mode 100644
index 00000000000000..cbefbe5cac4b81
--- /dev/null
+++ b/llvm/test/CodeGen/X86/select-neg.ll
@@ -0,0 +1,17 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -mtriple=i386-unknown-unknown | FileCheck %s
+
+ at value1 = external hidden constant i32
+
+define i32 @function(i32 %arg1) {
+; CHECK-LABEL: function:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    movl $value1, %eax
+; CHECK-NEXT:    xorl {{[0-9]+}}(%esp), %eax
+; CHECK-NEXT:    negl %eax
+; CHECK-NEXT:    retl
+entry:
+  %0 = xor i32 %arg1, xor (i32 ptrtoint (i32* @value1 to i32), i32 -1)
+  %.neg = add i32 %0, 1
+  ret i32 %.neg
+}


        


More information about the llvm-commits mailing list