aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp')
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp100
1 files changed, 87 insertions, 13 deletions
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 80bbfea..b5d502b 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -2514,18 +2514,20 @@ static bool canFoldStoreIntoLibCallOutputPointers(StoreSDNode *StoreNode,
bool SelectionDAG::expandMultipleResultFPLibCall(
RTLIB::Libcall LC, SDNode *Node, SmallVectorImpl<SDValue> &Results,
- std::optional<unsigned> CallRetResNo) {
- LLVMContext &Ctx = *getContext();
- EVT VT = Node->getValueType(0);
- unsigned NumResults = Node->getNumValues();
-
+ EVT CallVT, std::optional<unsigned> CallRetResNo) {
if (LC == RTLIB::UNKNOWN_LIBCALL)
return false;
- const char *LCName = TLI->getLibcallName(LC);
- if (!LCName)
+ EVT VT = Node->getValueType(0);
+
+ RTLIB::LibcallImpl Impl = TLI->getLibcallImpl(LC);
+ if (Impl == RTLIB::Unsupported)
return false;
+ StringRef LCName = TLI->getLibcallImplName(Impl);
+
+ // FIXME: This should not use TargetLibraryInfo. There should be
+ // RTLIB::Libcall entries for each used vector type, and directly matched.
auto getVecDesc = [&]() -> VecDesc const * {
for (bool Masked : {false, true}) {
if (VecDesc const *VD = getLibInfo().getVectorMappingInfo(
@@ -2538,9 +2540,34 @@ bool SelectionDAG::expandMultipleResultFPLibCall(
// For vector types, we must find a vector mapping for the libcall.
VecDesc const *VD = nullptr;
- if (VT.isVector() && !(VD = getVecDesc()))
+ if (VT.isVector() && !CallVT.isVector() && !(VD = getVecDesc()))
return false;
+ bool IsMasked = (VD && VD->isMasked()) ||
+ RTLIB::RuntimeLibcallsInfo::hasVectorMaskArgument(Impl);
+
+ // This wrapper function exists because getVectorMappingInfo works in terms of
+ // function names instead of RTLIB enums.
+
+ // FIXME: If we used a vector mapping, this assumes the calling convention of
+ // the vector function is the same as the scalar.
+
+ StringRef Name = VD ? VD->getVectorFnName() : LCName;
+
+ return expandMultipleResultFPLibCall(Name,
+ TLI->getLibcallImplCallingConv(Impl),
+ Node, Results, CallRetResNo, IsMasked);
+}
+
+// FIXME: This belongs in TargetLowering
+bool SelectionDAG::expandMultipleResultFPLibCall(
+ StringRef Name, CallingConv::ID CC, SDNode *Node,
+ SmallVectorImpl<SDValue> &Results, std::optional<unsigned> CallRetResNo,
+ bool IsMasked) {
+ LLVMContext &Ctx = *getContext();
+ EVT VT = Node->getValueType(0);
+ unsigned NumResults = Node->getNumValues();
+
// Find users of the node that store the results (and share input chains). The
// destination pointers can be used instead of creating stack allocations.
SDValue StoresInChain;
@@ -2598,7 +2625,7 @@ bool SelectionDAG::expandMultipleResultFPLibCall(
SDLoc DL(Node);
// Pass the vector mask (if required).
- if (VD && VD->isMasked()) {
+ if (IsMasked) {
EVT MaskVT = TLI->getSetCCResultType(getDataLayout(), Ctx, VT);
SDValue Mask = getBoolConstant(true, DL, MaskVT, VT);
Args.emplace_back(Mask, MaskVT.getTypeForEVT(Ctx));
@@ -2608,11 +2635,11 @@ bool SelectionDAG::expandMultipleResultFPLibCall(
? Node->getValueType(*CallRetResNo).getTypeForEVT(Ctx)
: Type::getVoidTy(Ctx);
SDValue InChain = StoresInChain ? StoresInChain : getEntryNode();
- SDValue Callee = getExternalSymbol(VD ? VD->getVectorFnName().data() : LCName,
- TLI->getPointerTy(getDataLayout()));
+ SDValue Callee =
+ getExternalSymbol(Name.data(), TLI->getPointerTy(getDataLayout()));
TargetLowering::CallLoweringInfo CLI(*this);
- CLI.setDebugLoc(DL).setChain(InChain).setLibCallee(
- TLI->getLibcallCallingConv(LC), RetType, Callee, std::move(Args));
+ CLI.setDebugLoc(DL).setChain(InChain).setLibCallee(CC, RetType, Callee,
+ std::move(Args));
auto [Call, CallChain] = TLI->LowerCallTo(CLI);
@@ -2920,6 +2947,34 @@ bool SelectionDAG::SignBitIsZero(SDValue Op, unsigned Depth) const {
return MaskedValueIsZero(Op, APInt::getSignMask(BitWidth), Depth);
}
+bool SelectionDAG::SignBitIsZeroFP(SDValue Op, unsigned Depth) const {
+ if (Depth >= MaxRecursionDepth)
+ return false; // Limit search depth.
+
+ unsigned Opc = Op.getOpcode();
+ switch (Opc) {
+ case ISD::FABS:
+ return true;
+ case ISD::AssertNoFPClass: {
+ FPClassTest NoFPClass =
+ static_cast<FPClassTest>(Op.getConstantOperandVal(1));
+
+ const FPClassTest TestMask = fcNan | fcNegative;
+ return (NoFPClass & TestMask) == TestMask;
+ }
+ case ISD::ARITH_FENCE:
+ return SignBitIsZeroFP(Op, Depth + 1);
+ case ISD::FEXP:
+ case ISD::FEXP2:
+ case ISD::FEXP10:
+ return Op->getFlags().hasNoNaNs();
+ default:
+ return false;
+ }
+
+ llvm_unreachable("covered opcode switch");
+}
+
/// MaskedValueIsZero - Return true if 'V & Mask' is known to be zero. We use
/// this predicate to simplify operations downstream. Mask is known to be zero
/// for bits that V cannot have.
@@ -4121,6 +4176,25 @@ KnownBits SelectionDAG::computeKnownBits(SDValue Op, const APInt &DemandedElts,
Known.One.clearLowBits(LogOfAlign);
break;
}
+ case ISD::AssertNoFPClass: {
+ Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1);
+
+ FPClassTest NoFPClass =
+ static_cast<FPClassTest>(Op.getConstantOperandVal(1));
+ const FPClassTest NegativeTestMask = fcNan | fcNegative;
+ if ((NoFPClass & NegativeTestMask) == NegativeTestMask) {
+ // Cannot be negative.
+ Known.makeNonNegative();
+ }
+
+ const FPClassTest PositiveTestMask = fcNan | fcPositive;
+ if ((NoFPClass & PositiveTestMask) == PositiveTestMask) {
+ // Cannot be positive.
+ Known.makeNegative();
+ }
+
+ break;
+ }
case ISD::FGETSIGN:
// All bits are zero except the low bit.
Known.Zero.setBitsFrom(1);