diff --git a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h --- a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h +++ b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h @@ -1565,6 +1565,8 @@ bool isOne() const { return Value->isOne(); } bool isNullValue() const { return Value->isZero(); } bool isAllOnesValue() const { return Value->isMinusOne(); } + bool isMaxSignedValue() const { return Value->isMaxValue(true); } + bool isMinSignedValue() const { return Value->isMinValue(true); } bool isOpaque() const { return ConstantSDNodeBits.IsOpaque; } diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp --- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -10223,9 +10223,62 @@ bool PreferSetCC = N->hasOneUse() && N->use_begin()->getOpcode() == ISD::BRCOND; - SDValue Combined = SimplifySetCC( - N->getValueType(0), N->getOperand(0), N->getOperand(1), - cast(N->getOperand(2))->get(), SDLoc(N), !PreferSetCC); + ISD::CondCode Cond = cast(N->getOperand(2))->get(); + EVT VT = N->getValueType(0); + + // SETCC(FREEZE(X), CONST, Cond) + // => + // FREEZE(SETCC(X, CONST, Cond)) + // This is correct if FREEZE(X) has one use and SETCC(FREEZE(X), CONST, Cond) + // isn't equivalent to true or false. + // For example, SETCC(FREEZE(X), -128, SETULT) cannot be folded to + // FREEZE(SETCC(X, -128, SETULT)) because X can be poison. + // + // This transformation is beneficial because visitBRCOND can fold + // BRCOND(FREEZE(X)) to BRCOND(X). + + // Conservatively optimize integer comparisons only. + if (PreferSetCC) { + // Do this only when SETCC is going to be used by BRCOND. + + SDValue N0 = N->getOperand(0), N1 = N->getOperand(1); + ConstantSDNode *N0C = dyn_cast(N0); + ConstantSDNode *N1C = dyn_cast(N1); + bool Updated = false; + + // Is 'X Cond C' always true or false? + auto IsAlwaysTrueOrFalse = [](ISD::CondCode Cond, ConstantSDNode *C) { + bool False = (Cond == ISD::SETULT && C->isNullValue()) || + (Cond == ISD::SETLT && C->isMinSignedValue()) || + (Cond == ISD::SETUGT && C->isAllOnesValue()) || + (Cond == ISD::SETGT && C->isMaxSignedValue()); + bool True = (Cond == ISD::SETULE && C->isAllOnesValue()) || + (Cond == ISD::SETLE && C->isMaxSignedValue()) || + (Cond == ISD::SETUGE && C->isNullValue()) || + (Cond == ISD::SETGE && C->isMinSignedValue()); + return True || False; + }; + + if (N0->getOpcode() == ISD::FREEZE && N0.hasOneUse() && N1C) { + if (!IsAlwaysTrueOrFalse(Cond, N1C)) { + N0 = N0->getOperand(0); + Updated = true; + } + } + if (N1->getOpcode() == ISD::FREEZE && N1.hasOneUse() && N0C) { + if (!IsAlwaysTrueOrFalse(ISD::getSetCCSwappedOperands(Cond), + N0C)) { + N1 = N1->getOperand(0); + Updated = true; + } + } + + if (Updated) + return DAG.getFreeze(DAG.getSetCC(SDLoc(N), VT, N0, N1, Cond)); + } + + SDValue Combined = SimplifySetCC(VT, N->getOperand(0), N->getOperand(1), Cond, + SDLoc(N), !PreferSetCC); if (!Combined) return SDValue(); diff --git a/llvm/test/CodeGen/X86/setcc-freeze.ll b/llvm/test/CodeGen/X86/setcc-freeze.ll --- a/llvm/test/CodeGen/X86/setcc-freeze.ll +++ b/llvm/test/CodeGen/X86/setcc-freeze.ll @@ -4,9 +4,7 @@ define i32 @f(i16* %p) { ; CHECK-LABEL: f: ; CHECK: # %bb.0: -; CHECK-NEXT: movzwl (%rdi), %eax -; CHECK-NEXT: andl $2048, %eax # imm = 0x800 -; CHECK-NEXT: testw %ax, %ax +; CHECK-NEXT: testb $8, 1(%rdi) ; CHECK-NEXT: je .LBB0_1 ; CHECK-NEXT: # %bb.2: # %B ; CHECK-NEXT: movl $20, %eax