Index: lib/Target/PowerPC/PPCISelDAGToDAG.cpp =================================================================== --- lib/Target/PowerPC/PPCISelDAGToDAG.cpp +++ lib/Target/PowerPC/PPCISelDAGToDAG.cpp @@ -269,6 +269,10 @@ SDValue getSETGE0I64InGPR(SDValue LHS, SDLoc dl, bool IsSext); SDValue getSETLE0I32InGPR(SDValue LHS, SDLoc dl, bool IsSext); SDValue getSETLE0I64InGPR(SDValue LHS, SDLoc dl, bool IsSext); + SDValue get32BitZExtCompare(SDValue LHS, SDValue RHS, ISD::CondCode CC, + int64_t RHSValue, SDLoc dl); + SDValue get32BitSExtCompare(SDValue LHS, SDValue RHS, ISD::CondCode CC, + int64_t RHSValue, SDLoc dl); void PeepholePPC64(); void PeepholePPC64ZExt(); @@ -2631,6 +2635,225 @@ Or, getI64Imm(1, dl), getI64Imm(63, dl)), 0); } + +static void swapAndReset(SDValue &LHS, SDValue &RHS, bool &IsRHSZero, + bool &IsRHSOne, bool &IsRHSNegOne) { + std::swap(LHS, RHS); + ConstantSDNode *RHSConst = dyn_cast(RHS); + IsRHSZero = RHSConst && RHSConst->isNullValue(); + IsRHSOne = RHSConst && RHSConst->getSExtValue() == 1; + IsRHSNegOne = RHSConst && RHSConst->isAllOnesValue(); +} + +/// Produces a zero-extended result of comparing two 32-bit values according to +/// the passed condition code. +SDValue PPCDAGToDAGISel::get32BitZExtCompare(SDValue LHS, SDValue RHS, + ISD::CondCode CC, + int64_t RHSValue, SDLoc dl) { + bool IsRHSZero = RHSValue == 0; + bool IsRHSOne = RHSValue == 1; + bool IsRHSNegOne = RHSValue == -1LL; + switch (CC) { + default: llvm_unreachable("Unknown condition!"); + case ISD::SETEQ: { + SDValue Xor = IsRHSZero ? LHS : + SDValue(CurDAG->getMachineNode(PPC::XOR, dl, MVT::i32, LHS, RHS), 0); + SDValue Clz = + SDValue(CurDAG->getMachineNode(PPC::CNTLZW, dl, MVT::i32, Xor), 0); + SDValue ShiftOps[] = { Clz, getI32Imm(27, dl), getI32Imm(5, dl), + getI32Imm(31, dl) }; + return SDValue(CurDAG->getMachineNode(PPC::RLWINM, dl, MVT::i32, + ShiftOps), 0); + } + case ISD::SETNE: { + SDValue Xor = IsRHSZero ? LHS : + SDValue(CurDAG->getMachineNode(PPC::XOR, dl, MVT::i32, LHS, RHS), 0); + SDValue Clz = + SDValue(CurDAG->getMachineNode(PPC::CNTLZW, dl, MVT::i32, Xor), 0); + SDValue ShiftOps[] = { Clz, getI32Imm(27, dl), getI32Imm(5, dl), + getI32Imm(31, dl) }; + SDValue Shift = + SDValue(CurDAG->getMachineNode(PPC::RLWINM, dl, MVT::i32, ShiftOps), 0); + return SDValue(CurDAG->getMachineNode(PPC::XORI, dl, MVT::i32, Shift, + getI32Imm(1, dl)), 0); + } + case ISD::SETGE: { + if(IsRHSZero) + return getSETGE0I32InGPR(LHS, dl, false); + swapAndReset(LHS, RHS, IsRHSZero, IsRHSOne, IsRHSNegOne); + LLVM_FALLTHROUGH; + } + case ISD::SETLE: { + SDValue SubOrNeg = IsRHSZero ? + SDValue(CurDAG->getMachineNode(PPC::NEG, dl, MVT::i32, LHS), 0) : + SDValue(CurDAG->getMachineNode(PPC::SUBF, dl, MVT::i32, LHS, RHS), 0); + SDValue Shift = + SDValue(CurDAG->getMachineNode(PPC::RLDICL_32, dl, MVT::i32, SubOrNeg, + getI64Imm(1, dl), getI64Imm(63, dl)), 0); + return SDValue(CurDAG->getMachineNode(PPC::XORI, dl, + MVT::i32, Shift, getI32Imm(1, dl)), 0); + } + case ISD::SETGT: { + if (IsRHSNegOne) + return getSETGE0I32InGPR(LHS, dl, false); + if (IsRHSZero) { + SDValue Neg = + SDValue(CurDAG->getMachineNode(PPC::NEG, dl, MVT::i32, LHS), 0); + return SDValue(CurDAG->getMachineNode(PPC::RLDICL_32, dl, MVT::i32, + Neg, getI32Imm(1, dl), getI32Imm(63, dl)), 0); + } + swapAndReset(LHS, RHS, IsRHSZero, IsRHSOne, IsRHSNegOne); + LLVM_FALLTHROUGH; + } + case ISD::SETLT: { + // Handle SETLT 1 (which is equivalent to SETLE 0) + if (IsRHSOne) + return getSETLE0I32InGPR(LHS, dl, false); + if (IsRHSZero) { + SDValue ShiftOps[] = { LHS, getI32Imm(1, dl), getI32Imm(31, dl), + getI32Imm(31, dl) }; + return SDValue(CurDAG->getMachineNode(PPC::RLWINM, dl, MVT::i32, + ShiftOps), 0); + } + SDValue SUBFNode = + SDValue(CurDAG->getMachineNode(PPC::SUBF, dl, MVT::i32, RHS, LHS), 0); + return SDValue(CurDAG->getMachineNode(PPC::RLDICL_32, dl, MVT::i32, + SUBFNode, getI64Imm(1, dl), + getI64Imm(63, dl)), 0); + } + case ISD::SETUGE: + swapAndReset(LHS, RHS, IsRHSZero, IsRHSOne, IsRHSNegOne); + LLVM_FALLTHROUGH; + case ISD::SETULE: { + SDValue Subtract = + SDValue(CurDAG->getMachineNode(PPC::SUBF, dl, MVT::i32, LHS, RHS), 0); + SDValue SrdiNode = + SDValue(CurDAG->getMachineNode(PPC::RLDICL_32, dl, MVT::i32, + Subtract, getI64Imm(1, dl), + getI64Imm(63, dl)), 0); + return SDValue(CurDAG->getMachineNode(PPC::XORI, dl, MVT::i32, SrdiNode, + getI32Imm(1, dl)), 0); + } + case ISD::SETUGT: + swapAndReset(LHS, RHS, IsRHSZero, IsRHSOne, IsRHSNegOne); + LLVM_FALLTHROUGH; + case ISD::SETULT: { + // FIXME: This is converted upstream to a shift/subtract sequence that + // does excessive zero extension/truncation for i8 and i16. + SDValue Subtract = + SDValue(CurDAG->getMachineNode(PPC::SUBF, dl, MVT::i32, RHS, LHS), 0); + return SDValue(CurDAG->getMachineNode(PPC::RLDICL_32, dl, MVT::i32, + Subtract, getI64Imm(1, dl), + getI64Imm(63, dl)), 0); + } + } +} + +/// Produces a sign-extended result of comparing two 32-bit values according to +/// the passed condition code. +SDValue PPCDAGToDAGISel::get32BitSExtCompare(SDValue LHS, SDValue RHS, + ISD::CondCode CC, + int64_t RHSValue, SDLoc dl) { + bool IsRHSZero = RHSValue == 0; + bool IsRHSOne = RHSValue == 1; + bool IsRHSNegOne = RHSValue == -1LL; + switch (CC) { + default: llvm_unreachable("Unknown condition!"); + case ISD::SETEQ: { + SDValue CountInput = IsRHSZero ? LHS : + SDValue(CurDAG->getMachineNode(PPC::XOR, dl, MVT::i32, LHS, RHS), 0); + SDValue Cntlzw = + SDValue(CurDAG->getMachineNode(PPC::CNTLZW, dl, MVT::i32, CountInput), 0); + SDValue LSHROps[] = + { Cntlzw, getI32Imm(27, dl), getI32Imm(5, dl), getI32Imm(31, dl) }; + SDValue Srwi = + SDValue(CurDAG->getMachineNode(PPC::RLWINM, dl, MVT::i32, LSHROps), 0); + SDValue SHLOps[] = { Srwi, getI32Imm(63, dl), getI32Imm(0, dl) }; + SDValue Sldi = + SDValue(CurDAG->getMachineNode(PPC::RLDICR_32, dl, MVT::i32, SHLOps), 0); + return SDValue(CurDAG->getMachineNode(PPC::SRADI_32, dl, MVT::i32, Sldi, + getI32Imm(63, dl)), 0); + } + case ISD::SETNE: { + SDValue Xor = IsRHSZero ? LHS : + SDValue(CurDAG->getMachineNode(PPC::XOR, dl, MVT::i32, LHS, RHS), 0); + SDValue Clz = + SDValue(CurDAG->getMachineNode(PPC::CNTLZW, dl, MVT::i32, Xor), 0); + SDValue ShiftOps[] = + { Clz, getI32Imm(27, dl), getI32Imm(5, dl), getI32Imm(31, dl) }; + SDValue Shift = + SDValue(CurDAG->getMachineNode(PPC::RLWINM, dl, MVT::i32, ShiftOps), 0); + SDValue Xori = + SDValue(CurDAG->getMachineNode(PPC::XORI, dl, MVT::i32, Shift, + getI32Imm(1, dl)), 0); + return SDValue(CurDAG->getMachineNode(PPC::NEG, dl, MVT::i32, Xori), 0); + } + case ISD::SETGE: { + if(IsRHSZero) + return getSETGE0I32InGPR(LHS, dl, true); + swapAndReset(LHS, RHS, IsRHSZero, IsRHSOne, IsRHSNegOne); + LLVM_FALLTHROUGH; + } + case ISD::SETLE: { + if (IsRHSZero) + return getSETLE0I32InGPR(LHS, dl, true); + SDValue SUBFNode = + SDValue(CurDAG->getMachineNode(PPC::SUBF, dl, MVT::i32, MVT::Glue, + LHS, RHS), 0); + SDValue Srdi = + SDValue(CurDAG->getMachineNode(PPC::RLDICL_32, dl, MVT::i32, MVT::Glue, + SUBFNode, getI64Imm(1, dl), + getI64Imm(63, dl)), 0); + return SDValue(CurDAG->getMachineNode(PPC::ADDI, dl, MVT::i32, Srdi, + getI32Imm(-1, dl)), 0); + } + case ISD::SETGT: { + if (IsRHSNegOne) + return getSETGE0I32InGPR(LHS, dl, true); + if (IsRHSZero) { + SDValue Neg = + SDValue(CurDAG->getMachineNode(PPC::NEG, dl, MVT::i32, LHS), 0); + return SDValue(CurDAG->getMachineNode(PPC::SRADI_32, dl, MVT::i32, Neg, + getI64Imm(63, dl)), 0); + } + swapAndReset(LHS, RHS, IsRHSZero, IsRHSOne, IsRHSNegOne); + LLVM_FALLTHROUGH; + } + case ISD::SETLT: { + if (IsRHSOne) + return getSETLE0I32InGPR(LHS, dl, true); + if (IsRHSZero) + return SDValue(CurDAG->getMachineNode(PPC::SRAWI, dl, MVT::i32, LHS, + getI32Imm(31, dl)), 0); + SDValue SUBFNode = + SDValue(CurDAG->getMachineNode(PPC::SUBF, dl, MVT::i32, RHS, LHS), 0); + return SDValue(CurDAG->getMachineNode(PPC::SRADI_32, dl, MVT::i32, + SUBFNode, getI64Imm(63, dl)), 0); + } + case ISD::SETUGE: + swapAndReset(LHS, RHS, IsRHSZero, IsRHSOne, IsRHSNegOne); + LLVM_FALLTHROUGH; + case ISD::SETULE: { + SDValue Subtract = + SDValue(CurDAG->getMachineNode(PPC::SUBF, dl, MVT::i32, LHS, RHS), 0); + SDValue Shift = + SDValue(CurDAG->getMachineNode(PPC::RLDICL_32, dl, MVT::i32, Subtract, + getI32Imm(1, dl), getI32Imm(63,dl)), 0); + return SDValue(CurDAG->getMachineNode(PPC::ADDI, dl, MVT::i32, Shift, + getI32Imm(-1, dl)), 0); + } + case ISD::SETUGT: + swapAndReset(LHS, RHS, IsRHSZero, IsRHSOne, IsRHSNegOne); + LLVM_FALLTHROUGH; + case ISD::SETULT: { + SDValue Subtract = + SDValue(CurDAG->getMachineNode(PPC::SUBF, dl, MVT::i32, RHS, LHS), 0); + return SDValue(CurDAG->getMachineNode(PPC::SRADI_32, dl, MVT::i32, + Subtract, getI64Imm(63, dl)), 0); + } + } +} + void PPCDAGToDAGISel::transferMemOperands(SDNode *N, SDNode *Result) { // Transfer memoperands. MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);