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 @@ -16381,6 +16381,46 @@ return SDValue(); } +// Transform and(fcmp(a, b), fcmp(c, d)) into fccmp(fcmp(a, b), c, d) +static SDValue performANDSETCCCombine(SDNode *N, + TargetLowering::DAGCombinerInfo &DCI) { + + // This function performs an optimization on a specific pattern involving + // an AND operation and SETCC (Set Condition Code) node. + + SDValue SetCC = N->getOperand(0); + EVT VT = N->getValueType(0); + SelectionDAG &DAG = DCI.DAG; + + // Checks if the current node (N) is used by any SELECT instruction and + // returns an empty SDValue to avoid applying the optimization to prevent + // incorrect results + for (auto U : N->uses()) + if (U->getOpcode() == ISD::SELECT) + return SDValue(); + + // Check if the operand is a SETCC node with floating-point comparison + if (SetCC.getOpcode() == ISD::SETCC && + SetCC.getOperand(0).getValueType() == MVT::f32) { + + SDValue Cmp; + AArch64CC::CondCode CC; + + // Check if the DAG is after legalization and if we can emit the conjunction + if (!DCI.isBeforeLegalize() && + (Cmp = emitConjunction(DAG, SDValue(N, 0), CC))) { + + AArch64CC::CondCode InvertedCC = AArch64CC::getInvertedCondCode(CC); + + SDLoc DL(N); + return DAG.getNode(AArch64ISD::CSINC, DL, VT, DAG.getConstant(0, DL, VT), + DAG.getConstant(0, DL, VT), + DAG.getConstant(InvertedCC, DL, MVT::i32), Cmp); + } + } + return SDValue(); +} + static SDValue performANDCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { SelectionDAG &DAG = DCI.DAG; @@ -16391,6 +16431,9 @@ if (SDValue R = performANDORCSELCombine(N, DAG)) return R; + if (SDValue R = performANDSETCCCombine(N,DCI)) + return R; + if (!DAG.getTargetLoweringInfo().isTypeLegal(VT)) return SDValue(); diff --git a/llvm/test/CodeGen/AArch64/andcompare.ll b/llvm/test/CodeGen/AArch64/andcompare.ll --- a/llvm/test/CodeGen/AArch64/andcompare.ll +++ b/llvm/test/CodeGen/AArch64/andcompare.ll @@ -2522,6 +2522,29 @@ ret i32 %r } +define i1 @and_fcmp(float %0, float %1) { +; SDISEL-LABEL: and_fcmp: +; SDISEL: // %bb.0: +; SDISEL-NEXT: fcmp s1, s1 +; SDISEL-NEXT: fccmp s0, s0, #0, vs +; SDISEL-NEXT: cset w0, vs +; SDISEL-NEXT: ret +; +; GISEL-LABEL: and_fcmp: +; GISEL: // %bb.0: +; GISEL-NEXT: fcmp s0, #0.0 +; GISEL-NEXT: cset w8, vs +; GISEL-NEXT: fcmp s1, #0.0 +; GISEL-NEXT: cset w9, vs +; GISEL-NEXT: and w0, w8, w9 +; GISEL-NEXT: ret + + %3 = fcmp uno float %0, 0.000000e+00 + %4 = fcmp uno float %1, 0.000000e+00 + %5 = and i1 %3, %4 + ret i1 %5 +} + ;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: ; CHECK: {{.*}}