|  | //===- SelectionDAG.cpp - Implement the SelectionDAG data structures ------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This implements the SelectionDAG class. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/CodeGen/SelectionDAG.h" | 
|  | #include "SDNodeDbgValue.h" | 
|  | #include "llvm/ADT/APFloat.h" | 
|  | #include "llvm/ADT/APInt.h" | 
|  | #include "llvm/ADT/APSInt.h" | 
|  | #include "llvm/ADT/ArrayRef.h" | 
|  | #include "llvm/ADT/BitVector.h" | 
|  | #include "llvm/ADT/DenseSet.h" | 
|  | #include "llvm/ADT/FoldingSet.h" | 
|  | #include "llvm/ADT/STLExtras.h" | 
|  | #include "llvm/ADT/SmallPtrSet.h" | 
|  | #include "llvm/ADT/SmallVector.h" | 
|  | #include "llvm/ADT/Twine.h" | 
|  | #include "llvm/Analysis/AliasAnalysis.h" | 
|  | #include "llvm/Analysis/MemoryLocation.h" | 
|  | #include "llvm/Analysis/TargetLibraryInfo.h" | 
|  | #include "llvm/Analysis/ValueTracking.h" | 
|  | #include "llvm/Analysis/VectorUtils.h" | 
|  | #include "llvm/BinaryFormat/Dwarf.h" | 
|  | #include "llvm/CodeGen/Analysis.h" | 
|  | #include "llvm/CodeGen/FunctionLoweringInfo.h" | 
|  | #include "llvm/CodeGen/ISDOpcodes.h" | 
|  | #include "llvm/CodeGen/MachineBasicBlock.h" | 
|  | #include "llvm/CodeGen/MachineConstantPool.h" | 
|  | #include "llvm/CodeGen/MachineFrameInfo.h" | 
|  | #include "llvm/CodeGen/MachineFunction.h" | 
|  | #include "llvm/CodeGen/MachineMemOperand.h" | 
|  | #include "llvm/CodeGen/RuntimeLibcallUtil.h" | 
|  | #include "llvm/CodeGen/SDPatternMatch.h" | 
|  | #include "llvm/CodeGen/SelectionDAGAddressAnalysis.h" | 
|  | #include "llvm/CodeGen/SelectionDAGNodes.h" | 
|  | #include "llvm/CodeGen/SelectionDAGTargetInfo.h" | 
|  | #include "llvm/CodeGen/TargetFrameLowering.h" | 
|  | #include "llvm/CodeGen/TargetLowering.h" | 
|  | #include "llvm/CodeGen/TargetRegisterInfo.h" | 
|  | #include "llvm/CodeGen/TargetSubtargetInfo.h" | 
|  | #include "llvm/CodeGen/ValueTypes.h" | 
|  | #include "llvm/CodeGenTypes/MachineValueType.h" | 
|  | #include "llvm/IR/Constant.h" | 
|  | #include "llvm/IR/Constants.h" | 
|  | #include "llvm/IR/DataLayout.h" | 
|  | #include "llvm/IR/DebugInfoMetadata.h" | 
|  | #include "llvm/IR/DebugLoc.h" | 
|  | #include "llvm/IR/DerivedTypes.h" | 
|  | #include "llvm/IR/Function.h" | 
|  | #include "llvm/IR/GlobalValue.h" | 
|  | #include "llvm/IR/Metadata.h" | 
|  | #include "llvm/IR/Type.h" | 
|  | #include "llvm/Support/Casting.h" | 
|  | #include "llvm/Support/CodeGen.h" | 
|  | #include "llvm/Support/Compiler.h" | 
|  | #include "llvm/Support/Debug.h" | 
|  | #include "llvm/Support/ErrorHandling.h" | 
|  | #include "llvm/Support/KnownBits.h" | 
|  | #include "llvm/Support/MathExtras.h" | 
|  | #include "llvm/Support/raw_ostream.h" | 
|  | #include "llvm/Target/TargetMachine.h" | 
|  | #include "llvm/Target/TargetOptions.h" | 
|  | #include "llvm/TargetParser/Triple.h" | 
|  | #include "llvm/Transforms/Utils/SizeOpts.h" | 
|  | #include <algorithm> | 
|  | #include <cassert> | 
|  | #include <cstdint> | 
|  | #include <cstdlib> | 
|  | #include <limits> | 
|  | #include <optional> | 
|  | #include <set> | 
|  | #include <string> | 
|  | #include <utility> | 
|  | #include <vector> | 
|  |  | 
|  | using namespace llvm; | 
|  | using namespace llvm::SDPatternMatch; | 
|  |  | 
|  | /// makeVTList - Return an instance of the SDVTList struct initialized with the | 
|  | /// specified members. | 
|  | static SDVTList makeVTList(const EVT *VTs, unsigned NumVTs) { | 
|  | SDVTList Res = {VTs, NumVTs}; | 
|  | return Res; | 
|  | } | 
|  |  | 
|  | // Default null implementations of the callbacks. | 
|  | void SelectionDAG::DAGUpdateListener::NodeDeleted(SDNode*, SDNode*) {} | 
|  | void SelectionDAG::DAGUpdateListener::NodeUpdated(SDNode*) {} | 
|  | void SelectionDAG::DAGUpdateListener::NodeInserted(SDNode *) {} | 
|  |  | 
|  | void SelectionDAG::DAGNodeDeletedListener::anchor() {} | 
|  | void SelectionDAG::DAGNodeInsertedListener::anchor() {} | 
|  |  | 
|  | #define DEBUG_TYPE "selectiondag" | 
|  |  | 
|  | static cl::opt<bool> EnableMemCpyDAGOpt("enable-memcpy-dag-opt", | 
|  | cl::Hidden, cl::init(true), | 
|  | cl::desc("Gang up loads and stores generated by inlining of memcpy")); | 
|  |  | 
|  | static cl::opt<int> MaxLdStGlue("ldstmemcpy-glue-max", | 
|  | cl::desc("Number limit for gluing ld/st of memcpy."), | 
|  | cl::Hidden, cl::init(0)); | 
|  |  | 
|  | static cl::opt<unsigned> | 
|  | MaxSteps("has-predecessor-max-steps", cl::Hidden, cl::init(8192), | 
|  | cl::desc("DAG combiner limit number of steps when searching DAG " | 
|  | "for predecessor nodes")); | 
|  |  | 
|  | static void NewSDValueDbgMsg(SDValue V, StringRef Msg, SelectionDAG *G) { | 
|  | LLVM_DEBUG(dbgs() << Msg; V.getNode()->dump(G);); | 
|  | } | 
|  |  | 
|  | unsigned SelectionDAG::getHasPredecessorMaxSteps() { return MaxSteps; } | 
|  |  | 
|  | //===----------------------------------------------------------------------===// | 
|  | //                              ConstantFPSDNode Class | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | /// isExactlyValue - We don't rely on operator== working on double values, as | 
|  | /// it returns true for things that are clearly not equal, like -0.0 and 0.0. | 
|  | /// As such, this method can be used to do an exact bit-for-bit comparison of | 
|  | /// two floating point values. | 
|  | bool ConstantFPSDNode::isExactlyValue(const APFloat& V) const { | 
|  | return getValueAPF().bitwiseIsEqual(V); | 
|  | } | 
|  |  | 
|  | bool ConstantFPSDNode::isValueValidForType(EVT VT, | 
|  | const APFloat& Val) { | 
|  | assert(VT.isFloatingPoint() && "Can only convert between FP types"); | 
|  |  | 
|  | // convert modifies in place, so make a copy. | 
|  | APFloat Val2 = APFloat(Val); | 
|  | bool losesInfo; | 
|  | (void)Val2.convert(VT.getFltSemantics(), APFloat::rmNearestTiesToEven, | 
|  | &losesInfo); | 
|  | return !losesInfo; | 
|  | } | 
|  |  | 
|  | //===----------------------------------------------------------------------===// | 
|  | //                              ISD Namespace | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | bool ISD::isConstantSplatVector(const SDNode *N, APInt &SplatVal) { | 
|  | if (N->getOpcode() == ISD::SPLAT_VECTOR) { | 
|  | if (auto OptAPInt = N->getOperand(0)->bitcastToAPInt()) { | 
|  | unsigned EltSize = | 
|  | N->getValueType(0).getVectorElementType().getSizeInBits(); | 
|  | SplatVal = OptAPInt->trunc(EltSize); | 
|  | return true; | 
|  | } | 
|  | } | 
|  |  | 
|  | auto *BV = dyn_cast<BuildVectorSDNode>(N); | 
|  | if (!BV) | 
|  | return false; | 
|  |  | 
|  | APInt SplatUndef; | 
|  | unsigned SplatBitSize; | 
|  | bool HasUndefs; | 
|  | unsigned EltSize = N->getValueType(0).getVectorElementType().getSizeInBits(); | 
|  | // Endianness does not matter here. We are checking for a splat given the | 
|  | // element size of the vector, and if we find such a splat for little endian | 
|  | // layout, then that should be valid also for big endian (as the full vector | 
|  | // size is known to be a multiple of the element size). | 
|  | const bool IsBigEndian = false; | 
|  | return BV->isConstantSplat(SplatVal, SplatUndef, SplatBitSize, HasUndefs, | 
|  | EltSize, IsBigEndian) && | 
|  | EltSize == SplatBitSize; | 
|  | } | 
|  |  | 
|  | // FIXME: AllOnes and AllZeros duplicate a lot of code. Could these be | 
|  | // specializations of the more general isConstantSplatVector()? | 
|  |  | 
|  | bool ISD::isConstantSplatVectorAllOnes(const SDNode *N, bool BuildVectorOnly) { | 
|  | // Look through a bit convert. | 
|  | while (N->getOpcode() == ISD::BITCAST) | 
|  | N = N->getOperand(0).getNode(); | 
|  |  | 
|  | if (!BuildVectorOnly && N->getOpcode() == ISD::SPLAT_VECTOR) { | 
|  | APInt SplatVal; | 
|  | return isConstantSplatVector(N, SplatVal) && SplatVal.isAllOnes(); | 
|  | } | 
|  |  | 
|  | if (N->getOpcode() != ISD::BUILD_VECTOR) return false; | 
|  |  | 
|  | unsigned i = 0, e = N->getNumOperands(); | 
|  |  | 
|  | // Skip over all of the undef values. | 
|  | while (i != e && N->getOperand(i).isUndef()) | 
|  | ++i; | 
|  |  | 
|  | // Do not accept an all-undef vector. | 
|  | if (i == e) return false; | 
|  |  | 
|  | // Do not accept build_vectors that aren't all constants or which have non-~0 | 
|  | // elements. We have to be a bit careful here, as the type of the constant | 
|  | // may not be the same as the type of the vector elements due to type | 
|  | // legalization (the elements are promoted to a legal type for the target and | 
|  | // a vector of a type may be legal when the base element type is not). | 
|  | // We only want to check enough bits to cover the vector elements, because | 
|  | // we care if the resultant vector is all ones, not whether the individual | 
|  | // constants are. | 
|  | SDValue NotZero = N->getOperand(i); | 
|  | if (auto OptAPInt = NotZero->bitcastToAPInt()) { | 
|  | unsigned EltSize = N->getValueType(0).getScalarSizeInBits(); | 
|  | if (OptAPInt->countr_one() < EltSize) | 
|  | return false; | 
|  | } else | 
|  | return false; | 
|  |  | 
|  | // Okay, we have at least one ~0 value, check to see if the rest match or are | 
|  | // undefs. Even with the above element type twiddling, this should be OK, as | 
|  | // the same type legalization should have applied to all the elements. | 
|  | for (++i; i != e; ++i) | 
|  | if (N->getOperand(i) != NotZero && !N->getOperand(i).isUndef()) | 
|  | return false; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool ISD::isConstantSplatVectorAllZeros(const SDNode *N, bool BuildVectorOnly) { | 
|  | // Look through a bit convert. | 
|  | while (N->getOpcode() == ISD::BITCAST) | 
|  | N = N->getOperand(0).getNode(); | 
|  |  | 
|  | if (!BuildVectorOnly && N->getOpcode() == ISD::SPLAT_VECTOR) { | 
|  | APInt SplatVal; | 
|  | return isConstantSplatVector(N, SplatVal) && SplatVal.isZero(); | 
|  | } | 
|  |  | 
|  | if (N->getOpcode() != ISD::BUILD_VECTOR) return false; | 
|  |  | 
|  | bool IsAllUndef = true; | 
|  | for (const SDValue &Op : N->op_values()) { | 
|  | if (Op.isUndef()) | 
|  | continue; | 
|  | IsAllUndef = false; | 
|  | // Do not accept build_vectors that aren't all constants or which have non-0 | 
|  | // elements. We have to be a bit careful here, as the type of the constant | 
|  | // may not be the same as the type of the vector elements due to type | 
|  | // legalization (the elements are promoted to a legal type for the target | 
|  | // and a vector of a type may be legal when the base element type is not). | 
|  | // We only want to check enough bits to cover the vector elements, because | 
|  | // we care if the resultant vector is all zeros, not whether the individual | 
|  | // constants are. | 
|  | if (auto OptAPInt = Op->bitcastToAPInt()) { | 
|  | unsigned EltSize = N->getValueType(0).getScalarSizeInBits(); | 
|  | if (OptAPInt->countr_zero() < EltSize) | 
|  | return false; | 
|  | } else | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Do not accept an all-undef vector. | 
|  | if (IsAllUndef) | 
|  | return false; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool ISD::isBuildVectorAllOnes(const SDNode *N) { | 
|  | return isConstantSplatVectorAllOnes(N, /*BuildVectorOnly*/ true); | 
|  | } | 
|  |  | 
|  | bool ISD::isBuildVectorAllZeros(const SDNode *N) { | 
|  | return isConstantSplatVectorAllZeros(N, /*BuildVectorOnly*/ true); | 
|  | } | 
|  |  | 
|  | bool ISD::isBuildVectorOfConstantSDNodes(const SDNode *N) { | 
|  | if (N->getOpcode() != ISD::BUILD_VECTOR) | 
|  | return false; | 
|  |  | 
|  | for (const SDValue &Op : N->op_values()) { | 
|  | if (Op.isUndef()) | 
|  | continue; | 
|  | if (!isa<ConstantSDNode>(Op)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool ISD::isBuildVectorOfConstantFPSDNodes(const SDNode *N) { | 
|  | if (N->getOpcode() != ISD::BUILD_VECTOR) | 
|  | return false; | 
|  |  | 
|  | for (const SDValue &Op : N->op_values()) { | 
|  | if (Op.isUndef()) | 
|  | continue; | 
|  | if (!isa<ConstantFPSDNode>(Op)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool ISD::isVectorShrinkable(const SDNode *N, unsigned NewEltSize, | 
|  | bool Signed) { | 
|  | assert(N->getValueType(0).isVector() && "Expected a vector!"); | 
|  |  | 
|  | unsigned EltSize = N->getValueType(0).getScalarSizeInBits(); | 
|  | if (EltSize <= NewEltSize) | 
|  | return false; | 
|  |  | 
|  | if (N->getOpcode() == ISD::ZERO_EXTEND) { | 
|  | return (N->getOperand(0).getValueType().getScalarSizeInBits() <= | 
|  | NewEltSize) && | 
|  | !Signed; | 
|  | } | 
|  | if (N->getOpcode() == ISD::SIGN_EXTEND) { | 
|  | return (N->getOperand(0).getValueType().getScalarSizeInBits() <= | 
|  | NewEltSize) && | 
|  | Signed; | 
|  | } | 
|  | if (N->getOpcode() != ISD::BUILD_VECTOR) | 
|  | return false; | 
|  |  | 
|  | for (const SDValue &Op : N->op_values()) { | 
|  | if (Op.isUndef()) | 
|  | continue; | 
|  | if (!isa<ConstantSDNode>(Op)) | 
|  | return false; | 
|  |  | 
|  | APInt C = Op->getAsAPIntVal().trunc(EltSize); | 
|  | if (Signed && C.trunc(NewEltSize).sext(EltSize) != C) | 
|  | return false; | 
|  | if (!Signed && C.trunc(NewEltSize).zext(EltSize) != C) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool ISD::allOperandsUndef(const SDNode *N) { | 
|  | // Return false if the node has no operands. | 
|  | // This is "logically inconsistent" with the definition of "all" but | 
|  | // is probably the desired behavior. | 
|  | if (N->getNumOperands() == 0) | 
|  | return false; | 
|  | return all_of(N->op_values(), [](SDValue Op) { return Op.isUndef(); }); | 
|  | } | 
|  |  | 
|  | bool ISD::isFreezeUndef(const SDNode *N) { | 
|  | return N->getOpcode() == ISD::FREEZE && N->getOperand(0).isUndef(); | 
|  | } | 
|  |  | 
|  | template <typename ConstNodeType> | 
|  | bool ISD::matchUnaryPredicateImpl(SDValue Op, | 
|  | std::function<bool(ConstNodeType *)> Match, | 
|  | bool AllowUndefs, bool AllowTruncation) { | 
|  | // FIXME: Add support for scalar UNDEF cases? | 
|  | if (auto *C = dyn_cast<ConstNodeType>(Op)) | 
|  | return Match(C); | 
|  |  | 
|  | // FIXME: Add support for vector UNDEF cases? | 
|  | if (ISD::BUILD_VECTOR != Op.getOpcode() && | 
|  | ISD::SPLAT_VECTOR != Op.getOpcode()) | 
|  | return false; | 
|  |  | 
|  | EVT SVT = Op.getValueType().getScalarType(); | 
|  | for (unsigned i = 0, e = Op.getNumOperands(); i != e; ++i) { | 
|  | if (AllowUndefs && Op.getOperand(i).isUndef()) { | 
|  | if (!Match(nullptr)) | 
|  | return false; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | auto *Cst = dyn_cast<ConstNodeType>(Op.getOperand(i)); | 
|  | if (!Cst || (!AllowTruncation && Cst->getValueType(0) != SVT) || | 
|  | !Match(Cst)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  | // Build used template types. | 
|  | template bool ISD::matchUnaryPredicateImpl<ConstantSDNode>( | 
|  | SDValue, std::function<bool(ConstantSDNode *)>, bool, bool); | 
|  | template bool ISD::matchUnaryPredicateImpl<ConstantFPSDNode>( | 
|  | SDValue, std::function<bool(ConstantFPSDNode *)>, bool, bool); | 
|  |  | 
|  | bool ISD::matchBinaryPredicate( | 
|  | SDValue LHS, SDValue RHS, | 
|  | std::function<bool(ConstantSDNode *, ConstantSDNode *)> Match, | 
|  | bool AllowUndefs, bool AllowTypeMismatch) { | 
|  | if (!AllowTypeMismatch && LHS.getValueType() != RHS.getValueType()) | 
|  | return false; | 
|  |  | 
|  | // TODO: Add support for scalar UNDEF cases? | 
|  | if (auto *LHSCst = dyn_cast<ConstantSDNode>(LHS)) | 
|  | if (auto *RHSCst = dyn_cast<ConstantSDNode>(RHS)) | 
|  | return Match(LHSCst, RHSCst); | 
|  |  | 
|  | // TODO: Add support for vector UNDEF cases? | 
|  | if (LHS.getOpcode() != RHS.getOpcode() || | 
|  | (LHS.getOpcode() != ISD::BUILD_VECTOR && | 
|  | LHS.getOpcode() != ISD::SPLAT_VECTOR)) | 
|  | return false; | 
|  |  | 
|  | EVT SVT = LHS.getValueType().getScalarType(); | 
|  | for (unsigned i = 0, e = LHS.getNumOperands(); i != e; ++i) { | 
|  | SDValue LHSOp = LHS.getOperand(i); | 
|  | SDValue RHSOp = RHS.getOperand(i); | 
|  | bool LHSUndef = AllowUndefs && LHSOp.isUndef(); | 
|  | bool RHSUndef = AllowUndefs && RHSOp.isUndef(); | 
|  | auto *LHSCst = dyn_cast<ConstantSDNode>(LHSOp); | 
|  | auto *RHSCst = dyn_cast<ConstantSDNode>(RHSOp); | 
|  | if ((!LHSCst && !LHSUndef) || (!RHSCst && !RHSUndef)) | 
|  | return false; | 
|  | if (!AllowTypeMismatch && (LHSOp.getValueType() != SVT || | 
|  | LHSOp.getValueType() != RHSOp.getValueType())) | 
|  | return false; | 
|  | if (!Match(LHSCst, RHSCst)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | ISD::NodeType ISD::getInverseMinMaxOpcode(unsigned MinMaxOpc) { | 
|  | switch (MinMaxOpc) { | 
|  | default: | 
|  | llvm_unreachable("unrecognized opcode"); | 
|  | case ISD::UMIN: | 
|  | return ISD::UMAX; | 
|  | case ISD::UMAX: | 
|  | return ISD::UMIN; | 
|  | case ISD::SMIN: | 
|  | return ISD::SMAX; | 
|  | case ISD::SMAX: | 
|  | return ISD::SMIN; | 
|  | } | 
|  | } | 
|  |  | 
|  | ISD::NodeType ISD::getVecReduceBaseOpcode(unsigned VecReduceOpcode) { | 
|  | switch (VecReduceOpcode) { | 
|  | default: | 
|  | llvm_unreachable("Expected VECREDUCE opcode"); | 
|  | case ISD::VECREDUCE_FADD: | 
|  | case ISD::VECREDUCE_SEQ_FADD: | 
|  | case ISD::VP_REDUCE_FADD: | 
|  | case ISD::VP_REDUCE_SEQ_FADD: | 
|  | return ISD::FADD; | 
|  | case ISD::VECREDUCE_FMUL: | 
|  | case ISD::VECREDUCE_SEQ_FMUL: | 
|  | case ISD::VP_REDUCE_FMUL: | 
|  | case ISD::VP_REDUCE_SEQ_FMUL: | 
|  | return ISD::FMUL; | 
|  | case ISD::VECREDUCE_ADD: | 
|  | case ISD::VP_REDUCE_ADD: | 
|  | return ISD::ADD; | 
|  | case ISD::VECREDUCE_MUL: | 
|  | case ISD::VP_REDUCE_MUL: | 
|  | return ISD::MUL; | 
|  | case ISD::VECREDUCE_AND: | 
|  | case ISD::VP_REDUCE_AND: | 
|  | return ISD::AND; | 
|  | case ISD::VECREDUCE_OR: | 
|  | case ISD::VP_REDUCE_OR: | 
|  | return ISD::OR; | 
|  | case ISD::VECREDUCE_XOR: | 
|  | case ISD::VP_REDUCE_XOR: | 
|  | return ISD::XOR; | 
|  | case ISD::VECREDUCE_SMAX: | 
|  | case ISD::VP_REDUCE_SMAX: | 
|  | return ISD::SMAX; | 
|  | case ISD::VECREDUCE_SMIN: | 
|  | case ISD::VP_REDUCE_SMIN: | 
|  | return ISD::SMIN; | 
|  | case ISD::VECREDUCE_UMAX: | 
|  | case ISD::VP_REDUCE_UMAX: | 
|  | return ISD::UMAX; | 
|  | case ISD::VECREDUCE_UMIN: | 
|  | case ISD::VP_REDUCE_UMIN: | 
|  | return ISD::UMIN; | 
|  | case ISD::VECREDUCE_FMAX: | 
|  | case ISD::VP_REDUCE_FMAX: | 
|  | return ISD::FMAXNUM; | 
|  | case ISD::VECREDUCE_FMIN: | 
|  | case ISD::VP_REDUCE_FMIN: | 
|  | return ISD::FMINNUM; | 
|  | case ISD::VECREDUCE_FMAXIMUM: | 
|  | case ISD::VP_REDUCE_FMAXIMUM: | 
|  | return ISD::FMAXIMUM; | 
|  | case ISD::VECREDUCE_FMINIMUM: | 
|  | case ISD::VP_REDUCE_FMINIMUM: | 
|  | return ISD::FMINIMUM; | 
|  | } | 
|  | } | 
|  |  | 
|  | bool ISD::isVPOpcode(unsigned Opcode) { | 
|  | switch (Opcode) { | 
|  | default: | 
|  | return false; | 
|  | #define BEGIN_REGISTER_VP_SDNODE(VPSD, ...)                                    \ | 
|  | case ISD::VPSD:                                                              \ | 
|  | return true; | 
|  | #include "llvm/IR/VPIntrinsics.def" | 
|  | } | 
|  | } | 
|  |  | 
|  | bool ISD::isVPBinaryOp(unsigned Opcode) { | 
|  | switch (Opcode) { | 
|  | default: | 
|  | break; | 
|  | #define BEGIN_REGISTER_VP_SDNODE(VPSD, ...) case ISD::VPSD: | 
|  | #define VP_PROPERTY_BINARYOP return true; | 
|  | #define END_REGISTER_VP_SDNODE(VPSD) break; | 
|  | #include "llvm/IR/VPIntrinsics.def" | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool ISD::isVPReduction(unsigned Opcode) { | 
|  | switch (Opcode) { | 
|  | default: | 
|  | return false; | 
|  | case ISD::VP_REDUCE_ADD: | 
|  | case ISD::VP_REDUCE_MUL: | 
|  | case ISD::VP_REDUCE_AND: | 
|  | case ISD::VP_REDUCE_OR: | 
|  | case ISD::VP_REDUCE_XOR: | 
|  | case ISD::VP_REDUCE_SMAX: | 
|  | case ISD::VP_REDUCE_SMIN: | 
|  | case ISD::VP_REDUCE_UMAX: | 
|  | case ISD::VP_REDUCE_UMIN: | 
|  | case ISD::VP_REDUCE_FMAX: | 
|  | case ISD::VP_REDUCE_FMIN: | 
|  | case ISD::VP_REDUCE_FMAXIMUM: | 
|  | case ISD::VP_REDUCE_FMINIMUM: | 
|  | case ISD::VP_REDUCE_FADD: | 
|  | case ISD::VP_REDUCE_FMUL: | 
|  | case ISD::VP_REDUCE_SEQ_FADD: | 
|  | case ISD::VP_REDUCE_SEQ_FMUL: | 
|  | return true; | 
|  | } | 
|  | } | 
|  |  | 
|  | /// The operand position of the vector mask. | 
|  | std::optional<unsigned> ISD::getVPMaskIdx(unsigned Opcode) { | 
|  | switch (Opcode) { | 
|  | default: | 
|  | return std::nullopt; | 
|  | #define BEGIN_REGISTER_VP_SDNODE(VPSD, LEGALPOS, TDNAME, MASKPOS, ...)         \ | 
|  | case ISD::VPSD:                                                              \ | 
|  | return MASKPOS; | 
|  | #include "llvm/IR/VPIntrinsics.def" | 
|  | } | 
|  | } | 
|  |  | 
|  | /// The operand position of the explicit vector length parameter. | 
|  | std::optional<unsigned> ISD::getVPExplicitVectorLengthIdx(unsigned Opcode) { | 
|  | switch (Opcode) { | 
|  | default: | 
|  | return std::nullopt; | 
|  | #define BEGIN_REGISTER_VP_SDNODE(VPSD, LEGALPOS, TDNAME, MASKPOS, EVLPOS)      \ | 
|  | case ISD::VPSD:                                                              \ | 
|  | return EVLPOS; | 
|  | #include "llvm/IR/VPIntrinsics.def" | 
|  | } | 
|  | } | 
|  |  | 
|  | std::optional<unsigned> ISD::getBaseOpcodeForVP(unsigned VPOpcode, | 
|  | bool hasFPExcept) { | 
|  | // FIXME: Return strict opcodes in case of fp exceptions. | 
|  | switch (VPOpcode) { | 
|  | default: | 
|  | return std::nullopt; | 
|  | #define BEGIN_REGISTER_VP_SDNODE(VPOPC, ...) case ISD::VPOPC: | 
|  | #define VP_PROPERTY_FUNCTIONAL_SDOPC(SDOPC) return ISD::SDOPC; | 
|  | #define END_REGISTER_VP_SDNODE(VPOPC) break; | 
|  | #include "llvm/IR/VPIntrinsics.def" | 
|  | } | 
|  | return std::nullopt; | 
|  | } | 
|  |  | 
|  | std::optional<unsigned> ISD::getVPForBaseOpcode(unsigned Opcode) { | 
|  | switch (Opcode) { | 
|  | default: | 
|  | return std::nullopt; | 
|  | #define BEGIN_REGISTER_VP_SDNODE(VPOPC, ...) break; | 
|  | #define VP_PROPERTY_FUNCTIONAL_SDOPC(SDOPC) case ISD::SDOPC: | 
|  | #define END_REGISTER_VP_SDNODE(VPOPC) return ISD::VPOPC; | 
|  | #include "llvm/IR/VPIntrinsics.def" | 
|  | } | 
|  | } | 
|  |  | 
|  | ISD::NodeType ISD::getExtForLoadExtType(bool IsFP, ISD::LoadExtType ExtType) { | 
|  | switch (ExtType) { | 
|  | case ISD::EXTLOAD: | 
|  | return IsFP ? ISD::FP_EXTEND : ISD::ANY_EXTEND; | 
|  | case ISD::SEXTLOAD: | 
|  | return ISD::SIGN_EXTEND; | 
|  | case ISD::ZEXTLOAD: | 
|  | return ISD::ZERO_EXTEND; | 
|  | default: | 
|  | break; | 
|  | } | 
|  |  | 
|  | llvm_unreachable("Invalid LoadExtType"); | 
|  | } | 
|  |  | 
|  | ISD::CondCode ISD::getSetCCSwappedOperands(ISD::CondCode Operation) { | 
|  | // To perform this operation, we just need to swap the L and G bits of the | 
|  | // operation. | 
|  | unsigned OldL = (Operation >> 2) & 1; | 
|  | unsigned OldG = (Operation >> 1) & 1; | 
|  | return ISD::CondCode((Operation & ~6) |  // Keep the N, U, E bits | 
|  | (OldL << 1) |       // New G bit | 
|  | (OldG << 2));       // New L bit. | 
|  | } | 
|  |  | 
|  | static ISD::CondCode getSetCCInverseImpl(ISD::CondCode Op, bool isIntegerLike) { | 
|  | unsigned Operation = Op; | 
|  | if (isIntegerLike) | 
|  | Operation ^= 7;   // Flip L, G, E bits, but not U. | 
|  | else | 
|  | Operation ^= 15;  // Flip all of the condition bits. | 
|  |  | 
|  | if (Operation > ISD::SETTRUE2) | 
|  | Operation &= ~8;  // Don't let N and U bits get set. | 
|  |  | 
|  | return ISD::CondCode(Operation); | 
|  | } | 
|  |  | 
|  | ISD::CondCode ISD::getSetCCInverse(ISD::CondCode Op, EVT Type) { | 
|  | return getSetCCInverseImpl(Op, Type.isInteger()); | 
|  | } | 
|  |  | 
|  | ISD::CondCode ISD::GlobalISel::getSetCCInverse(ISD::CondCode Op, | 
|  | bool isIntegerLike) { | 
|  | return getSetCCInverseImpl(Op, isIntegerLike); | 
|  | } | 
|  |  | 
|  | /// For an integer comparison, return 1 if the comparison is a signed operation | 
|  | /// and 2 if the result is an unsigned comparison. Return zero if the operation | 
|  | /// does not depend on the sign of the input (setne and seteq). | 
|  | static int isSignedOp(ISD::CondCode Opcode) { | 
|  | switch (Opcode) { | 
|  | default: llvm_unreachable("Illegal integer setcc operation!"); | 
|  | case ISD::SETEQ: | 
|  | case ISD::SETNE: return 0; | 
|  | case ISD::SETLT: | 
|  | case ISD::SETLE: | 
|  | case ISD::SETGT: | 
|  | case ISD::SETGE: return 1; | 
|  | case ISD::SETULT: | 
|  | case ISD::SETULE: | 
|  | case ISD::SETUGT: | 
|  | case ISD::SETUGE: return 2; | 
|  | } | 
|  | } | 
|  |  | 
|  | ISD::CondCode ISD::getSetCCOrOperation(ISD::CondCode Op1, ISD::CondCode Op2, | 
|  | EVT Type) { | 
|  | bool IsInteger = Type.isInteger(); | 
|  | if (IsInteger && (isSignedOp(Op1) | isSignedOp(Op2)) == 3) | 
|  | // Cannot fold a signed integer setcc with an unsigned integer setcc. | 
|  | return ISD::SETCC_INVALID; | 
|  |  | 
|  | unsigned Op = Op1 | Op2;  // Combine all of the condition bits. | 
|  |  | 
|  | // If the N and U bits get set, then the resultant comparison DOES suddenly | 
|  | // care about orderedness, and it is true when ordered. | 
|  | if (Op > ISD::SETTRUE2) | 
|  | Op &= ~16;     // Clear the U bit if the N bit is set. | 
|  |  | 
|  | // Canonicalize illegal integer setcc's. | 
|  | if (IsInteger && Op == ISD::SETUNE)  // e.g. SETUGT | SETULT | 
|  | Op = ISD::SETNE; | 
|  |  | 
|  | return ISD::CondCode(Op); | 
|  | } | 
|  |  | 
|  | ISD::CondCode ISD::getSetCCAndOperation(ISD::CondCode Op1, ISD::CondCode Op2, | 
|  | EVT Type) { | 
|  | bool IsInteger = Type.isInteger(); | 
|  | if (IsInteger && (isSignedOp(Op1) | isSignedOp(Op2)) == 3) | 
|  | // Cannot fold a signed setcc with an unsigned setcc. | 
|  | return ISD::SETCC_INVALID; | 
|  |  | 
|  | // Combine all of the condition bits. | 
|  | ISD::CondCode Result = ISD::CondCode(Op1 & Op2); | 
|  |  | 
|  | // Canonicalize illegal integer setcc's. | 
|  | if (IsInteger) { | 
|  | switch (Result) { | 
|  | default: break; | 
|  | case ISD::SETUO : Result = ISD::SETFALSE; break;  // SETUGT & SETULT | 
|  | case ISD::SETOEQ:                                 // SETEQ  & SETU[LG]E | 
|  | case ISD::SETUEQ: Result = ISD::SETEQ   ; break;  // SETUGE & SETULE | 
|  | case ISD::SETOLT: Result = ISD::SETULT  ; break;  // SETULT & SETNE | 
|  | case ISD::SETOGT: Result = ISD::SETUGT  ; break;  // SETUGT & SETNE | 
|  | } | 
|  | } | 
|  |  | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | //===----------------------------------------------------------------------===// | 
|  | //                           SDNode Profile Support | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | /// AddNodeIDOpcode - Add the node opcode to the NodeID data. | 
|  | static void AddNodeIDOpcode(FoldingSetNodeID &ID, unsigned OpC)  { | 
|  | ID.AddInteger(OpC); | 
|  | } | 
|  |  | 
|  | /// AddNodeIDValueTypes - Value type lists are intern'd so we can represent them | 
|  | /// solely with their pointer. | 
|  | static void AddNodeIDValueTypes(FoldingSetNodeID &ID, SDVTList VTList) { | 
|  | ID.AddPointer(VTList.VTs); | 
|  | } | 
|  |  | 
|  | /// AddNodeIDOperands - Various routines for adding operands to the NodeID data. | 
|  | static void AddNodeIDOperands(FoldingSetNodeID &ID, | 
|  | ArrayRef<SDValue> Ops) { | 
|  | for (const auto &Op : Ops) { | 
|  | ID.AddPointer(Op.getNode()); | 
|  | ID.AddInteger(Op.getResNo()); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// AddNodeIDOperands - Various routines for adding operands to the NodeID data. | 
|  | static void AddNodeIDOperands(FoldingSetNodeID &ID, | 
|  | ArrayRef<SDUse> Ops) { | 
|  | for (const auto &Op : Ops) { | 
|  | ID.AddPointer(Op.getNode()); | 
|  | ID.AddInteger(Op.getResNo()); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void AddNodeIDNode(FoldingSetNodeID &ID, unsigned OpC, | 
|  | SDVTList VTList, ArrayRef<SDValue> OpList) { | 
|  | AddNodeIDOpcode(ID, OpC); | 
|  | AddNodeIDValueTypes(ID, VTList); | 
|  | AddNodeIDOperands(ID, OpList); | 
|  | } | 
|  |  | 
|  | /// If this is an SDNode with special info, add this info to the NodeID data. | 
|  | static void AddNodeIDCustom(FoldingSetNodeID &ID, const SDNode *N) { | 
|  | switch (N->getOpcode()) { | 
|  | case ISD::TargetExternalSymbol: | 
|  | case ISD::ExternalSymbol: | 
|  | case ISD::MCSymbol: | 
|  | llvm_unreachable("Should only be used on nodes with operands"); | 
|  | default: break;  // Normal nodes don't need extra info. | 
|  | case ISD::TargetConstant: | 
|  | case ISD::Constant: { | 
|  | const ConstantSDNode *C = cast<ConstantSDNode>(N); | 
|  | ID.AddPointer(C->getConstantIntValue()); | 
|  | ID.AddBoolean(C->isOpaque()); | 
|  | break; | 
|  | } | 
|  | case ISD::TargetConstantFP: | 
|  | case ISD::ConstantFP: | 
|  | ID.AddPointer(cast<ConstantFPSDNode>(N)->getConstantFPValue()); | 
|  | break; | 
|  | case ISD::TargetGlobalAddress: | 
|  | case ISD::GlobalAddress: | 
|  | case ISD::TargetGlobalTLSAddress: | 
|  | case ISD::GlobalTLSAddress: { | 
|  | const GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(N); | 
|  | ID.AddPointer(GA->getGlobal()); | 
|  | ID.AddInteger(GA->getOffset()); | 
|  | ID.AddInteger(GA->getTargetFlags()); | 
|  | break; | 
|  | } | 
|  | case ISD::BasicBlock: | 
|  | ID.AddPointer(cast<BasicBlockSDNode>(N)->getBasicBlock()); | 
|  | break; | 
|  | case ISD::Register: | 
|  | ID.AddInteger(cast<RegisterSDNode>(N)->getReg().id()); | 
|  | break; | 
|  | case ISD::RegisterMask: | 
|  | ID.AddPointer(cast<RegisterMaskSDNode>(N)->getRegMask()); | 
|  | break; | 
|  | case ISD::SRCVALUE: | 
|  | ID.AddPointer(cast<SrcValueSDNode>(N)->getValue()); | 
|  | break; | 
|  | case ISD::FrameIndex: | 
|  | case ISD::TargetFrameIndex: | 
|  | ID.AddInteger(cast<FrameIndexSDNode>(N)->getIndex()); | 
|  | break; | 
|  | case ISD::PSEUDO_PROBE: | 
|  | ID.AddInteger(cast<PseudoProbeSDNode>(N)->getGuid()); | 
|  | ID.AddInteger(cast<PseudoProbeSDNode>(N)->getIndex()); | 
|  | ID.AddInteger(cast<PseudoProbeSDNode>(N)->getAttributes()); | 
|  | break; | 
|  | case ISD::JumpTable: | 
|  | case ISD::TargetJumpTable: | 
|  | ID.AddInteger(cast<JumpTableSDNode>(N)->getIndex()); | 
|  | ID.AddInteger(cast<JumpTableSDNode>(N)->getTargetFlags()); | 
|  | break; | 
|  | case ISD::ConstantPool: | 
|  | case ISD::TargetConstantPool: { | 
|  | const ConstantPoolSDNode *CP = cast<ConstantPoolSDNode>(N); | 
|  | ID.AddInteger(CP->getAlign().value()); | 
|  | ID.AddInteger(CP->getOffset()); | 
|  | if (CP->isMachineConstantPoolEntry()) | 
|  | CP->getMachineCPVal()->addSelectionDAGCSEId(ID); | 
|  | else | 
|  | ID.AddPointer(CP->getConstVal()); | 
|  | ID.AddInteger(CP->getTargetFlags()); | 
|  | break; | 
|  | } | 
|  | case ISD::TargetIndex: { | 
|  | const TargetIndexSDNode *TI = cast<TargetIndexSDNode>(N); | 
|  | ID.AddInteger(TI->getIndex()); | 
|  | ID.AddInteger(TI->getOffset()); | 
|  | ID.AddInteger(TI->getTargetFlags()); | 
|  | break; | 
|  | } | 
|  | case ISD::LOAD: { | 
|  | const LoadSDNode *LD = cast<LoadSDNode>(N); | 
|  | ID.AddInteger(LD->getMemoryVT().getRawBits()); | 
|  | ID.AddInteger(LD->getRawSubclassData()); | 
|  | ID.AddInteger(LD->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(LD->getMemOperand()->getFlags()); | 
|  | break; | 
|  | } | 
|  | case ISD::STORE: { | 
|  | const StoreSDNode *ST = cast<StoreSDNode>(N); | 
|  | ID.AddInteger(ST->getMemoryVT().getRawBits()); | 
|  | ID.AddInteger(ST->getRawSubclassData()); | 
|  | ID.AddInteger(ST->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(ST->getMemOperand()->getFlags()); | 
|  | break; | 
|  | } | 
|  | case ISD::VP_LOAD: { | 
|  | const VPLoadSDNode *ELD = cast<VPLoadSDNode>(N); | 
|  | ID.AddInteger(ELD->getMemoryVT().getRawBits()); | 
|  | ID.AddInteger(ELD->getRawSubclassData()); | 
|  | ID.AddInteger(ELD->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(ELD->getMemOperand()->getFlags()); | 
|  | break; | 
|  | } | 
|  | case ISD::VP_LOAD_FF: { | 
|  | const auto *LD = cast<VPLoadFFSDNode>(N); | 
|  | ID.AddInteger(LD->getMemoryVT().getRawBits()); | 
|  | ID.AddInteger(LD->getRawSubclassData()); | 
|  | ID.AddInteger(LD->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(LD->getMemOperand()->getFlags()); | 
|  | break; | 
|  | } | 
|  | case ISD::VP_STORE: { | 
|  | const VPStoreSDNode *EST = cast<VPStoreSDNode>(N); | 
|  | ID.AddInteger(EST->getMemoryVT().getRawBits()); | 
|  | ID.AddInteger(EST->getRawSubclassData()); | 
|  | ID.AddInteger(EST->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(EST->getMemOperand()->getFlags()); | 
|  | break; | 
|  | } | 
|  | case ISD::EXPERIMENTAL_VP_STRIDED_LOAD: { | 
|  | const VPStridedLoadSDNode *SLD = cast<VPStridedLoadSDNode>(N); | 
|  | ID.AddInteger(SLD->getMemoryVT().getRawBits()); | 
|  | ID.AddInteger(SLD->getRawSubclassData()); | 
|  | ID.AddInteger(SLD->getPointerInfo().getAddrSpace()); | 
|  | break; | 
|  | } | 
|  | case ISD::EXPERIMENTAL_VP_STRIDED_STORE: { | 
|  | const VPStridedStoreSDNode *SST = cast<VPStridedStoreSDNode>(N); | 
|  | ID.AddInteger(SST->getMemoryVT().getRawBits()); | 
|  | ID.AddInteger(SST->getRawSubclassData()); | 
|  | ID.AddInteger(SST->getPointerInfo().getAddrSpace()); | 
|  | break; | 
|  | } | 
|  | case ISD::VP_GATHER: { | 
|  | const VPGatherSDNode *EG = cast<VPGatherSDNode>(N); | 
|  | ID.AddInteger(EG->getMemoryVT().getRawBits()); | 
|  | ID.AddInteger(EG->getRawSubclassData()); | 
|  | ID.AddInteger(EG->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(EG->getMemOperand()->getFlags()); | 
|  | break; | 
|  | } | 
|  | case ISD::VP_SCATTER: { | 
|  | const VPScatterSDNode *ES = cast<VPScatterSDNode>(N); | 
|  | ID.AddInteger(ES->getMemoryVT().getRawBits()); | 
|  | ID.AddInteger(ES->getRawSubclassData()); | 
|  | ID.AddInteger(ES->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(ES->getMemOperand()->getFlags()); | 
|  | break; | 
|  | } | 
|  | case ISD::MLOAD: { | 
|  | const MaskedLoadSDNode *MLD = cast<MaskedLoadSDNode>(N); | 
|  | ID.AddInteger(MLD->getMemoryVT().getRawBits()); | 
|  | ID.AddInteger(MLD->getRawSubclassData()); | 
|  | ID.AddInteger(MLD->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(MLD->getMemOperand()->getFlags()); | 
|  | break; | 
|  | } | 
|  | case ISD::MSTORE: { | 
|  | const MaskedStoreSDNode *MST = cast<MaskedStoreSDNode>(N); | 
|  | ID.AddInteger(MST->getMemoryVT().getRawBits()); | 
|  | ID.AddInteger(MST->getRawSubclassData()); | 
|  | ID.AddInteger(MST->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(MST->getMemOperand()->getFlags()); | 
|  | break; | 
|  | } | 
|  | case ISD::MGATHER: { | 
|  | const MaskedGatherSDNode *MG = cast<MaskedGatherSDNode>(N); | 
|  | ID.AddInteger(MG->getMemoryVT().getRawBits()); | 
|  | ID.AddInteger(MG->getRawSubclassData()); | 
|  | ID.AddInteger(MG->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(MG->getMemOperand()->getFlags()); | 
|  | break; | 
|  | } | 
|  | case ISD::MSCATTER: { | 
|  | const MaskedScatterSDNode *MS = cast<MaskedScatterSDNode>(N); | 
|  | ID.AddInteger(MS->getMemoryVT().getRawBits()); | 
|  | ID.AddInteger(MS->getRawSubclassData()); | 
|  | ID.AddInteger(MS->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(MS->getMemOperand()->getFlags()); | 
|  | break; | 
|  | } | 
|  | case ISD::ATOMIC_CMP_SWAP: | 
|  | case ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS: | 
|  | case ISD::ATOMIC_SWAP: | 
|  | case ISD::ATOMIC_LOAD_ADD: | 
|  | case ISD::ATOMIC_LOAD_SUB: | 
|  | case ISD::ATOMIC_LOAD_AND: | 
|  | case ISD::ATOMIC_LOAD_CLR: | 
|  | case ISD::ATOMIC_LOAD_OR: | 
|  | case ISD::ATOMIC_LOAD_XOR: | 
|  | case ISD::ATOMIC_LOAD_NAND: | 
|  | case ISD::ATOMIC_LOAD_MIN: | 
|  | case ISD::ATOMIC_LOAD_MAX: | 
|  | case ISD::ATOMIC_LOAD_UMIN: | 
|  | case ISD::ATOMIC_LOAD_UMAX: | 
|  | case ISD::ATOMIC_LOAD: | 
|  | case ISD::ATOMIC_STORE: { | 
|  | const AtomicSDNode *AT = cast<AtomicSDNode>(N); | 
|  | ID.AddInteger(AT->getMemoryVT().getRawBits()); | 
|  | ID.AddInteger(AT->getRawSubclassData()); | 
|  | ID.AddInteger(AT->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(AT->getMemOperand()->getFlags()); | 
|  | break; | 
|  | } | 
|  | case ISD::VECTOR_SHUFFLE: { | 
|  | ArrayRef<int> Mask = cast<ShuffleVectorSDNode>(N)->getMask(); | 
|  | for (int M : Mask) | 
|  | ID.AddInteger(M); | 
|  | break; | 
|  | } | 
|  | case ISD::ADDRSPACECAST: { | 
|  | const AddrSpaceCastSDNode *ASC = cast<AddrSpaceCastSDNode>(N); | 
|  | ID.AddInteger(ASC->getSrcAddressSpace()); | 
|  | ID.AddInteger(ASC->getDestAddressSpace()); | 
|  | break; | 
|  | } | 
|  | case ISD::TargetBlockAddress: | 
|  | case ISD::BlockAddress: { | 
|  | const BlockAddressSDNode *BA = cast<BlockAddressSDNode>(N); | 
|  | ID.AddPointer(BA->getBlockAddress()); | 
|  | ID.AddInteger(BA->getOffset()); | 
|  | ID.AddInteger(BA->getTargetFlags()); | 
|  | break; | 
|  | } | 
|  | case ISD::AssertAlign: | 
|  | ID.AddInteger(cast<AssertAlignSDNode>(N)->getAlign().value()); | 
|  | break; | 
|  | case ISD::PREFETCH: | 
|  | case ISD::INTRINSIC_VOID: | 
|  | case ISD::INTRINSIC_W_CHAIN: | 
|  | // Handled by MemIntrinsicSDNode check after the switch. | 
|  | break; | 
|  | case ISD::MDNODE_SDNODE: | 
|  | ID.AddPointer(cast<MDNodeSDNode>(N)->getMD()); | 
|  | break; | 
|  | } // end switch (N->getOpcode()) | 
|  |  | 
|  | // MemIntrinsic nodes could also have subclass data, address spaces, and flags | 
|  | // to check. | 
|  | if (auto *MN = dyn_cast<MemIntrinsicSDNode>(N)) { | 
|  | ID.AddInteger(MN->getRawSubclassData()); | 
|  | ID.AddInteger(MN->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(MN->getMemOperand()->getFlags()); | 
|  | ID.AddInteger(MN->getMemoryVT().getRawBits()); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// AddNodeIDNode - Generic routine for adding a nodes info to the NodeID | 
|  | /// data. | 
|  | static void AddNodeIDNode(FoldingSetNodeID &ID, const SDNode *N) { | 
|  | AddNodeIDOpcode(ID, N->getOpcode()); | 
|  | // Add the return value info. | 
|  | AddNodeIDValueTypes(ID, N->getVTList()); | 
|  | // Add the operand info. | 
|  | AddNodeIDOperands(ID, N->ops()); | 
|  |  | 
|  | // Handle SDNode leafs with special info. | 
|  | AddNodeIDCustom(ID, N); | 
|  | } | 
|  |  | 
|  | //===----------------------------------------------------------------------===// | 
|  | //                              SelectionDAG Class | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | /// doNotCSE - Return true if CSE should not be performed for this node. | 
|  | static bool doNotCSE(SDNode *N) { | 
|  | if (N->getValueType(0) == MVT::Glue) | 
|  | return true; // Never CSE anything that produces a glue result. | 
|  |  | 
|  | switch (N->getOpcode()) { | 
|  | default: break; | 
|  | case ISD::HANDLENODE: | 
|  | case ISD::EH_LABEL: | 
|  | return true;   // Never CSE these nodes. | 
|  | } | 
|  |  | 
|  | // Check that remaining values produced are not flags. | 
|  | for (unsigned i = 1, e = N->getNumValues(); i != e; ++i) | 
|  | if (N->getValueType(i) == MVT::Glue) | 
|  | return true; // Never CSE anything that produces a glue result. | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /// RemoveDeadNodes - This method deletes all unreachable nodes in the | 
|  | /// SelectionDAG. | 
|  | void SelectionDAG::RemoveDeadNodes() { | 
|  | // Create a dummy node (which is not added to allnodes), that adds a reference | 
|  | // to the root node, preventing it from being deleted. | 
|  | HandleSDNode Dummy(getRoot()); | 
|  |  | 
|  | SmallVector<SDNode*, 128> DeadNodes; | 
|  |  | 
|  | // Add all obviously-dead nodes to the DeadNodes worklist. | 
|  | for (SDNode &Node : allnodes()) | 
|  | if (Node.use_empty()) | 
|  | DeadNodes.push_back(&Node); | 
|  |  | 
|  | RemoveDeadNodes(DeadNodes); | 
|  |  | 
|  | // If the root changed (e.g. it was a dead load, update the root). | 
|  | setRoot(Dummy.getValue()); | 
|  | } | 
|  |  | 
|  | /// RemoveDeadNodes - This method deletes the unreachable nodes in the | 
|  | /// given list, and any nodes that become unreachable as a result. | 
|  | void SelectionDAG::RemoveDeadNodes(SmallVectorImpl<SDNode *> &DeadNodes) { | 
|  |  | 
|  | // Process the worklist, deleting the nodes and adding their uses to the | 
|  | // worklist. | 
|  | while (!DeadNodes.empty()) { | 
|  | SDNode *N = DeadNodes.pop_back_val(); | 
|  | // Skip to next node if we've already managed to delete the node. This could | 
|  | // happen if replacing a node causes a node previously added to the node to | 
|  | // be deleted. | 
|  | if (N->getOpcode() == ISD::DELETED_NODE) | 
|  | continue; | 
|  |  | 
|  | for (DAGUpdateListener *DUL = UpdateListeners; DUL; DUL = DUL->Next) | 
|  | DUL->NodeDeleted(N, nullptr); | 
|  |  | 
|  | // Take the node out of the appropriate CSE map. | 
|  | RemoveNodeFromCSEMaps(N); | 
|  |  | 
|  | // Next, brutally remove the operand list.  This is safe to do, as there are | 
|  | // no cycles in the graph. | 
|  | for (SDNode::op_iterator I = N->op_begin(), E = N->op_end(); I != E; ) { | 
|  | SDUse &Use = *I++; | 
|  | SDNode *Operand = Use.getNode(); | 
|  | Use.set(SDValue()); | 
|  |  | 
|  | // Now that we removed this operand, see if there are no uses of it left. | 
|  | if (Operand->use_empty()) | 
|  | DeadNodes.push_back(Operand); | 
|  | } | 
|  |  | 
|  | DeallocateNode(N); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SelectionDAG::RemoveDeadNode(SDNode *N){ | 
|  | SmallVector<SDNode*, 16> DeadNodes(1, N); | 
|  |  | 
|  | // Create a dummy node that adds a reference to the root node, preventing | 
|  | // it from being deleted.  (This matters if the root is an operand of the | 
|  | // dead node.) | 
|  | HandleSDNode Dummy(getRoot()); | 
|  |  | 
|  | RemoveDeadNodes(DeadNodes); | 
|  | } | 
|  |  | 
|  | void SelectionDAG::DeleteNode(SDNode *N) { | 
|  | // First take this out of the appropriate CSE map. | 
|  | RemoveNodeFromCSEMaps(N); | 
|  |  | 
|  | // Finally, remove uses due to operands of this node, remove from the | 
|  | // AllNodes list, and delete the node. | 
|  | DeleteNodeNotInCSEMaps(N); | 
|  | } | 
|  |  | 
|  | void SelectionDAG::DeleteNodeNotInCSEMaps(SDNode *N) { | 
|  | assert(N->getIterator() != AllNodes.begin() && | 
|  | "Cannot delete the entry node!"); | 
|  | assert(N->use_empty() && "Cannot delete a node that is not dead!"); | 
|  |  | 
|  | // Drop all of the operands and decrement used node's use counts. | 
|  | N->DropOperands(); | 
|  |  | 
|  | DeallocateNode(N); | 
|  | } | 
|  |  | 
|  | void SDDbgInfo::add(SDDbgValue *V, bool isParameter) { | 
|  | assert(!(V->isVariadic() && isParameter)); | 
|  | if (isParameter) | 
|  | ByvalParmDbgValues.push_back(V); | 
|  | else | 
|  | DbgValues.push_back(V); | 
|  | for (const SDNode *Node : V->getSDNodes()) | 
|  | if (Node) | 
|  | DbgValMap[Node].push_back(V); | 
|  | } | 
|  |  | 
|  | void SDDbgInfo::erase(const SDNode *Node) { | 
|  | DbgValMapType::iterator I = DbgValMap.find(Node); | 
|  | if (I == DbgValMap.end()) | 
|  | return; | 
|  | for (auto &Val: I->second) | 
|  | Val->setIsInvalidated(); | 
|  | DbgValMap.erase(I); | 
|  | } | 
|  |  | 
|  | void SelectionDAG::DeallocateNode(SDNode *N) { | 
|  | // If we have operands, deallocate them. | 
|  | removeOperands(N); | 
|  |  | 
|  | NodeAllocator.Deallocate(AllNodes.remove(N)); | 
|  |  | 
|  | // Set the opcode to DELETED_NODE to help catch bugs when node | 
|  | // memory is reallocated. | 
|  | // FIXME: There are places in SDag that have grown a dependency on the opcode | 
|  | // value in the released node. | 
|  | __asan_unpoison_memory_region(&N->NodeType, sizeof(N->NodeType)); | 
|  | N->NodeType = ISD::DELETED_NODE; | 
|  |  | 
|  | // If any of the SDDbgValue nodes refer to this SDNode, invalidate | 
|  | // them and forget about that node. | 
|  | DbgInfo->erase(N); | 
|  |  | 
|  | // Invalidate extra info. | 
|  | SDEI.erase(N); | 
|  | } | 
|  |  | 
|  | #ifndef NDEBUG | 
|  | /// VerifySDNode - Check the given SDNode.  Aborts if it is invalid. | 
|  | void SelectionDAG::verifyNode(SDNode *N) const { | 
|  | switch (N->getOpcode()) { | 
|  | default: | 
|  | if (N->isTargetOpcode()) | 
|  | getSelectionDAGInfo().verifyTargetNode(*this, N); | 
|  | break; | 
|  | case ISD::BUILD_PAIR: { | 
|  | EVT VT = N->getValueType(0); | 
|  | assert(N->getNumValues() == 1 && "Too many results!"); | 
|  | assert(!VT.isVector() && (VT.isInteger() || VT.isFloatingPoint()) && | 
|  | "Wrong return type!"); | 
|  | assert(N->getNumOperands() == 2 && "Wrong number of operands!"); | 
|  | assert(N->getOperand(0).getValueType() == N->getOperand(1).getValueType() && | 
|  | "Mismatched operand types!"); | 
|  | assert(N->getOperand(0).getValueType().isInteger() == VT.isInteger() && | 
|  | "Wrong operand type!"); | 
|  | assert(VT.getSizeInBits() == 2 * N->getOperand(0).getValueSizeInBits() && | 
|  | "Wrong return type size"); | 
|  | break; | 
|  | } | 
|  | case ISD::BUILD_VECTOR: { | 
|  | assert(N->getNumValues() == 1 && "Too many results!"); | 
|  | assert(N->getValueType(0).isVector() && "Wrong return type!"); | 
|  | assert(N->getNumOperands() == N->getValueType(0).getVectorNumElements() && | 
|  | "Wrong number of operands!"); | 
|  | EVT EltVT = N->getValueType(0).getVectorElementType(); | 
|  | for (const SDUse &Op : N->ops()) { | 
|  | assert((Op.getValueType() == EltVT || | 
|  | (EltVT.isInteger() && Op.getValueType().isInteger() && | 
|  | EltVT.bitsLE(Op.getValueType()))) && | 
|  | "Wrong operand type!"); | 
|  | assert(Op.getValueType() == N->getOperand(0).getValueType() && | 
|  | "Operands must all have the same type"); | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | #endif // NDEBUG | 
|  |  | 
|  | /// Insert a newly allocated node into the DAG. | 
|  | /// | 
|  | /// Handles insertion into the all nodes list and CSE map, as well as | 
|  | /// verification and other common operations when a new node is allocated. | 
|  | void SelectionDAG::InsertNode(SDNode *N) { | 
|  | AllNodes.push_back(N); | 
|  | #ifndef NDEBUG | 
|  | N->PersistentId = NextPersistentId++; | 
|  | verifyNode(N); | 
|  | #endif | 
|  | for (DAGUpdateListener *DUL = UpdateListeners; DUL; DUL = DUL->Next) | 
|  | DUL->NodeInserted(N); | 
|  | } | 
|  |  | 
|  | /// RemoveNodeFromCSEMaps - Take the specified node out of the CSE map that | 
|  | /// correspond to it.  This is useful when we're about to delete or repurpose | 
|  | /// the node.  We don't want future request for structurally identical nodes | 
|  | /// to return N anymore. | 
|  | bool SelectionDAG::RemoveNodeFromCSEMaps(SDNode *N) { | 
|  | bool Erased = false; | 
|  | switch (N->getOpcode()) { | 
|  | case ISD::HANDLENODE: return false;  // noop. | 
|  | case ISD::CONDCODE: | 
|  | assert(CondCodeNodes[cast<CondCodeSDNode>(N)->get()] && | 
|  | "Cond code doesn't exist!"); | 
|  | Erased = CondCodeNodes[cast<CondCodeSDNode>(N)->get()] != nullptr; | 
|  | CondCodeNodes[cast<CondCodeSDNode>(N)->get()] = nullptr; | 
|  | break; | 
|  | case ISD::ExternalSymbol: | 
|  | Erased = ExternalSymbols.erase(cast<ExternalSymbolSDNode>(N)->getSymbol()); | 
|  | break; | 
|  | case ISD::TargetExternalSymbol: { | 
|  | ExternalSymbolSDNode *ESN = cast<ExternalSymbolSDNode>(N); | 
|  | Erased = TargetExternalSymbols.erase(std::pair<std::string, unsigned>( | 
|  | ESN->getSymbol(), ESN->getTargetFlags())); | 
|  | break; | 
|  | } | 
|  | case ISD::MCSymbol: { | 
|  | auto *MCSN = cast<MCSymbolSDNode>(N); | 
|  | Erased = MCSymbols.erase(MCSN->getMCSymbol()); | 
|  | break; | 
|  | } | 
|  | case ISD::VALUETYPE: { | 
|  | EVT VT = cast<VTSDNode>(N)->getVT(); | 
|  | if (VT.isExtended()) { | 
|  | Erased = ExtendedValueTypeNodes.erase(VT); | 
|  | } else { | 
|  | Erased = ValueTypeNodes[VT.getSimpleVT().SimpleTy] != nullptr; | 
|  | ValueTypeNodes[VT.getSimpleVT().SimpleTy] = nullptr; | 
|  | } | 
|  | break; | 
|  | } | 
|  | default: | 
|  | // Remove it from the CSE Map. | 
|  | assert(N->getOpcode() != ISD::DELETED_NODE && "DELETED_NODE in CSEMap!"); | 
|  | assert(N->getOpcode() != ISD::EntryToken && "EntryToken in CSEMap!"); | 
|  | Erased = CSEMap.RemoveNode(N); | 
|  | break; | 
|  | } | 
|  | #ifndef NDEBUG | 
|  | // Verify that the node was actually in one of the CSE maps, unless it has a | 
|  | // glue result (which cannot be CSE'd) or is one of the special cases that are | 
|  | // not subject to CSE. | 
|  | if (!Erased && N->getValueType(N->getNumValues()-1) != MVT::Glue && | 
|  | !N->isMachineOpcode() && !doNotCSE(N)) { | 
|  | N->dump(this); | 
|  | dbgs() << "\n"; | 
|  | llvm_unreachable("Node is not in map!"); | 
|  | } | 
|  | #endif | 
|  | return Erased; | 
|  | } | 
|  |  | 
|  | /// AddModifiedNodeToCSEMaps - The specified node has been removed from the CSE | 
|  | /// maps and modified in place. Add it back to the CSE maps, unless an identical | 
|  | /// node already exists, in which case transfer all its users to the existing | 
|  | /// node. This transfer can potentially trigger recursive merging. | 
|  | void | 
|  | SelectionDAG::AddModifiedNodeToCSEMaps(SDNode *N) { | 
|  | // For node types that aren't CSE'd, just act as if no identical node | 
|  | // already exists. | 
|  | if (!doNotCSE(N)) { | 
|  | SDNode *Existing = CSEMap.GetOrInsertNode(N); | 
|  | if (Existing != N) { | 
|  | // If there was already an existing matching node, use ReplaceAllUsesWith | 
|  | // to replace the dead one with the existing one.  This can cause | 
|  | // recursive merging of other unrelated nodes down the line. | 
|  | Existing->intersectFlagsWith(N->getFlags()); | 
|  | if (auto *MemNode = dyn_cast<MemSDNode>(Existing)) | 
|  | MemNode->refineRanges(cast<MemSDNode>(N)->getMemOperand()); | 
|  | ReplaceAllUsesWith(N, Existing); | 
|  |  | 
|  | // N is now dead. Inform the listeners and delete it. | 
|  | for (DAGUpdateListener *DUL = UpdateListeners; DUL; DUL = DUL->Next) | 
|  | DUL->NodeDeleted(N, Existing); | 
|  | DeleteNodeNotInCSEMaps(N); | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | // If the node doesn't already exist, we updated it.  Inform listeners. | 
|  | for (DAGUpdateListener *DUL = UpdateListeners; DUL; DUL = DUL->Next) | 
|  | DUL->NodeUpdated(N); | 
|  | } | 
|  |  | 
|  | /// FindModifiedNodeSlot - Find a slot for the specified node if its operands | 
|  | /// were replaced with those specified.  If this node is never memoized, | 
|  | /// return null, otherwise return a pointer to the slot it would take.  If a | 
|  | /// node already exists with these operands, the slot will be non-null. | 
|  | SDNode *SelectionDAG::FindModifiedNodeSlot(SDNode *N, SDValue Op, | 
|  | void *&InsertPos) { | 
|  | if (doNotCSE(N)) | 
|  | return nullptr; | 
|  |  | 
|  | SDValue Ops[] = { Op }; | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, N->getOpcode(), N->getVTList(), Ops); | 
|  | AddNodeIDCustom(ID, N); | 
|  | SDNode *Node = FindNodeOrInsertPos(ID, SDLoc(N), InsertPos); | 
|  | if (Node) | 
|  | Node->intersectFlagsWith(N->getFlags()); | 
|  | return Node; | 
|  | } | 
|  |  | 
|  | /// FindModifiedNodeSlot - Find a slot for the specified node if its operands | 
|  | /// were replaced with those specified.  If this node is never memoized, | 
|  | /// return null, otherwise return a pointer to the slot it would take.  If a | 
|  | /// node already exists with these operands, the slot will be non-null. | 
|  | SDNode *SelectionDAG::FindModifiedNodeSlot(SDNode *N, | 
|  | SDValue Op1, SDValue Op2, | 
|  | void *&InsertPos) { | 
|  | if (doNotCSE(N)) | 
|  | return nullptr; | 
|  |  | 
|  | SDValue Ops[] = { Op1, Op2 }; | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, N->getOpcode(), N->getVTList(), Ops); | 
|  | AddNodeIDCustom(ID, N); | 
|  | SDNode *Node = FindNodeOrInsertPos(ID, SDLoc(N), InsertPos); | 
|  | if (Node) | 
|  | Node->intersectFlagsWith(N->getFlags()); | 
|  | return Node; | 
|  | } | 
|  |  | 
|  | /// FindModifiedNodeSlot - Find a slot for the specified node if its operands | 
|  | /// were replaced with those specified.  If this node is never memoized, | 
|  | /// return null, otherwise return a pointer to the slot it would take.  If a | 
|  | /// node already exists with these operands, the slot will be non-null. | 
|  | SDNode *SelectionDAG::FindModifiedNodeSlot(SDNode *N, ArrayRef<SDValue> Ops, | 
|  | void *&InsertPos) { | 
|  | if (doNotCSE(N)) | 
|  | return nullptr; | 
|  |  | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, N->getOpcode(), N->getVTList(), Ops); | 
|  | AddNodeIDCustom(ID, N); | 
|  | SDNode *Node = FindNodeOrInsertPos(ID, SDLoc(N), InsertPos); | 
|  | if (Node) | 
|  | Node->intersectFlagsWith(N->getFlags()); | 
|  | return Node; | 
|  | } | 
|  |  | 
|  | Align SelectionDAG::getEVTAlign(EVT VT) const { | 
|  | Type *Ty = VT == MVT::iPTR ? PointerType::get(*getContext(), 0) | 
|  | : VT.getTypeForEVT(*getContext()); | 
|  |  | 
|  | return getDataLayout().getABITypeAlign(Ty); | 
|  | } | 
|  |  | 
|  | // EntryNode could meaningfully have debug info if we can find it... | 
|  | SelectionDAG::SelectionDAG(const TargetMachine &tm, CodeGenOptLevel OL) | 
|  | : TM(tm), OptLevel(OL), EntryNode(ISD::EntryToken, 0, DebugLoc(), | 
|  | getVTList(MVT::Other, MVT::Glue)), | 
|  | Root(getEntryNode()) { | 
|  | InsertNode(&EntryNode); | 
|  | DbgInfo = new SDDbgInfo(); | 
|  | } | 
|  |  | 
|  | void SelectionDAG::init(MachineFunction &NewMF, | 
|  | OptimizationRemarkEmitter &NewORE, Pass *PassPtr, | 
|  | const TargetLibraryInfo *LibraryInfo, | 
|  | UniformityInfo *NewUA, ProfileSummaryInfo *PSIin, | 
|  | BlockFrequencyInfo *BFIin, MachineModuleInfo &MMIin, | 
|  | FunctionVarLocs const *VarLocs) { | 
|  | MF = &NewMF; | 
|  | SDAGISelPass = PassPtr; | 
|  | ORE = &NewORE; | 
|  | TLI = getSubtarget().getTargetLowering(); | 
|  | TSI = getSubtarget().getSelectionDAGInfo(); | 
|  | LibInfo = LibraryInfo; | 
|  | Context = &MF->getFunction().getContext(); | 
|  | UA = NewUA; | 
|  | PSI = PSIin; | 
|  | BFI = BFIin; | 
|  | MMI = &MMIin; | 
|  | FnVarLocs = VarLocs; | 
|  | } | 
|  |  | 
|  | SelectionDAG::~SelectionDAG() { | 
|  | assert(!UpdateListeners && "Dangling registered DAGUpdateListeners"); | 
|  | allnodes_clear(); | 
|  | OperandRecycler.clear(OperandAllocator); | 
|  | delete DbgInfo; | 
|  | } | 
|  |  | 
|  | bool SelectionDAG::shouldOptForSize() const { | 
|  | return llvm::shouldOptimizeForSize(FLI->MBB->getBasicBlock(), PSI, BFI); | 
|  | } | 
|  |  | 
|  | void SelectionDAG::allnodes_clear() { | 
|  | assert(&*AllNodes.begin() == &EntryNode); | 
|  | AllNodes.remove(AllNodes.begin()); | 
|  | while (!AllNodes.empty()) | 
|  | DeallocateNode(&AllNodes.front()); | 
|  | #ifndef NDEBUG | 
|  | NextPersistentId = 0; | 
|  | #endif | 
|  | } | 
|  |  | 
|  | SDNode *SelectionDAG::FindNodeOrInsertPos(const FoldingSetNodeID &ID, | 
|  | void *&InsertPos) { | 
|  | SDNode *N = CSEMap.FindNodeOrInsertPos(ID, InsertPos); | 
|  | if (N) { | 
|  | switch (N->getOpcode()) { | 
|  | default: break; | 
|  | case ISD::Constant: | 
|  | case ISD::ConstantFP: | 
|  | llvm_unreachable("Querying for Constant and ConstantFP nodes requires " | 
|  | "debug location.  Use another overload."); | 
|  | } | 
|  | } | 
|  | return N; | 
|  | } | 
|  |  | 
|  | SDNode *SelectionDAG::FindNodeOrInsertPos(const FoldingSetNodeID &ID, | 
|  | const SDLoc &DL, void *&InsertPos) { | 
|  | SDNode *N = CSEMap.FindNodeOrInsertPos(ID, InsertPos); | 
|  | if (N) { | 
|  | switch (N->getOpcode()) { | 
|  | case ISD::Constant: | 
|  | case ISD::ConstantFP: | 
|  | // Erase debug location from the node if the node is used at several | 
|  | // different places. Do not propagate one location to all uses as it | 
|  | // will cause a worse single stepping debugging experience. | 
|  | if (N->getDebugLoc() != DL.getDebugLoc()) | 
|  | N->setDebugLoc(DebugLoc()); | 
|  | break; | 
|  | default: | 
|  | // When the node's point of use is located earlier in the instruction | 
|  | // sequence than its prior point of use, update its debug info to the | 
|  | // earlier location. | 
|  | if (DL.getIROrder() && DL.getIROrder() < N->getIROrder()) | 
|  | N->setDebugLoc(DL.getDebugLoc()); | 
|  | break; | 
|  | } | 
|  | } | 
|  | return N; | 
|  | } | 
|  |  | 
|  | void SelectionDAG::clear() { | 
|  | allnodes_clear(); | 
|  | OperandRecycler.clear(OperandAllocator); | 
|  | OperandAllocator.Reset(); | 
|  | CSEMap.clear(); | 
|  |  | 
|  | ExtendedValueTypeNodes.clear(); | 
|  | ExternalSymbols.clear(); | 
|  | TargetExternalSymbols.clear(); | 
|  | MCSymbols.clear(); | 
|  | SDEI.clear(); | 
|  | llvm::fill(CondCodeNodes, nullptr); | 
|  | llvm::fill(ValueTypeNodes, nullptr); | 
|  |  | 
|  | EntryNode.UseList = nullptr; | 
|  | InsertNode(&EntryNode); | 
|  | Root = getEntryNode(); | 
|  | DbgInfo->clear(); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getFPExtendOrRound(SDValue Op, const SDLoc &DL, EVT VT) { | 
|  | return VT.bitsGT(Op.getValueType()) | 
|  | ? getNode(ISD::FP_EXTEND, DL, VT, Op) | 
|  | : getNode(ISD::FP_ROUND, DL, VT, Op, | 
|  | getIntPtrConstant(0, DL, /*isTarget=*/true)); | 
|  | } | 
|  |  | 
|  | std::pair<SDValue, SDValue> | 
|  | SelectionDAG::getStrictFPExtendOrRound(SDValue Op, SDValue Chain, | 
|  | const SDLoc &DL, EVT VT) { | 
|  | assert(!VT.bitsEq(Op.getValueType()) && | 
|  | "Strict no-op FP extend/round not allowed."); | 
|  | SDValue Res = | 
|  | VT.bitsGT(Op.getValueType()) | 
|  | ? getNode(ISD::STRICT_FP_EXTEND, DL, {VT, MVT::Other}, {Chain, Op}) | 
|  | : getNode(ISD::STRICT_FP_ROUND, DL, {VT, MVT::Other}, | 
|  | {Chain, Op, getIntPtrConstant(0, DL, /*isTarget=*/true)}); | 
|  |  | 
|  | return std::pair<SDValue, SDValue>(Res, SDValue(Res.getNode(), 1)); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getAnyExtOrTrunc(SDValue Op, const SDLoc &DL, EVT VT) { | 
|  | return VT.bitsGT(Op.getValueType()) ? | 
|  | getNode(ISD::ANY_EXTEND, DL, VT, Op) : | 
|  | getNode(ISD::TRUNCATE, DL, VT, Op); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getSExtOrTrunc(SDValue Op, const SDLoc &DL, EVT VT) { | 
|  | return VT.bitsGT(Op.getValueType()) ? | 
|  | getNode(ISD::SIGN_EXTEND, DL, VT, Op) : | 
|  | getNode(ISD::TRUNCATE, DL, VT, Op); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getZExtOrTrunc(SDValue Op, const SDLoc &DL, EVT VT) { | 
|  | return VT.bitsGT(Op.getValueType()) ? | 
|  | getNode(ISD::ZERO_EXTEND, DL, VT, Op) : | 
|  | getNode(ISD::TRUNCATE, DL, VT, Op); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getBitcastedAnyExtOrTrunc(SDValue Op, const SDLoc &DL, | 
|  | EVT VT) { | 
|  | assert(!VT.isVector()); | 
|  | auto Type = Op.getValueType(); | 
|  | SDValue DestOp; | 
|  | if (Type == VT) | 
|  | return Op; | 
|  | auto Size = Op.getValueSizeInBits(); | 
|  | DestOp = getBitcast(EVT::getIntegerVT(*Context, Size), Op); | 
|  | if (DestOp.getValueType() == VT) | 
|  | return DestOp; | 
|  |  | 
|  | return getAnyExtOrTrunc(DestOp, DL, VT); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getBitcastedSExtOrTrunc(SDValue Op, const SDLoc &DL, | 
|  | EVT VT) { | 
|  | assert(!VT.isVector()); | 
|  | auto Type = Op.getValueType(); | 
|  | SDValue DestOp; | 
|  | if (Type == VT) | 
|  | return Op; | 
|  | auto Size = Op.getValueSizeInBits(); | 
|  | DestOp = getBitcast(MVT::getIntegerVT(Size), Op); | 
|  | if (DestOp.getValueType() == VT) | 
|  | return DestOp; | 
|  |  | 
|  | return getSExtOrTrunc(DestOp, DL, VT); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getBitcastedZExtOrTrunc(SDValue Op, const SDLoc &DL, | 
|  | EVT VT) { | 
|  | assert(!VT.isVector()); | 
|  | auto Type = Op.getValueType(); | 
|  | SDValue DestOp; | 
|  | if (Type == VT) | 
|  | return Op; | 
|  | auto Size = Op.getValueSizeInBits(); | 
|  | DestOp = getBitcast(MVT::getIntegerVT(Size), Op); | 
|  | if (DestOp.getValueType() == VT) | 
|  | return DestOp; | 
|  |  | 
|  | return getZExtOrTrunc(DestOp, DL, VT); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getBoolExtOrTrunc(SDValue Op, const SDLoc &SL, EVT VT, | 
|  | EVT OpVT) { | 
|  | if (VT.bitsLE(Op.getValueType())) | 
|  | return getNode(ISD::TRUNCATE, SL, VT, Op); | 
|  |  | 
|  | TargetLowering::BooleanContent BType = TLI->getBooleanContents(OpVT); | 
|  | return getNode(TLI->getExtendForContent(BType), SL, VT, Op); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getZeroExtendInReg(SDValue Op, const SDLoc &DL, EVT VT) { | 
|  | EVT OpVT = Op.getValueType(); | 
|  | assert(VT.isInteger() && OpVT.isInteger() && | 
|  | "Cannot getZeroExtendInReg FP types"); | 
|  | assert(VT.isVector() == OpVT.isVector() && | 
|  | "getZeroExtendInReg type should be vector iff the operand " | 
|  | "type is vector!"); | 
|  | assert((!VT.isVector() || | 
|  | VT.getVectorElementCount() == OpVT.getVectorElementCount()) && | 
|  | "Vector element counts must match in getZeroExtendInReg"); | 
|  | assert(VT.bitsLE(OpVT) && "Not extending!"); | 
|  | if (OpVT == VT) | 
|  | return Op; | 
|  | APInt Imm = APInt::getLowBitsSet(OpVT.getScalarSizeInBits(), | 
|  | VT.getScalarSizeInBits()); | 
|  | return getNode(ISD::AND, DL, OpVT, Op, getConstant(Imm, DL, OpVT)); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getVPZeroExtendInReg(SDValue Op, SDValue Mask, | 
|  | SDValue EVL, const SDLoc &DL, | 
|  | EVT VT) { | 
|  | EVT OpVT = Op.getValueType(); | 
|  | assert(VT.isInteger() && OpVT.isInteger() && | 
|  | "Cannot getVPZeroExtendInReg FP types"); | 
|  | assert(VT.isVector() && OpVT.isVector() && | 
|  | "getVPZeroExtendInReg type and operand type should be vector!"); | 
|  | assert(VT.getVectorElementCount() == OpVT.getVectorElementCount() && | 
|  | "Vector element counts must match in getZeroExtendInReg"); | 
|  | assert(VT.bitsLE(OpVT) && "Not extending!"); | 
|  | if (OpVT == VT) | 
|  | return Op; | 
|  | APInt Imm = APInt::getLowBitsSet(OpVT.getScalarSizeInBits(), | 
|  | VT.getScalarSizeInBits()); | 
|  | return getNode(ISD::VP_AND, DL, OpVT, Op, getConstant(Imm, DL, OpVT), Mask, | 
|  | EVL); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getPtrExtOrTrunc(SDValue Op, const SDLoc &DL, EVT VT) { | 
|  | // Only unsigned pointer semantics are supported right now. In the future this | 
|  | // might delegate to TLI to check pointer signedness. | 
|  | return getZExtOrTrunc(Op, DL, VT); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getPtrExtendInReg(SDValue Op, const SDLoc &DL, EVT VT) { | 
|  | // Only unsigned pointer semantics are supported right now. In the future this | 
|  | // might delegate to TLI to check pointer signedness. | 
|  | return getZeroExtendInReg(Op, DL, VT); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getNegative(SDValue Val, const SDLoc &DL, EVT VT) { | 
|  | return getNode(ISD::SUB, DL, VT, getConstant(0, DL, VT), Val); | 
|  | } | 
|  |  | 
|  | /// getNOT - Create a bitwise NOT operation as (XOR Val, -1). | 
|  | SDValue SelectionDAG::getNOT(const SDLoc &DL, SDValue Val, EVT VT) { | 
|  | return getNode(ISD::XOR, DL, VT, Val, getAllOnesConstant(DL, VT)); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getLogicalNOT(const SDLoc &DL, SDValue Val, EVT VT) { | 
|  | SDValue TrueValue = getBoolConstant(true, DL, VT, VT); | 
|  | return getNode(ISD::XOR, DL, VT, Val, TrueValue); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getVPLogicalNOT(const SDLoc &DL, SDValue Val, | 
|  | SDValue Mask, SDValue EVL, EVT VT) { | 
|  | SDValue TrueValue = getBoolConstant(true, DL, VT, VT); | 
|  | return getNode(ISD::VP_XOR, DL, VT, Val, TrueValue, Mask, EVL); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getVPPtrExtOrTrunc(const SDLoc &DL, EVT VT, SDValue Op, | 
|  | SDValue Mask, SDValue EVL) { | 
|  | return getVPZExtOrTrunc(DL, VT, Op, Mask, EVL); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getVPZExtOrTrunc(const SDLoc &DL, EVT VT, SDValue Op, | 
|  | SDValue Mask, SDValue EVL) { | 
|  | if (VT.bitsGT(Op.getValueType())) | 
|  | return getNode(ISD::VP_ZERO_EXTEND, DL, VT, Op, Mask, EVL); | 
|  | if (VT.bitsLT(Op.getValueType())) | 
|  | return getNode(ISD::VP_TRUNCATE, DL, VT, Op, Mask, EVL); | 
|  | return Op; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getBoolConstant(bool V, const SDLoc &DL, EVT VT, | 
|  | EVT OpVT) { | 
|  | if (!V) | 
|  | return getConstant(0, DL, VT); | 
|  |  | 
|  | switch (TLI->getBooleanContents(OpVT)) { | 
|  | case TargetLowering::ZeroOrOneBooleanContent: | 
|  | case TargetLowering::UndefinedBooleanContent: | 
|  | return getConstant(1, DL, VT); | 
|  | case TargetLowering::ZeroOrNegativeOneBooleanContent: | 
|  | return getAllOnesConstant(DL, VT); | 
|  | } | 
|  | llvm_unreachable("Unexpected boolean content enum!"); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getConstant(uint64_t Val, const SDLoc &DL, EVT VT, | 
|  | bool isT, bool isO) { | 
|  | return getConstant(APInt(VT.getScalarSizeInBits(), Val, /*isSigned=*/false), | 
|  | DL, VT, isT, isO); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getConstant(const APInt &Val, const SDLoc &DL, EVT VT, | 
|  | bool isT, bool isO) { | 
|  | return getConstant(*ConstantInt::get(*Context, Val), DL, VT, isT, isO); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getConstant(const ConstantInt &Val, const SDLoc &DL, | 
|  | EVT VT, bool isT, bool isO) { | 
|  | assert(VT.isInteger() && "Cannot create FP integer constant!"); | 
|  |  | 
|  | EVT EltVT = VT.getScalarType(); | 
|  | const ConstantInt *Elt = &Val; | 
|  |  | 
|  | // Vector splats are explicit within the DAG, with ConstantSDNode holding the | 
|  | // to-be-splatted scalar ConstantInt. | 
|  | if (isa<VectorType>(Elt->getType())) | 
|  | Elt = ConstantInt::get(*getContext(), Elt->getValue()); | 
|  |  | 
|  | // In some cases the vector type is legal but the element type is illegal and | 
|  | // needs to be promoted, for example v8i8 on ARM.  In this case, promote the | 
|  | // inserted value (the type does not need to match the vector element type). | 
|  | // Any extra bits introduced will be truncated away. | 
|  | if (VT.isVector() && TLI->getTypeAction(*getContext(), EltVT) == | 
|  | TargetLowering::TypePromoteInteger) { | 
|  | EltVT = TLI->getTypeToTransformTo(*getContext(), EltVT); | 
|  | APInt NewVal; | 
|  | if (TLI->isSExtCheaperThanZExt(VT.getScalarType(), EltVT)) | 
|  | NewVal = Elt->getValue().sextOrTrunc(EltVT.getSizeInBits()); | 
|  | else | 
|  | NewVal = Elt->getValue().zextOrTrunc(EltVT.getSizeInBits()); | 
|  | Elt = ConstantInt::get(*getContext(), NewVal); | 
|  | } | 
|  | // In other cases the element type is illegal and needs to be expanded, for | 
|  | // example v2i64 on MIPS32. In this case, find the nearest legal type, split | 
|  | // the value into n parts and use a vector type with n-times the elements. | 
|  | // Then bitcast to the type requested. | 
|  | // Legalizing constants too early makes the DAGCombiner's job harder so we | 
|  | // only legalize if the DAG tells us we must produce legal types. | 
|  | else if (NewNodesMustHaveLegalTypes && VT.isVector() && | 
|  | TLI->getTypeAction(*getContext(), EltVT) == | 
|  | TargetLowering::TypeExpandInteger) { | 
|  | const APInt &NewVal = Elt->getValue(); | 
|  | EVT ViaEltVT = TLI->getTypeToTransformTo(*getContext(), EltVT); | 
|  | unsigned ViaEltSizeInBits = ViaEltVT.getSizeInBits(); | 
|  |  | 
|  | // For scalable vectors, try to use a SPLAT_VECTOR_PARTS node. | 
|  | if (VT.isScalableVector() || | 
|  | TLI->isOperationLegal(ISD::SPLAT_VECTOR, VT)) { | 
|  | assert(EltVT.getSizeInBits() % ViaEltSizeInBits == 0 && | 
|  | "Can only handle an even split!"); | 
|  | unsigned Parts = EltVT.getSizeInBits() / ViaEltSizeInBits; | 
|  |  | 
|  | SmallVector<SDValue, 2> ScalarParts; | 
|  | for (unsigned i = 0; i != Parts; ++i) | 
|  | ScalarParts.push_back(getConstant( | 
|  | NewVal.extractBits(ViaEltSizeInBits, i * ViaEltSizeInBits), DL, | 
|  | ViaEltVT, isT, isO)); | 
|  |  | 
|  | return getNode(ISD::SPLAT_VECTOR_PARTS, DL, VT, ScalarParts); | 
|  | } | 
|  |  | 
|  | unsigned ViaVecNumElts = VT.getSizeInBits() / ViaEltSizeInBits; | 
|  | EVT ViaVecVT = EVT::getVectorVT(*getContext(), ViaEltVT, ViaVecNumElts); | 
|  |  | 
|  | // Check the temporary vector is the correct size. If this fails then | 
|  | // getTypeToTransformTo() probably returned a type whose size (in bits) | 
|  | // isn't a power-of-2 factor of the requested type size. | 
|  | assert(ViaVecVT.getSizeInBits() == VT.getSizeInBits()); | 
|  |  | 
|  | SmallVector<SDValue, 2> EltParts; | 
|  | for (unsigned i = 0; i < ViaVecNumElts / VT.getVectorNumElements(); ++i) | 
|  | EltParts.push_back(getConstant( | 
|  | NewVal.extractBits(ViaEltSizeInBits, i * ViaEltSizeInBits), DL, | 
|  | ViaEltVT, isT, isO)); | 
|  |  | 
|  | // EltParts is currently in little endian order. If we actually want | 
|  | // big-endian order then reverse it now. | 
|  | if (getDataLayout().isBigEndian()) | 
|  | std::reverse(EltParts.begin(), EltParts.end()); | 
|  |  | 
|  | // The elements must be reversed when the element order is different | 
|  | // to the endianness of the elements (because the BITCAST is itself a | 
|  | // vector shuffle in this situation). However, we do not need any code to | 
|  | // perform this reversal because getConstant() is producing a vector | 
|  | // splat. | 
|  | // This situation occurs in MIPS MSA. | 
|  |  | 
|  | SmallVector<SDValue, 8> Ops; | 
|  | for (unsigned i = 0, e = VT.getVectorNumElements(); i != e; ++i) | 
|  | llvm::append_range(Ops, EltParts); | 
|  |  | 
|  | SDValue V = | 
|  | getNode(ISD::BITCAST, DL, VT, getBuildVector(ViaVecVT, DL, Ops)); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | assert(Elt->getBitWidth() == EltVT.getSizeInBits() && | 
|  | "APInt size does not match type size!"); | 
|  | unsigned Opc = isT ? ISD::TargetConstant : ISD::Constant; | 
|  | SDVTList VTs = getVTList(EltVT); | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, Opc, VTs, {}); | 
|  | ID.AddPointer(Elt); | 
|  | ID.AddBoolean(isO); | 
|  | void *IP = nullptr; | 
|  | SDNode *N = nullptr; | 
|  | if ((N = FindNodeOrInsertPos(ID, DL, IP))) | 
|  | if (!VT.isVector()) | 
|  | return SDValue(N, 0); | 
|  |  | 
|  | if (!N) { | 
|  | N = newSDNode<ConstantSDNode>(isT, isO, Elt, VTs); | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | NewSDValueDbgMsg(SDValue(N, 0), "Creating constant: ", this); | 
|  | } | 
|  |  | 
|  | SDValue Result(N, 0); | 
|  | if (VT.isVector()) | 
|  | Result = getSplat(VT, DL, Result); | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getSignedConstant(int64_t Val, const SDLoc &DL, EVT VT, | 
|  | bool isT, bool isO) { | 
|  | unsigned Size = VT.getScalarSizeInBits(); | 
|  | return getConstant(APInt(Size, Val, /*isSigned=*/true), DL, VT, isT, isO); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getAllOnesConstant(const SDLoc &DL, EVT VT, bool IsTarget, | 
|  | bool IsOpaque) { | 
|  | return getConstant(APInt::getAllOnes(VT.getScalarSizeInBits()), DL, VT, | 
|  | IsTarget, IsOpaque); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getIntPtrConstant(uint64_t Val, const SDLoc &DL, | 
|  | bool isTarget) { | 
|  | return getConstant(Val, DL, TLI->getPointerTy(getDataLayout()), isTarget); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getShiftAmountConstant(uint64_t Val, EVT VT, | 
|  | const SDLoc &DL) { | 
|  | assert(VT.isInteger() && "Shift amount is not an integer type!"); | 
|  | EVT ShiftVT = TLI->getShiftAmountTy(VT, getDataLayout()); | 
|  | return getConstant(Val, DL, ShiftVT); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getShiftAmountConstant(const APInt &Val, EVT VT, | 
|  | const SDLoc &DL) { | 
|  | assert(Val.ult(VT.getScalarSizeInBits()) && "Out of range shift"); | 
|  | return getShiftAmountConstant(Val.getZExtValue(), VT, DL); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getVectorIdxConstant(uint64_t Val, const SDLoc &DL, | 
|  | bool isTarget) { | 
|  | return getConstant(Val, DL, TLI->getVectorIdxTy(getDataLayout()), isTarget); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getConstantFP(const APFloat &V, const SDLoc &DL, EVT VT, | 
|  | bool isTarget) { | 
|  | return getConstantFP(*ConstantFP::get(*getContext(), V), DL, VT, isTarget); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getConstantFP(const ConstantFP &V, const SDLoc &DL, | 
|  | EVT VT, bool isTarget) { | 
|  | assert(VT.isFloatingPoint() && "Cannot create integer FP constant!"); | 
|  |  | 
|  | EVT EltVT = VT.getScalarType(); | 
|  | const ConstantFP *Elt = &V; | 
|  |  | 
|  | // Vector splats are explicit within the DAG, with ConstantFPSDNode holding | 
|  | // the to-be-splatted scalar ConstantFP. | 
|  | if (isa<VectorType>(Elt->getType())) | 
|  | Elt = ConstantFP::get(*getContext(), Elt->getValue()); | 
|  |  | 
|  | // Do the map lookup using the actual bit pattern for the floating point | 
|  | // value, so that we don't have problems with 0.0 comparing equal to -0.0, and | 
|  | // we don't have issues with SNANs. | 
|  | unsigned Opc = isTarget ? ISD::TargetConstantFP : ISD::ConstantFP; | 
|  | SDVTList VTs = getVTList(EltVT); | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, Opc, VTs, {}); | 
|  | ID.AddPointer(Elt); | 
|  | void *IP = nullptr; | 
|  | SDNode *N = nullptr; | 
|  | if ((N = FindNodeOrInsertPos(ID, DL, IP))) | 
|  | if (!VT.isVector()) | 
|  | return SDValue(N, 0); | 
|  |  | 
|  | if (!N) { | 
|  | N = newSDNode<ConstantFPSDNode>(isTarget, Elt, VTs); | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | } | 
|  |  | 
|  | SDValue Result(N, 0); | 
|  | if (VT.isVector()) | 
|  | Result = getSplat(VT, DL, Result); | 
|  | NewSDValueDbgMsg(Result, "Creating fp constant: ", this); | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getConstantFP(double Val, const SDLoc &DL, EVT VT, | 
|  | bool isTarget) { | 
|  | EVT EltVT = VT.getScalarType(); | 
|  | if (EltVT == MVT::f32) | 
|  | return getConstantFP(APFloat((float)Val), DL, VT, isTarget); | 
|  | if (EltVT == MVT::f64) | 
|  | return getConstantFP(APFloat(Val), DL, VT, isTarget); | 
|  | if (EltVT == MVT::f80 || EltVT == MVT::f128 || EltVT == MVT::ppcf128 || | 
|  | EltVT == MVT::f16 || EltVT == MVT::bf16) { | 
|  | bool Ignored; | 
|  | APFloat APF = APFloat(Val); | 
|  | APF.convert(EltVT.getFltSemantics(), APFloat::rmNearestTiesToEven, | 
|  | &Ignored); | 
|  | return getConstantFP(APF, DL, VT, isTarget); | 
|  | } | 
|  | llvm_unreachable("Unsupported type in getConstantFP"); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getGlobalAddress(const GlobalValue *GV, const SDLoc &DL, | 
|  | EVT VT, int64_t Offset, bool isTargetGA, | 
|  | unsigned TargetFlags) { | 
|  | assert((TargetFlags == 0 || isTargetGA) && | 
|  | "Cannot set target flags on target-independent globals"); | 
|  |  | 
|  | // Truncate (with sign-extension) the offset value to the pointer size. | 
|  | unsigned BitWidth = getDataLayout().getPointerTypeSizeInBits(GV->getType()); | 
|  | if (BitWidth < 64) | 
|  | Offset = SignExtend64(Offset, BitWidth); | 
|  |  | 
|  | unsigned Opc; | 
|  | if (GV->isThreadLocal()) | 
|  | Opc = isTargetGA ? ISD::TargetGlobalTLSAddress : ISD::GlobalTLSAddress; | 
|  | else | 
|  | Opc = isTargetGA ? ISD::TargetGlobalAddress : ISD::GlobalAddress; | 
|  |  | 
|  | SDVTList VTs = getVTList(VT); | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, Opc, VTs, {}); | 
|  | ID.AddPointer(GV); | 
|  | ID.AddInteger(Offset); | 
|  | ID.AddInteger(TargetFlags); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, DL, IP)) | 
|  | return SDValue(E, 0); | 
|  |  | 
|  | auto *N = newSDNode<GlobalAddressSDNode>( | 
|  | Opc, DL.getIROrder(), DL.getDebugLoc(), GV, VTs, Offset, TargetFlags); | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | return SDValue(N, 0); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getFrameIndex(int FI, EVT VT, bool isTarget) { | 
|  | unsigned Opc = isTarget ? ISD::TargetFrameIndex : ISD::FrameIndex; | 
|  | SDVTList VTs = getVTList(VT); | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, Opc, VTs, {}); | 
|  | ID.AddInteger(FI); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, IP)) | 
|  | return SDValue(E, 0); | 
|  |  | 
|  | auto *N = newSDNode<FrameIndexSDNode>(FI, VTs, isTarget); | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | return SDValue(N, 0); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getJumpTable(int JTI, EVT VT, bool isTarget, | 
|  | unsigned TargetFlags) { | 
|  | assert((TargetFlags == 0 || isTarget) && | 
|  | "Cannot set target flags on target-independent jump tables"); | 
|  | unsigned Opc = isTarget ? ISD::TargetJumpTable : ISD::JumpTable; | 
|  | SDVTList VTs = getVTList(VT); | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, Opc, VTs, {}); | 
|  | ID.AddInteger(JTI); | 
|  | ID.AddInteger(TargetFlags); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, IP)) | 
|  | return SDValue(E, 0); | 
|  |  | 
|  | auto *N = newSDNode<JumpTableSDNode>(JTI, VTs, isTarget, TargetFlags); | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | return SDValue(N, 0); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getJumpTableDebugInfo(int JTI, SDValue Chain, | 
|  | const SDLoc &DL) { | 
|  | EVT PTy = getTargetLoweringInfo().getPointerTy(getDataLayout()); | 
|  | return getNode(ISD::JUMP_TABLE_DEBUG_INFO, DL, MVT::Glue, Chain, | 
|  | getTargetConstant(static_cast<uint64_t>(JTI), DL, PTy, true)); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getConstantPool(const Constant *C, EVT VT, | 
|  | MaybeAlign Alignment, int Offset, | 
|  | bool isTarget, unsigned TargetFlags) { | 
|  | assert((TargetFlags == 0 || isTarget) && | 
|  | "Cannot set target flags on target-independent globals"); | 
|  | if (!Alignment) | 
|  | Alignment = shouldOptForSize() | 
|  | ? getDataLayout().getABITypeAlign(C->getType()) | 
|  | : getDataLayout().getPrefTypeAlign(C->getType()); | 
|  | unsigned Opc = isTarget ? ISD::TargetConstantPool : ISD::ConstantPool; | 
|  | SDVTList VTs = getVTList(VT); | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, Opc, VTs, {}); | 
|  | ID.AddInteger(Alignment->value()); | 
|  | ID.AddInteger(Offset); | 
|  | ID.AddPointer(C); | 
|  | ID.AddInteger(TargetFlags); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, IP)) | 
|  | return SDValue(E, 0); | 
|  |  | 
|  | auto *N = newSDNode<ConstantPoolSDNode>(isTarget, C, VTs, Offset, *Alignment, | 
|  | TargetFlags); | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | SDValue V = SDValue(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new constant pool: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getConstantPool(MachineConstantPoolValue *C, EVT VT, | 
|  | MaybeAlign Alignment, int Offset, | 
|  | bool isTarget, unsigned TargetFlags) { | 
|  | assert((TargetFlags == 0 || isTarget) && | 
|  | "Cannot set target flags on target-independent globals"); | 
|  | if (!Alignment) | 
|  | Alignment = getDataLayout().getPrefTypeAlign(C->getType()); | 
|  | unsigned Opc = isTarget ? ISD::TargetConstantPool : ISD::ConstantPool; | 
|  | SDVTList VTs = getVTList(VT); | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, Opc, VTs, {}); | 
|  | ID.AddInteger(Alignment->value()); | 
|  | ID.AddInteger(Offset); | 
|  | C->addSelectionDAGCSEId(ID); | 
|  | ID.AddInteger(TargetFlags); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, IP)) | 
|  | return SDValue(E, 0); | 
|  |  | 
|  | auto *N = newSDNode<ConstantPoolSDNode>(isTarget, C, VTs, Offset, *Alignment, | 
|  | TargetFlags); | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | return SDValue(N, 0); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getBasicBlock(MachineBasicBlock *MBB) { | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, ISD::BasicBlock, getVTList(MVT::Other), {}); | 
|  | ID.AddPointer(MBB); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, IP)) | 
|  | return SDValue(E, 0); | 
|  |  | 
|  | auto *N = newSDNode<BasicBlockSDNode>(MBB); | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | return SDValue(N, 0); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getValueType(EVT VT) { | 
|  | if (VT.isSimple() && (unsigned)VT.getSimpleVT().SimpleTy >= | 
|  | ValueTypeNodes.size()) | 
|  | ValueTypeNodes.resize(VT.getSimpleVT().SimpleTy+1); | 
|  |  | 
|  | SDNode *&N = VT.isExtended() ? | 
|  | ExtendedValueTypeNodes[VT] : ValueTypeNodes[VT.getSimpleVT().SimpleTy]; | 
|  |  | 
|  | if (N) return SDValue(N, 0); | 
|  | N = newSDNode<VTSDNode>(VT); | 
|  | InsertNode(N); | 
|  | return SDValue(N, 0); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getExternalSymbol(const char *Sym, EVT VT) { | 
|  | SDNode *&N = ExternalSymbols[Sym]; | 
|  | if (N) return SDValue(N, 0); | 
|  | N = newSDNode<ExternalSymbolSDNode>(false, Sym, 0, getVTList(VT)); | 
|  | InsertNode(N); | 
|  | return SDValue(N, 0); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getMCSymbol(MCSymbol *Sym, EVT VT) { | 
|  | SDNode *&N = MCSymbols[Sym]; | 
|  | if (N) | 
|  | return SDValue(N, 0); | 
|  | N = newSDNode<MCSymbolSDNode>(Sym, getVTList(VT)); | 
|  | InsertNode(N); | 
|  | return SDValue(N, 0); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getTargetExternalSymbol(const char *Sym, EVT VT, | 
|  | unsigned TargetFlags) { | 
|  | SDNode *&N = | 
|  | TargetExternalSymbols[std::pair<std::string, unsigned>(Sym, TargetFlags)]; | 
|  | if (N) return SDValue(N, 0); | 
|  | N = newSDNode<ExternalSymbolSDNode>(true, Sym, TargetFlags, getVTList(VT)); | 
|  | InsertNode(N); | 
|  | return SDValue(N, 0); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getCondCode(ISD::CondCode Cond) { | 
|  | if ((unsigned)Cond >= CondCodeNodes.size()) | 
|  | CondCodeNodes.resize(Cond+1); | 
|  |  | 
|  | if (!CondCodeNodes[Cond]) { | 
|  | auto *N = newSDNode<CondCodeSDNode>(Cond); | 
|  | CondCodeNodes[Cond] = N; | 
|  | InsertNode(N); | 
|  | } | 
|  |  | 
|  | return SDValue(CondCodeNodes[Cond], 0); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getVScale(const SDLoc &DL, EVT VT, APInt MulImm, | 
|  | bool ConstantFold) { | 
|  | assert(MulImm.getBitWidth() == VT.getSizeInBits() && | 
|  | "APInt size does not match type size!"); | 
|  |  | 
|  | if (MulImm == 0) | 
|  | return getConstant(0, DL, VT); | 
|  |  | 
|  | if (ConstantFold) { | 
|  | const MachineFunction &MF = getMachineFunction(); | 
|  | const Function &F = MF.getFunction(); | 
|  | ConstantRange CR = getVScaleRange(&F, 64); | 
|  | if (const APInt *C = CR.getSingleElement()) | 
|  | return getConstant(MulImm * C->getZExtValue(), DL, VT); | 
|  | } | 
|  |  | 
|  | return getNode(ISD::VSCALE, DL, VT, getConstant(MulImm, DL, VT)); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getElementCount(const SDLoc &DL, EVT VT, ElementCount EC, | 
|  | bool ConstantFold) { | 
|  | if (EC.isScalable()) | 
|  | return getVScale(DL, VT, | 
|  | APInt(VT.getSizeInBits(), EC.getKnownMinValue())); | 
|  |  | 
|  | return getConstant(EC.getKnownMinValue(), DL, VT); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getStepVector(const SDLoc &DL, EVT ResVT) { | 
|  | APInt One(ResVT.getScalarSizeInBits(), 1); | 
|  | return getStepVector(DL, ResVT, One); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getStepVector(const SDLoc &DL, EVT ResVT, | 
|  | const APInt &StepVal) { | 
|  | assert(ResVT.getScalarSizeInBits() == StepVal.getBitWidth()); | 
|  | if (ResVT.isScalableVector()) | 
|  | return getNode( | 
|  | ISD::STEP_VECTOR, DL, ResVT, | 
|  | getTargetConstant(StepVal, DL, ResVT.getVectorElementType())); | 
|  |  | 
|  | SmallVector<SDValue, 16> OpsStepConstants; | 
|  | for (uint64_t i = 0; i < ResVT.getVectorNumElements(); i++) | 
|  | OpsStepConstants.push_back( | 
|  | getConstant(StepVal * i, DL, ResVT.getVectorElementType())); | 
|  | return getBuildVector(ResVT, DL, OpsStepConstants); | 
|  | } | 
|  |  | 
|  | /// Swaps the values of N1 and N2. Swaps all indices in the shuffle mask M that | 
|  | /// point at N1 to point at N2 and indices that point at N2 to point at N1. | 
|  | static void commuteShuffle(SDValue &N1, SDValue &N2, MutableArrayRef<int> M) { | 
|  | std::swap(N1, N2); | 
|  | ShuffleVectorSDNode::commuteMask(M); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getVectorShuffle(EVT VT, const SDLoc &dl, SDValue N1, | 
|  | SDValue N2, ArrayRef<int> Mask) { | 
|  | assert(VT.getVectorNumElements() == Mask.size() && | 
|  | "Must have the same number of vector elements as mask elements!"); | 
|  | assert(VT == N1.getValueType() && VT == N2.getValueType() && | 
|  | "Invalid VECTOR_SHUFFLE"); | 
|  |  | 
|  | // Canonicalize shuffle undef, undef -> undef | 
|  | if (N1.isUndef() && N2.isUndef()) | 
|  | return getUNDEF(VT); | 
|  |  | 
|  | // Validate that all indices in Mask are within the range of the elements | 
|  | // input to the shuffle. | 
|  | int NElts = Mask.size(); | 
|  | assert(llvm::all_of(Mask, | 
|  | [&](int M) { return M < (NElts * 2) && M >= -1; }) && | 
|  | "Index out of range"); | 
|  |  | 
|  | // Copy the mask so we can do any needed cleanup. | 
|  | SmallVector<int, 8> MaskVec(Mask); | 
|  |  | 
|  | // Canonicalize shuffle v, v -> v, undef | 
|  | if (N1 == N2) { | 
|  | N2 = getUNDEF(VT); | 
|  | for (int i = 0; i != NElts; ++i) | 
|  | if (MaskVec[i] >= NElts) MaskVec[i] -= NElts; | 
|  | } | 
|  |  | 
|  | // Canonicalize shuffle undef, v -> v, undef.  Commute the shuffle mask. | 
|  | if (N1.isUndef()) | 
|  | commuteShuffle(N1, N2, MaskVec); | 
|  |  | 
|  | if (TLI->hasVectorBlend()) { | 
|  | // If shuffling a splat, try to blend the splat instead. We do this here so | 
|  | // that even when this arises during lowering we don't have to re-handle it. | 
|  | auto BlendSplat = [&](BuildVectorSDNode *BV, int Offset) { | 
|  | BitVector UndefElements; | 
|  | SDValue Splat = BV->getSplatValue(&UndefElements); | 
|  | if (!Splat) | 
|  | return; | 
|  |  | 
|  | for (int i = 0; i < NElts; ++i) { | 
|  | if (MaskVec[i] < Offset || MaskVec[i] >= (Offset + NElts)) | 
|  | continue; | 
|  |  | 
|  | // If this input comes from undef, mark it as such. | 
|  | if (UndefElements[MaskVec[i] - Offset]) { | 
|  | MaskVec[i] = -1; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // If we can blend a non-undef lane, use that instead. | 
|  | if (!UndefElements[i]) | 
|  | MaskVec[i] = i + Offset; | 
|  | } | 
|  | }; | 
|  | if (auto *N1BV = dyn_cast<BuildVectorSDNode>(N1)) | 
|  | BlendSplat(N1BV, 0); | 
|  | if (auto *N2BV = dyn_cast<BuildVectorSDNode>(N2)) | 
|  | BlendSplat(N2BV, NElts); | 
|  | } | 
|  |  | 
|  | // Canonicalize all index into lhs, -> shuffle lhs, undef | 
|  | // Canonicalize all index into rhs, -> shuffle rhs, undef | 
|  | bool AllLHS = true, AllRHS = true; | 
|  | bool N2Undef = N2.isUndef(); | 
|  | for (int i = 0; i != NElts; ++i) { | 
|  | if (MaskVec[i] >= NElts) { | 
|  | if (N2Undef) | 
|  | MaskVec[i] = -1; | 
|  | else | 
|  | AllLHS = false; | 
|  | } else if (MaskVec[i] >= 0) { | 
|  | AllRHS = false; | 
|  | } | 
|  | } | 
|  | if (AllLHS && AllRHS) | 
|  | return getUNDEF(VT); | 
|  | if (AllLHS && !N2Undef) | 
|  | N2 = getUNDEF(VT); | 
|  | if (AllRHS) { | 
|  | N1 = getUNDEF(VT); | 
|  | commuteShuffle(N1, N2, MaskVec); | 
|  | } | 
|  | // Reset our undef status after accounting for the mask. | 
|  | N2Undef = N2.isUndef(); | 
|  | // Re-check whether both sides ended up undef. | 
|  | if (N1.isUndef() && N2Undef) | 
|  | return getUNDEF(VT); | 
|  |  | 
|  | // If Identity shuffle return that node. | 
|  | bool Identity = true, AllSame = true; | 
|  | for (int i = 0; i != NElts; ++i) { | 
|  | if (MaskVec[i] >= 0 && MaskVec[i] != i) Identity = false; | 
|  | if (MaskVec[i] != MaskVec[0]) AllSame = false; | 
|  | } | 
|  | if (Identity && NElts) | 
|  | return N1; | 
|  |  | 
|  | // Shuffling a constant splat doesn't change the result. | 
|  | if (N2Undef) { | 
|  | SDValue V = N1; | 
|  |  | 
|  | // Look through any bitcasts. We check that these don't change the number | 
|  | // (and size) of elements and just changes their types. | 
|  | while (V.getOpcode() == ISD::BITCAST) | 
|  | V = V->getOperand(0); | 
|  |  | 
|  | // A splat should always show up as a build vector node. | 
|  | if (auto *BV = dyn_cast<BuildVectorSDNode>(V)) { | 
|  | BitVector UndefElements; | 
|  | SDValue Splat = BV->getSplatValue(&UndefElements); | 
|  | // If this is a splat of an undef, shuffling it is also undef. | 
|  | if (Splat && Splat.isUndef()) | 
|  | return getUNDEF(VT); | 
|  |  | 
|  | bool SameNumElts = | 
|  | V.getValueType().getVectorNumElements() == VT.getVectorNumElements(); | 
|  |  | 
|  | // We only have a splat which can skip shuffles if there is a splatted | 
|  | // value and no undef lanes rearranged by the shuffle. | 
|  | if (Splat && UndefElements.none()) { | 
|  | // Splat of <x, x, ..., x>, return <x, x, ..., x>, provided that the | 
|  | // number of elements match or the value splatted is a zero constant. | 
|  | if (SameNumElts || isNullConstant(Splat)) | 
|  | return N1; | 
|  | } | 
|  |  | 
|  | // If the shuffle itself creates a splat, build the vector directly. | 
|  | if (AllSame && SameNumElts) { | 
|  | EVT BuildVT = BV->getValueType(0); | 
|  | const SDValue &Splatted = BV->getOperand(MaskVec[0]); | 
|  | SDValue NewBV = getSplatBuildVector(BuildVT, dl, Splatted); | 
|  |  | 
|  | // We may have jumped through bitcasts, so the type of the | 
|  | // BUILD_VECTOR may not match the type of the shuffle. | 
|  | if (BuildVT != VT) | 
|  | NewBV = getNode(ISD::BITCAST, dl, VT, NewBV); | 
|  | return NewBV; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | SDVTList VTs = getVTList(VT); | 
|  | FoldingSetNodeID ID; | 
|  | SDValue Ops[2] = { N1, N2 }; | 
|  | AddNodeIDNode(ID, ISD::VECTOR_SHUFFLE, VTs, Ops); | 
|  | for (int i = 0; i != NElts; ++i) | 
|  | ID.AddInteger(MaskVec[i]); | 
|  |  | 
|  | void* IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, dl, IP)) | 
|  | return SDValue(E, 0); | 
|  |  | 
|  | // Allocate the mask array for the node out of the BumpPtrAllocator, since | 
|  | // SDNode doesn't have access to it.  This memory will be "leaked" when | 
|  | // the node is deallocated, but recovered when the NodeAllocator is released. | 
|  | int *MaskAlloc = OperandAllocator.Allocate<int>(NElts); | 
|  | llvm::copy(MaskVec, MaskAlloc); | 
|  |  | 
|  | auto *N = newSDNode<ShuffleVectorSDNode>(VTs, dl.getIROrder(), | 
|  | dl.getDebugLoc(), MaskAlloc); | 
|  | createOperands(N, Ops); | 
|  |  | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | SDValue V = SDValue(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getCommutedVectorShuffle(const ShuffleVectorSDNode &SV) { | 
|  | EVT VT = SV.getValueType(0); | 
|  | SmallVector<int, 8> MaskVec(SV.getMask()); | 
|  | ShuffleVectorSDNode::commuteMask(MaskVec); | 
|  |  | 
|  | SDValue Op0 = SV.getOperand(0); | 
|  | SDValue Op1 = SV.getOperand(1); | 
|  | return getVectorShuffle(VT, SDLoc(&SV), Op1, Op0, MaskVec); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getRegister(Register Reg, EVT VT) { | 
|  | SDVTList VTs = getVTList(VT); | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, ISD::Register, VTs, {}); | 
|  | ID.AddInteger(Reg.id()); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, IP)) | 
|  | return SDValue(E, 0); | 
|  |  | 
|  | auto *N = newSDNode<RegisterSDNode>(Reg, VTs); | 
|  | N->SDNodeBits.IsDivergent = TLI->isSDNodeSourceOfDivergence(N, FLI, UA); | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | return SDValue(N, 0); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getRegisterMask(const uint32_t *RegMask) { | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, ISD::RegisterMask, getVTList(MVT::Untyped), {}); | 
|  | ID.AddPointer(RegMask); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, IP)) | 
|  | return SDValue(E, 0); | 
|  |  | 
|  | auto *N = newSDNode<RegisterMaskSDNode>(RegMask); | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | return SDValue(N, 0); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getEHLabel(const SDLoc &dl, SDValue Root, | 
|  | MCSymbol *Label) { | 
|  | return getLabelNode(ISD::EH_LABEL, dl, Root, Label); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getLabelNode(unsigned Opcode, const SDLoc &dl, | 
|  | SDValue Root, MCSymbol *Label) { | 
|  | FoldingSetNodeID ID; | 
|  | SDValue Ops[] = { Root }; | 
|  | AddNodeIDNode(ID, Opcode, getVTList(MVT::Other), Ops); | 
|  | ID.AddPointer(Label); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, IP)) | 
|  | return SDValue(E, 0); | 
|  |  | 
|  | auto *N = | 
|  | newSDNode<LabelSDNode>(Opcode, dl.getIROrder(), dl.getDebugLoc(), Label); | 
|  | createOperands(N, Ops); | 
|  |  | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | return SDValue(N, 0); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getBlockAddress(const BlockAddress *BA, EVT VT, | 
|  | int64_t Offset, bool isTarget, | 
|  | unsigned TargetFlags) { | 
|  | unsigned Opc = isTarget ? ISD::TargetBlockAddress : ISD::BlockAddress; | 
|  | SDVTList VTs = getVTList(VT); | 
|  |  | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, Opc, VTs, {}); | 
|  | ID.AddPointer(BA); | 
|  | ID.AddInteger(Offset); | 
|  | ID.AddInteger(TargetFlags); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, IP)) | 
|  | return SDValue(E, 0); | 
|  |  | 
|  | auto *N = newSDNode<BlockAddressSDNode>(Opc, VTs, BA, Offset, TargetFlags); | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | return SDValue(N, 0); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getSrcValue(const Value *V) { | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, ISD::SRCVALUE, getVTList(MVT::Other), {}); | 
|  | ID.AddPointer(V); | 
|  |  | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, IP)) | 
|  | return SDValue(E, 0); | 
|  |  | 
|  | auto *N = newSDNode<SrcValueSDNode>(V); | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | return SDValue(N, 0); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getMDNode(const MDNode *MD) { | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, ISD::MDNODE_SDNODE, getVTList(MVT::Other), {}); | 
|  | ID.AddPointer(MD); | 
|  |  | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, IP)) | 
|  | return SDValue(E, 0); | 
|  |  | 
|  | auto *N = newSDNode<MDNodeSDNode>(MD); | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | return SDValue(N, 0); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getBitcast(EVT VT, SDValue V) { | 
|  | if (VT == V.getValueType()) | 
|  | return V; | 
|  |  | 
|  | return getNode(ISD::BITCAST, SDLoc(V), VT, V); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getAddrSpaceCast(const SDLoc &dl, EVT VT, SDValue Ptr, | 
|  | unsigned SrcAS, unsigned DestAS) { | 
|  | SDVTList VTs = getVTList(VT); | 
|  | SDValue Ops[] = {Ptr}; | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, ISD::ADDRSPACECAST, VTs, Ops); | 
|  | ID.AddInteger(SrcAS); | 
|  | ID.AddInteger(DestAS); | 
|  |  | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, dl, IP)) | 
|  | return SDValue(E, 0); | 
|  |  | 
|  | auto *N = newSDNode<AddrSpaceCastSDNode>(dl.getIROrder(), dl.getDebugLoc(), | 
|  | VTs, SrcAS, DestAS); | 
|  | createOperands(N, Ops); | 
|  |  | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | return SDValue(N, 0); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getFreeze(SDValue V) { | 
|  | return getNode(ISD::FREEZE, SDLoc(V), V.getValueType(), V); | 
|  | } | 
|  |  | 
|  | /// getShiftAmountOperand - Return the specified value casted to | 
|  | /// the target's desired shift amount type. | 
|  | SDValue SelectionDAG::getShiftAmountOperand(EVT LHSTy, SDValue Op) { | 
|  | EVT OpTy = Op.getValueType(); | 
|  | EVT ShTy = TLI->getShiftAmountTy(LHSTy, getDataLayout()); | 
|  | if (OpTy == ShTy || OpTy.isVector()) return Op; | 
|  |  | 
|  | return getZExtOrTrunc(Op, SDLoc(Op), ShTy); | 
|  | } | 
|  |  | 
|  | /// Given a store node \p StoreNode, return true if it is safe to fold that node | 
|  | /// into \p FPNode, which expands to a library call with output pointers. | 
|  | static bool canFoldStoreIntoLibCallOutputPointers(StoreSDNode *StoreNode, | 
|  | SDNode *FPNode) { | 
|  | SmallVector<const SDNode *, 8> Worklist; | 
|  | SmallVector<const SDNode *, 8> DeferredNodes; | 
|  | SmallPtrSet<const SDNode *, 16> Visited; | 
|  |  | 
|  | // Skip FPNode use by StoreNode (that's the use we want to fold into FPNode). | 
|  | for (SDValue Op : StoreNode->ops()) | 
|  | if (Op.getNode() != FPNode) | 
|  | Worklist.push_back(Op.getNode()); | 
|  |  | 
|  | unsigned MaxSteps = SelectionDAG::getHasPredecessorMaxSteps(); | 
|  | while (!Worklist.empty()) { | 
|  | const SDNode *Node = Worklist.pop_back_val(); | 
|  | auto [_, Inserted] = Visited.insert(Node); | 
|  | if (!Inserted) | 
|  | continue; | 
|  |  | 
|  | if (MaxSteps > 0 && Visited.size() >= MaxSteps) | 
|  | return false; | 
|  |  | 
|  | // Reached the FPNode (would result in a cycle). | 
|  | // OR Reached CALLSEQ_START (would result in nested call sequences). | 
|  | if (Node == FPNode || Node->getOpcode() == ISD::CALLSEQ_START) | 
|  | return false; | 
|  |  | 
|  | if (Node->getOpcode() == ISD::CALLSEQ_END) { | 
|  | // Defer looking into call sequences (so we can check we're outside one). | 
|  | // We still need to look through these for the predecessor check. | 
|  | DeferredNodes.push_back(Node); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | for (SDValue Op : Node->ops()) | 
|  | Worklist.push_back(Op.getNode()); | 
|  | } | 
|  |  | 
|  | // True if we're outside a call sequence and don't have the FPNode as a | 
|  | // predecessor. No cycles or nested call sequences possible. | 
|  | return !SDNode::hasPredecessorHelper(FPNode, Visited, DeferredNodes, | 
|  | MaxSteps); | 
|  | } | 
|  |  | 
|  | 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(); | 
|  |  | 
|  | if (LC == RTLIB::UNKNOWN_LIBCALL) | 
|  | return false; | 
|  |  | 
|  | const char *LCName = TLI->getLibcallName(LC); | 
|  | if (!LCName) | 
|  | return false; | 
|  |  | 
|  | auto getVecDesc = [&]() -> VecDesc const * { | 
|  | for (bool Masked : {false, true}) { | 
|  | if (VecDesc const *VD = getLibInfo().getVectorMappingInfo( | 
|  | LCName, VT.getVectorElementCount(), Masked)) { | 
|  | return VD; | 
|  | } | 
|  | } | 
|  | return nullptr; | 
|  | }; | 
|  |  | 
|  | // For vector types, we must find a vector mapping for the libcall. | 
|  | VecDesc const *VD = nullptr; | 
|  | if (VT.isVector() && !(VD = getVecDesc())) | 
|  | return false; | 
|  |  | 
|  | // 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; | 
|  | SmallVector<StoreSDNode *, 2> ResultStores(NumResults); | 
|  | for (SDNode *User : Node->users()) { | 
|  | if (!ISD::isNormalStore(User)) | 
|  | continue; | 
|  | auto *ST = cast<StoreSDNode>(User); | 
|  | SDValue StoreValue = ST->getValue(); | 
|  | unsigned ResNo = StoreValue.getResNo(); | 
|  | // Ensure the store corresponds to an output pointer. | 
|  | if (CallRetResNo == ResNo) | 
|  | continue; | 
|  | // Ensure the store to the default address space and not atomic or volatile. | 
|  | if (!ST->isSimple() || ST->getAddressSpace() != 0) | 
|  | continue; | 
|  | // Ensure all store chains are the same (so they don't alias). | 
|  | if (StoresInChain && ST->getChain() != StoresInChain) | 
|  | continue; | 
|  | // Ensure the store is properly aligned. | 
|  | Type *StoreType = StoreValue.getValueType().getTypeForEVT(Ctx); | 
|  | if (ST->getAlign() < | 
|  | getDataLayout().getABITypeAlign(StoreType->getScalarType())) | 
|  | continue; | 
|  | // Avoid: | 
|  | //  1. Creating cyclic dependencies. | 
|  | //  2. Expanding the node to a call within a call sequence. | 
|  | if (!canFoldStoreIntoLibCallOutputPointers(ST, Node)) | 
|  | continue; | 
|  | ResultStores[ResNo] = ST; | 
|  | StoresInChain = ST->getChain(); | 
|  | } | 
|  |  | 
|  | TargetLowering::ArgListTy Args; | 
|  |  | 
|  | // Pass the arguments. | 
|  | for (const SDValue &Op : Node->op_values()) { | 
|  | EVT ArgVT = Op.getValueType(); | 
|  | Type *ArgTy = ArgVT.getTypeForEVT(Ctx); | 
|  | Args.emplace_back(Op, ArgTy); | 
|  | } | 
|  |  | 
|  | // Pass the output pointers. | 
|  | SmallVector<SDValue, 2> ResultPtrs(NumResults); | 
|  | Type *PointerTy = PointerType::getUnqual(Ctx); | 
|  | for (auto [ResNo, ST] : llvm::enumerate(ResultStores)) { | 
|  | if (ResNo == CallRetResNo) | 
|  | continue; | 
|  | EVT ResVT = Node->getValueType(ResNo); | 
|  | SDValue ResultPtr = ST ? ST->getBasePtr() : CreateStackTemporary(ResVT); | 
|  | ResultPtrs[ResNo] = ResultPtr; | 
|  | Args.emplace_back(ResultPtr, PointerTy); | 
|  | } | 
|  |  | 
|  | SDLoc DL(Node); | 
|  |  | 
|  | // Pass the vector mask (if required). | 
|  | if (VD && VD->isMasked()) { | 
|  | EVT MaskVT = TLI->getSetCCResultType(getDataLayout(), Ctx, VT); | 
|  | SDValue Mask = getBoolConstant(true, DL, MaskVT, VT); | 
|  | Args.emplace_back(Mask, MaskVT.getTypeForEVT(Ctx)); | 
|  | } | 
|  |  | 
|  | Type *RetType = CallRetResNo.has_value() | 
|  | ? Node->getValueType(*CallRetResNo).getTypeForEVT(Ctx) | 
|  | : Type::getVoidTy(Ctx); | 
|  | SDValue InChain = StoresInChain ? StoresInChain : getEntryNode(); | 
|  | SDValue Callee = getExternalSymbol(VD ? VD->getVectorFnName().data() : LCName, | 
|  | TLI->getPointerTy(getDataLayout())); | 
|  | TargetLowering::CallLoweringInfo CLI(*this); | 
|  | CLI.setDebugLoc(DL).setChain(InChain).setLibCallee( | 
|  | TLI->getLibcallCallingConv(LC), RetType, Callee, std::move(Args)); | 
|  |  | 
|  | auto [Call, CallChain] = TLI->LowerCallTo(CLI); | 
|  |  | 
|  | for (auto [ResNo, ResultPtr] : llvm::enumerate(ResultPtrs)) { | 
|  | if (ResNo == CallRetResNo) { | 
|  | Results.push_back(Call); | 
|  | continue; | 
|  | } | 
|  | MachinePointerInfo PtrInfo; | 
|  | SDValue LoadResult = | 
|  | getLoad(Node->getValueType(ResNo), DL, CallChain, ResultPtr, PtrInfo); | 
|  | SDValue OutChain = LoadResult.getValue(1); | 
|  |  | 
|  | if (StoreSDNode *ST = ResultStores[ResNo]) { | 
|  | // Replace store with the library call. | 
|  | ReplaceAllUsesOfValueWith(SDValue(ST, 0), OutChain); | 
|  | PtrInfo = ST->getPointerInfo(); | 
|  | } else { | 
|  | PtrInfo = MachinePointerInfo::getFixedStack( | 
|  | getMachineFunction(), cast<FrameIndexSDNode>(ResultPtr)->getIndex()); | 
|  | } | 
|  |  | 
|  | Results.push_back(LoadResult); | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::expandVAArg(SDNode *Node) { | 
|  | SDLoc dl(Node); | 
|  | const TargetLowering &TLI = getTargetLoweringInfo(); | 
|  | const Value *V = cast<SrcValueSDNode>(Node->getOperand(2))->getValue(); | 
|  | EVT VT = Node->getValueType(0); | 
|  | SDValue Tmp1 = Node->getOperand(0); | 
|  | SDValue Tmp2 = Node->getOperand(1); | 
|  | const MaybeAlign MA(Node->getConstantOperandVal(3)); | 
|  |  | 
|  | SDValue VAListLoad = getLoad(TLI.getPointerTy(getDataLayout()), dl, Tmp1, | 
|  | Tmp2, MachinePointerInfo(V)); | 
|  | SDValue VAList = VAListLoad; | 
|  |  | 
|  | if (MA && *MA > TLI.getMinStackArgumentAlignment()) { | 
|  | VAList = getNode(ISD::ADD, dl, VAList.getValueType(), VAList, | 
|  | getConstant(MA->value() - 1, dl, VAList.getValueType())); | 
|  |  | 
|  | VAList = getNode( | 
|  | ISD::AND, dl, VAList.getValueType(), VAList, | 
|  | getSignedConstant(-(int64_t)MA->value(), dl, VAList.getValueType())); | 
|  | } | 
|  |  | 
|  | // Increment the pointer, VAList, to the next vaarg | 
|  | Tmp1 = getNode(ISD::ADD, dl, VAList.getValueType(), VAList, | 
|  | getConstant(getDataLayout().getTypeAllocSize( | 
|  | VT.getTypeForEVT(*getContext())), | 
|  | dl, VAList.getValueType())); | 
|  | // Store the incremented VAList to the legalized pointer | 
|  | Tmp1 = | 
|  | getStore(VAListLoad.getValue(1), dl, Tmp1, Tmp2, MachinePointerInfo(V)); | 
|  | // Load the actual argument out of the pointer VAList | 
|  | return getLoad(VT, dl, Tmp1, VAList, MachinePointerInfo()); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::expandVACopy(SDNode *Node) { | 
|  | SDLoc dl(Node); | 
|  | const TargetLowering &TLI = getTargetLoweringInfo(); | 
|  | // This defaults to loading a pointer from the input and storing it to the | 
|  | // output, returning the chain. | 
|  | const Value *VD = cast<SrcValueSDNode>(Node->getOperand(3))->getValue(); | 
|  | const Value *VS = cast<SrcValueSDNode>(Node->getOperand(4))->getValue(); | 
|  | SDValue Tmp1 = | 
|  | getLoad(TLI.getPointerTy(getDataLayout()), dl, Node->getOperand(0), | 
|  | Node->getOperand(2), MachinePointerInfo(VS)); | 
|  | return getStore(Tmp1.getValue(1), dl, Tmp1, Node->getOperand(1), | 
|  | MachinePointerInfo(VD)); | 
|  | } | 
|  |  | 
|  | Align SelectionDAG::getReducedAlign(EVT VT, bool UseABI) { | 
|  | const DataLayout &DL = getDataLayout(); | 
|  | Type *Ty = VT.getTypeForEVT(*getContext()); | 
|  | Align RedAlign = UseABI ? DL.getABITypeAlign(Ty) : DL.getPrefTypeAlign(Ty); | 
|  |  | 
|  | if (TLI->isTypeLegal(VT) || !VT.isVector()) | 
|  | return RedAlign; | 
|  |  | 
|  | const TargetFrameLowering *TFI = MF->getSubtarget().getFrameLowering(); | 
|  | const Align StackAlign = TFI->getStackAlign(); | 
|  |  | 
|  | // See if we can choose a smaller ABI alignment in cases where it's an | 
|  | // illegal vector type that will get broken down. | 
|  | if (RedAlign > StackAlign) { | 
|  | EVT IntermediateVT; | 
|  | MVT RegisterVT; | 
|  | unsigned NumIntermediates; | 
|  | TLI->getVectorTypeBreakdown(*getContext(), VT, IntermediateVT, | 
|  | NumIntermediates, RegisterVT); | 
|  | Ty = IntermediateVT.getTypeForEVT(*getContext()); | 
|  | Align RedAlign2 = UseABI ? DL.getABITypeAlign(Ty) : DL.getPrefTypeAlign(Ty); | 
|  | if (RedAlign2 < RedAlign) | 
|  | RedAlign = RedAlign2; | 
|  |  | 
|  | if (!getMachineFunction().getFrameInfo().isStackRealignable()) | 
|  | // If the stack is not realignable, the alignment should be limited to the | 
|  | // StackAlignment | 
|  | RedAlign = std::min(RedAlign, StackAlign); | 
|  | } | 
|  |  | 
|  | return RedAlign; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::CreateStackTemporary(TypeSize Bytes, Align Alignment) { | 
|  | MachineFrameInfo &MFI = MF->getFrameInfo(); | 
|  | const TargetFrameLowering *TFI = MF->getSubtarget().getFrameLowering(); | 
|  | int StackID = 0; | 
|  | if (Bytes.isScalable()) | 
|  | StackID = TFI->getStackIDForScalableVectors(); | 
|  | // The stack id gives an indication of whether the object is scalable or | 
|  | // not, so it's safe to pass in the minimum size here. | 
|  | int FrameIdx = MFI.CreateStackObject(Bytes.getKnownMinValue(), Alignment, | 
|  | false, nullptr, StackID); | 
|  | return getFrameIndex(FrameIdx, TLI->getFrameIndexTy(getDataLayout())); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::CreateStackTemporary(EVT VT, unsigned minAlign) { | 
|  | Type *Ty = VT.getTypeForEVT(*getContext()); | 
|  | Align StackAlign = | 
|  | std::max(getDataLayout().getPrefTypeAlign(Ty), Align(minAlign)); | 
|  | return CreateStackTemporary(VT.getStoreSize(), StackAlign); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::CreateStackTemporary(EVT VT1, EVT VT2) { | 
|  | TypeSize VT1Size = VT1.getStoreSize(); | 
|  | TypeSize VT2Size = VT2.getStoreSize(); | 
|  | assert(VT1Size.isScalable() == VT2Size.isScalable() && | 
|  | "Don't know how to choose the maximum size when creating a stack " | 
|  | "temporary"); | 
|  | TypeSize Bytes = VT1Size.getKnownMinValue() > VT2Size.getKnownMinValue() | 
|  | ? VT1Size | 
|  | : VT2Size; | 
|  |  | 
|  | Type *Ty1 = VT1.getTypeForEVT(*getContext()); | 
|  | Type *Ty2 = VT2.getTypeForEVT(*getContext()); | 
|  | const DataLayout &DL = getDataLayout(); | 
|  | Align Align = std::max(DL.getPrefTypeAlign(Ty1), DL.getPrefTypeAlign(Ty2)); | 
|  | return CreateStackTemporary(Bytes, Align); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::FoldSetCC(EVT VT, SDValue N1, SDValue N2, | 
|  | ISD::CondCode Cond, const SDLoc &dl) { | 
|  | EVT OpVT = N1.getValueType(); | 
|  |  | 
|  | auto GetUndefBooleanConstant = [&]() { | 
|  | if (VT.getScalarType() == MVT::i1 || | 
|  | TLI->getBooleanContents(OpVT) == | 
|  | TargetLowering::UndefinedBooleanContent) | 
|  | return getUNDEF(VT); | 
|  | // ZeroOrOne / ZeroOrNegative require specific values for the high bits, | 
|  | // so we cannot use getUNDEF(). Return zero instead. | 
|  | return getConstant(0, dl, VT); | 
|  | }; | 
|  |  | 
|  | // These setcc operations always fold. | 
|  | switch (Cond) { | 
|  | default: break; | 
|  | case ISD::SETFALSE: | 
|  | case ISD::SETFALSE2: return getBoolConstant(false, dl, VT, OpVT); | 
|  | case ISD::SETTRUE: | 
|  | case ISD::SETTRUE2: return getBoolConstant(true, dl, VT, OpVT); | 
|  |  | 
|  | case ISD::SETOEQ: | 
|  | case ISD::SETOGT: | 
|  | case ISD::SETOGE: | 
|  | case ISD::SETOLT: | 
|  | case ISD::SETOLE: | 
|  | case ISD::SETONE: | 
|  | case ISD::SETO: | 
|  | case ISD::SETUO: | 
|  | case ISD::SETUEQ: | 
|  | case ISD::SETUNE: | 
|  | assert(!OpVT.isInteger() && "Illegal setcc for integer!"); | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (OpVT.isInteger()) { | 
|  | // For EQ and NE, we can always pick a value for the undef to make the | 
|  | // predicate pass or fail, so we can return undef. | 
|  | // Matches behavior in llvm::ConstantFoldCompareInstruction. | 
|  | // icmp eq/ne X, undef -> undef. | 
|  | if ((N1.isUndef() || N2.isUndef()) && | 
|  | (Cond == ISD::SETEQ || Cond == ISD::SETNE)) | 
|  | return GetUndefBooleanConstant(); | 
|  |  | 
|  | // If both operands are undef, we can return undef for int comparison. | 
|  | // icmp undef, undef -> undef. | 
|  | if (N1.isUndef() && N2.isUndef()) | 
|  | return GetUndefBooleanConstant(); | 
|  |  | 
|  | // icmp X, X -> true/false | 
|  | // icmp X, undef -> true/false because undef could be X. | 
|  | if (N1.isUndef() || N2.isUndef() || N1 == N2) | 
|  | return getBoolConstant(ISD::isTrueWhenEqual(Cond), dl, VT, OpVT); | 
|  | } | 
|  |  | 
|  | if (ConstantSDNode *N2C = dyn_cast<ConstantSDNode>(N2)) { | 
|  | const APInt &C2 = N2C->getAPIntValue(); | 
|  | if (ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N1)) { | 
|  | const APInt &C1 = N1C->getAPIntValue(); | 
|  |  | 
|  | return getBoolConstant(ICmpInst::compare(C1, C2, getICmpCondCode(Cond)), | 
|  | dl, VT, OpVT); | 
|  | } | 
|  | } | 
|  |  | 
|  | auto *N1CFP = dyn_cast<ConstantFPSDNode>(N1); | 
|  | auto *N2CFP = dyn_cast<ConstantFPSDNode>(N2); | 
|  |  | 
|  | if (N1CFP && N2CFP) { | 
|  | APFloat::cmpResult R = N1CFP->getValueAPF().compare(N2CFP->getValueAPF()); | 
|  | switch (Cond) { | 
|  | default: break; | 
|  | case ISD::SETEQ:  if (R==APFloat::cmpUnordered) | 
|  | return GetUndefBooleanConstant(); | 
|  | [[fallthrough]]; | 
|  | case ISD::SETOEQ: return getBoolConstant(R==APFloat::cmpEqual, dl, VT, | 
|  | OpVT); | 
|  | case ISD::SETNE:  if (R==APFloat::cmpUnordered) | 
|  | return GetUndefBooleanConstant(); | 
|  | [[fallthrough]]; | 
|  | case ISD::SETONE: return getBoolConstant(R==APFloat::cmpGreaterThan || | 
|  | R==APFloat::cmpLessThan, dl, VT, | 
|  | OpVT); | 
|  | case ISD::SETLT:  if (R==APFloat::cmpUnordered) | 
|  | return GetUndefBooleanConstant(); | 
|  | [[fallthrough]]; | 
|  | case ISD::SETOLT: return getBoolConstant(R==APFloat::cmpLessThan, dl, VT, | 
|  | OpVT); | 
|  | case ISD::SETGT:  if (R==APFloat::cmpUnordered) | 
|  | return GetUndefBooleanConstant(); | 
|  | [[fallthrough]]; | 
|  | case ISD::SETOGT: return getBoolConstant(R==APFloat::cmpGreaterThan, dl, | 
|  | VT, OpVT); | 
|  | case ISD::SETLE:  if (R==APFloat::cmpUnordered) | 
|  | return GetUndefBooleanConstant(); | 
|  | [[fallthrough]]; | 
|  | case ISD::SETOLE: return getBoolConstant(R==APFloat::cmpLessThan || | 
|  | R==APFloat::cmpEqual, dl, VT, | 
|  | OpVT); | 
|  | case ISD::SETGE:  if (R==APFloat::cmpUnordered) | 
|  | return GetUndefBooleanConstant(); | 
|  | [[fallthrough]]; | 
|  | case ISD::SETOGE: return getBoolConstant(R==APFloat::cmpGreaterThan || | 
|  | R==APFloat::cmpEqual, dl, VT, OpVT); | 
|  | case ISD::SETO:   return getBoolConstant(R!=APFloat::cmpUnordered, dl, VT, | 
|  | OpVT); | 
|  | case ISD::SETUO:  return getBoolConstant(R==APFloat::cmpUnordered, dl, VT, | 
|  | OpVT); | 
|  | case ISD::SETUEQ: return getBoolConstant(R==APFloat::cmpUnordered || | 
|  | R==APFloat::cmpEqual, dl, VT, | 
|  | OpVT); | 
|  | case ISD::SETUNE: return getBoolConstant(R!=APFloat::cmpEqual, dl, VT, | 
|  | OpVT); | 
|  | case ISD::SETULT: return getBoolConstant(R==APFloat::cmpUnordered || | 
|  | R==APFloat::cmpLessThan, dl, VT, | 
|  | OpVT); | 
|  | case ISD::SETUGT: return getBoolConstant(R==APFloat::cmpGreaterThan || | 
|  | R==APFloat::cmpUnordered, dl, VT, | 
|  | OpVT); | 
|  | case ISD::SETULE: return getBoolConstant(R!=APFloat::cmpGreaterThan, dl, | 
|  | VT, OpVT); | 
|  | case ISD::SETUGE: return getBoolConstant(R!=APFloat::cmpLessThan, dl, VT, | 
|  | OpVT); | 
|  | } | 
|  | } else if (N1CFP && OpVT.isSimple() && !N2.isUndef()) { | 
|  | // Ensure that the constant occurs on the RHS. | 
|  | ISD::CondCode SwappedCond = ISD::getSetCCSwappedOperands(Cond); | 
|  | if (!TLI->isCondCodeLegal(SwappedCond, OpVT.getSimpleVT())) | 
|  | return SDValue(); | 
|  | return getSetCC(dl, VT, N2, N1, SwappedCond); | 
|  | } else if ((N2CFP && N2CFP->getValueAPF().isNaN()) || | 
|  | (OpVT.isFloatingPoint() && (N1.isUndef() || N2.isUndef()))) { | 
|  | // If an operand is known to be a nan (or undef that could be a nan), we can | 
|  | // fold it. | 
|  | // Choosing NaN for the undef will always make unordered comparison succeed | 
|  | // and ordered comparison fails. | 
|  | // Matches behavior in llvm::ConstantFoldCompareInstruction. | 
|  | switch (ISD::getUnorderedFlavor(Cond)) { | 
|  | default: | 
|  | llvm_unreachable("Unknown flavor!"); | 
|  | case 0: // Known false. | 
|  | return getBoolConstant(false, dl, VT, OpVT); | 
|  | case 1: // Known true. | 
|  | return getBoolConstant(true, dl, VT, OpVT); | 
|  | case 2: // Undefined. | 
|  | return GetUndefBooleanConstant(); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Could not fold it. | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | /// SignBitIsZero - Return true if the sign bit of Op is known to be zero.  We | 
|  | /// use this predicate to simplify operations downstream. | 
|  | bool SelectionDAG::SignBitIsZero(SDValue Op, unsigned Depth) const { | 
|  | unsigned BitWidth = Op.getScalarValueSizeInBits(); | 
|  | return MaskedValueIsZero(Op, APInt::getSignMask(BitWidth), Depth); | 
|  | } | 
|  |  | 
|  | /// 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. | 
|  | bool SelectionDAG::MaskedValueIsZero(SDValue V, const APInt &Mask, | 
|  | unsigned Depth) const { | 
|  | return Mask.isSubsetOf(computeKnownBits(V, Depth).Zero); | 
|  | } | 
|  |  | 
|  | /// MaskedValueIsZero - Return true if 'V & Mask' is known to be zero in | 
|  | /// DemandedElts.  We use this predicate to simplify operations downstream. | 
|  | /// Mask is known to be zero for bits that V cannot have. | 
|  | bool SelectionDAG::MaskedValueIsZero(SDValue V, const APInt &Mask, | 
|  | const APInt &DemandedElts, | 
|  | unsigned Depth) const { | 
|  | return Mask.isSubsetOf(computeKnownBits(V, DemandedElts, Depth).Zero); | 
|  | } | 
|  |  | 
|  | /// MaskedVectorIsZero - Return true if 'Op' is known to be zero in | 
|  | /// DemandedElts.  We use this predicate to simplify operations downstream. | 
|  | bool SelectionDAG::MaskedVectorIsZero(SDValue V, const APInt &DemandedElts, | 
|  | unsigned Depth /* = 0 */) const { | 
|  | return computeKnownBits(V, DemandedElts, Depth).isZero(); | 
|  | } | 
|  |  | 
|  | /// MaskedValueIsAllOnes - Return true if '(Op & Mask) == Mask'. | 
|  | bool SelectionDAG::MaskedValueIsAllOnes(SDValue V, const APInt &Mask, | 
|  | unsigned Depth) const { | 
|  | return Mask.isSubsetOf(computeKnownBits(V, Depth).One); | 
|  | } | 
|  |  | 
|  | APInt SelectionDAG::computeVectorKnownZeroElements(SDValue Op, | 
|  | const APInt &DemandedElts, | 
|  | unsigned Depth) const { | 
|  | EVT VT = Op.getValueType(); | 
|  | assert(VT.isVector() && !VT.isScalableVector() && "Only for fixed vectors!"); | 
|  |  | 
|  | unsigned NumElts = VT.getVectorNumElements(); | 
|  | assert(DemandedElts.getBitWidth() == NumElts && "Unexpected demanded mask."); | 
|  |  | 
|  | APInt KnownZeroElements = APInt::getZero(NumElts); | 
|  | for (unsigned EltIdx = 0; EltIdx != NumElts; ++EltIdx) { | 
|  | if (!DemandedElts[EltIdx]) | 
|  | continue; // Don't query elements that are not demanded. | 
|  | APInt Mask = APInt::getOneBitSet(NumElts, EltIdx); | 
|  | if (MaskedVectorIsZero(Op, Mask, Depth)) | 
|  | KnownZeroElements.setBit(EltIdx); | 
|  | } | 
|  | return KnownZeroElements; | 
|  | } | 
|  |  | 
|  | /// isSplatValue - Return true if the vector V has the same value | 
|  | /// across all DemandedElts. For scalable vectors, we don't know the | 
|  | /// number of lanes at compile time.  Instead, we use a 1 bit APInt | 
|  | /// to represent a conservative value for all lanes; that is, that | 
|  | /// one bit value is implicitly splatted across all lanes. | 
|  | bool SelectionDAG::isSplatValue(SDValue V, const APInt &DemandedElts, | 
|  | APInt &UndefElts, unsigned Depth) const { | 
|  | unsigned Opcode = V.getOpcode(); | 
|  | EVT VT = V.getValueType(); | 
|  | assert(VT.isVector() && "Vector type expected"); | 
|  | assert((!VT.isScalableVector() || DemandedElts.getBitWidth() == 1) && | 
|  | "scalable demanded bits are ignored"); | 
|  |  | 
|  | if (!DemandedElts) | 
|  | return false; // No demanded elts, better to assume we don't know anything. | 
|  |  | 
|  | if (Depth >= MaxRecursionDepth) | 
|  | return false; // Limit search depth. | 
|  |  | 
|  | // Deal with some common cases here that work for both fixed and scalable | 
|  | // vector types. | 
|  | switch (Opcode) { | 
|  | case ISD::SPLAT_VECTOR: | 
|  | UndefElts = V.getOperand(0).isUndef() | 
|  | ? APInt::getAllOnes(DemandedElts.getBitWidth()) | 
|  | : APInt(DemandedElts.getBitWidth(), 0); | 
|  | return true; | 
|  | case ISD::ADD: | 
|  | case ISD::SUB: | 
|  | case ISD::AND: | 
|  | case ISD::XOR: | 
|  | case ISD::OR: { | 
|  | APInt UndefLHS, UndefRHS; | 
|  | SDValue LHS = V.getOperand(0); | 
|  | SDValue RHS = V.getOperand(1); | 
|  | // Only recognize splats with the same demanded undef elements for both | 
|  | // operands, otherwise we might fail to handle binop-specific undef | 
|  | // handling. | 
|  | // e.g. (and undef, 0) -> 0 etc. | 
|  | if (isSplatValue(LHS, DemandedElts, UndefLHS, Depth + 1) && | 
|  | isSplatValue(RHS, DemandedElts, UndefRHS, Depth + 1) && | 
|  | (DemandedElts & UndefLHS) == (DemandedElts & UndefRHS)) { | 
|  | UndefElts = UndefLHS | UndefRHS; | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  | case ISD::ABS: | 
|  | case ISD::TRUNCATE: | 
|  | case ISD::SIGN_EXTEND: | 
|  | case ISD::ZERO_EXTEND: | 
|  | return isSplatValue(V.getOperand(0), DemandedElts, UndefElts, Depth + 1); | 
|  | default: | 
|  | if (Opcode >= ISD::BUILTIN_OP_END || Opcode == ISD::INTRINSIC_WO_CHAIN || | 
|  | Opcode == ISD::INTRINSIC_W_CHAIN || Opcode == ISD::INTRINSIC_VOID) | 
|  | return TLI->isSplatValueForTargetNode(V, DemandedElts, UndefElts, *this, | 
|  | Depth); | 
|  | break; | 
|  | } | 
|  |  | 
|  | // We don't support other cases than those above for scalable vectors at | 
|  | // the moment. | 
|  | if (VT.isScalableVector()) | 
|  | return false; | 
|  |  | 
|  | unsigned NumElts = VT.getVectorNumElements(); | 
|  | assert(NumElts == DemandedElts.getBitWidth() && "Vector size mismatch"); | 
|  | UndefElts = APInt::getZero(NumElts); | 
|  |  | 
|  | switch (Opcode) { | 
|  | case ISD::BUILD_VECTOR: { | 
|  | SDValue Scl; | 
|  | for (unsigned i = 0; i != NumElts; ++i) { | 
|  | SDValue Op = V.getOperand(i); | 
|  | if (Op.isUndef()) { | 
|  | UndefElts.setBit(i); | 
|  | continue; | 
|  | } | 
|  | if (!DemandedElts[i]) | 
|  | continue; | 
|  | if (Scl && Scl != Op) | 
|  | return false; | 
|  | Scl = Op; | 
|  | } | 
|  | return true; | 
|  | } | 
|  | case ISD::VECTOR_SHUFFLE: { | 
|  | // Check if this is a shuffle node doing a splat or a shuffle of a splat. | 
|  | APInt DemandedLHS = APInt::getZero(NumElts); | 
|  | APInt DemandedRHS = APInt::getZero(NumElts); | 
|  | ArrayRef<int> Mask = cast<ShuffleVectorSDNode>(V)->getMask(); | 
|  | for (int i = 0; i != (int)NumElts; ++i) { | 
|  | int M = Mask[i]; | 
|  | if (M < 0) { | 
|  | UndefElts.setBit(i); | 
|  | continue; | 
|  | } | 
|  | if (!DemandedElts[i]) | 
|  | continue; | 
|  | if (M < (int)NumElts) | 
|  | DemandedLHS.setBit(M); | 
|  | else | 
|  | DemandedRHS.setBit(M - NumElts); | 
|  | } | 
|  |  | 
|  | // If we aren't demanding either op, assume there's no splat. | 
|  | // If we are demanding both ops, assume there's no splat. | 
|  | if ((DemandedLHS.isZero() && DemandedRHS.isZero()) || | 
|  | (!DemandedLHS.isZero() && !DemandedRHS.isZero())) | 
|  | return false; | 
|  |  | 
|  | // See if the demanded elts of the source op is a splat or we only demand | 
|  | // one element, which should always be a splat. | 
|  | // TODO: Handle source ops splats with undefs. | 
|  | auto CheckSplatSrc = [&](SDValue Src, const APInt &SrcElts) { | 
|  | APInt SrcUndefs; | 
|  | return (SrcElts.popcount() == 1) || | 
|  | (isSplatValue(Src, SrcElts, SrcUndefs, Depth + 1) && | 
|  | (SrcElts & SrcUndefs).isZero()); | 
|  | }; | 
|  | if (!DemandedLHS.isZero()) | 
|  | return CheckSplatSrc(V.getOperand(0), DemandedLHS); | 
|  | return CheckSplatSrc(V.getOperand(1), DemandedRHS); | 
|  | } | 
|  | case ISD::EXTRACT_SUBVECTOR: { | 
|  | // Offset the demanded elts by the subvector index. | 
|  | SDValue Src = V.getOperand(0); | 
|  | // We don't support scalable vectors at the moment. | 
|  | if (Src.getValueType().isScalableVector()) | 
|  | return false; | 
|  | uint64_t Idx = V.getConstantOperandVal(1); | 
|  | unsigned NumSrcElts = Src.getValueType().getVectorNumElements(); | 
|  | APInt UndefSrcElts; | 
|  | APInt DemandedSrcElts = DemandedElts.zext(NumSrcElts).shl(Idx); | 
|  | if (isSplatValue(Src, DemandedSrcElts, UndefSrcElts, Depth + 1)) { | 
|  | UndefElts = UndefSrcElts.extractBits(NumElts, Idx); | 
|  | return true; | 
|  | } | 
|  | break; | 
|  | } | 
|  | case ISD::ANY_EXTEND_VECTOR_INREG: | 
|  | case ISD::SIGN_EXTEND_VECTOR_INREG: | 
|  | case ISD::ZERO_EXTEND_VECTOR_INREG: { | 
|  | // Widen the demanded elts by the src element count. | 
|  | SDValue Src = V.getOperand(0); | 
|  | // We don't support scalable vectors at the moment. | 
|  | if (Src.getValueType().isScalableVector()) | 
|  | return false; | 
|  | unsigned NumSrcElts = Src.getValueType().getVectorNumElements(); | 
|  | APInt UndefSrcElts; | 
|  | APInt DemandedSrcElts = DemandedElts.zext(NumSrcElts); | 
|  | if (isSplatValue(Src, DemandedSrcElts, UndefSrcElts, Depth + 1)) { | 
|  | UndefElts = UndefSrcElts.trunc(NumElts); | 
|  | return true; | 
|  | } | 
|  | break; | 
|  | } | 
|  | case ISD::BITCAST: { | 
|  | SDValue Src = V.getOperand(0); | 
|  | EVT SrcVT = Src.getValueType(); | 
|  | unsigned SrcBitWidth = SrcVT.getScalarSizeInBits(); | 
|  | unsigned BitWidth = VT.getScalarSizeInBits(); | 
|  |  | 
|  | // Ignore bitcasts from unsupported types. | 
|  | // TODO: Add fp support? | 
|  | if (!SrcVT.isVector() || !SrcVT.isInteger() || !VT.isInteger()) | 
|  | break; | 
|  |  | 
|  | // Bitcast 'small element' vector to 'large element' vector. | 
|  | if ((BitWidth % SrcBitWidth) == 0) { | 
|  | // See if each sub element is a splat. | 
|  | unsigned Scale = BitWidth / SrcBitWidth; | 
|  | unsigned NumSrcElts = SrcVT.getVectorNumElements(); | 
|  | APInt ScaledDemandedElts = | 
|  | APIntOps::ScaleBitMask(DemandedElts, NumSrcElts); | 
|  | for (unsigned I = 0; I != Scale; ++I) { | 
|  | APInt SubUndefElts; | 
|  | APInt SubDemandedElt = APInt::getOneBitSet(Scale, I); | 
|  | APInt SubDemandedElts = APInt::getSplat(NumSrcElts, SubDemandedElt); | 
|  | SubDemandedElts &= ScaledDemandedElts; | 
|  | if (!isSplatValue(Src, SubDemandedElts, SubUndefElts, Depth + 1)) | 
|  | return false; | 
|  | // TODO: Add support for merging sub undef elements. | 
|  | if (!SubUndefElts.isZero()) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /// Helper wrapper to main isSplatValue function. | 
|  | bool SelectionDAG::isSplatValue(SDValue V, bool AllowUndefs) const { | 
|  | EVT VT = V.getValueType(); | 
|  | assert(VT.isVector() && "Vector type expected"); | 
|  |  | 
|  | APInt UndefElts; | 
|  | // Since the number of lanes in a scalable vector is unknown at compile time, | 
|  | // we track one bit which is implicitly broadcast to all lanes.  This means | 
|  | // that all lanes in a scalable vector are considered demanded. | 
|  | APInt DemandedElts | 
|  | = APInt::getAllOnes(VT.isScalableVector() ? 1 : VT.getVectorNumElements()); | 
|  | return isSplatValue(V, DemandedElts, UndefElts) && | 
|  | (AllowUndefs || !UndefElts); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getSplatSourceVector(SDValue V, int &SplatIdx) { | 
|  | V = peekThroughExtractSubvectors(V); | 
|  |  | 
|  | EVT VT = V.getValueType(); | 
|  | unsigned Opcode = V.getOpcode(); | 
|  | switch (Opcode) { | 
|  | default: { | 
|  | APInt UndefElts; | 
|  | // Since the number of lanes in a scalable vector is unknown at compile time, | 
|  | // we track one bit which is implicitly broadcast to all lanes.  This means | 
|  | // that all lanes in a scalable vector are considered demanded. | 
|  | APInt DemandedElts | 
|  | = APInt::getAllOnes(VT.isScalableVector() ? 1 : VT.getVectorNumElements()); | 
|  |  | 
|  | if (isSplatValue(V, DemandedElts, UndefElts)) { | 
|  | if (VT.isScalableVector()) { | 
|  | // DemandedElts and UndefElts are ignored for scalable vectors, since | 
|  | // the only supported cases are SPLAT_VECTOR nodes. | 
|  | SplatIdx = 0; | 
|  | } else { | 
|  | // Handle case where all demanded elements are UNDEF. | 
|  | if (DemandedElts.isSubsetOf(UndefElts)) { | 
|  | SplatIdx = 0; | 
|  | return getUNDEF(VT); | 
|  | } | 
|  | SplatIdx = (UndefElts & DemandedElts).countr_one(); | 
|  | } | 
|  | return V; | 
|  | } | 
|  | break; | 
|  | } | 
|  | case ISD::SPLAT_VECTOR: | 
|  | SplatIdx = 0; | 
|  | return V; | 
|  | case ISD::VECTOR_SHUFFLE: { | 
|  | assert(!VT.isScalableVector()); | 
|  | // Check if this is a shuffle node doing a splat. | 
|  | // TODO - remove this and rely purely on SelectionDAG::isSplatValue, | 
|  | // getTargetVShiftNode currently struggles without the splat source. | 
|  | auto *SVN = cast<ShuffleVectorSDNode>(V); | 
|  | if (!SVN->isSplat()) | 
|  | break; | 
|  | int Idx = SVN->getSplatIndex(); | 
|  | int NumElts = V.getValueType().getVectorNumElements(); | 
|  | SplatIdx = Idx % NumElts; | 
|  | return V.getOperand(Idx / NumElts); | 
|  | } | 
|  | } | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getSplatValue(SDValue V, bool LegalTypes) { | 
|  | int SplatIdx; | 
|  | if (SDValue SrcVector = getSplatSourceVector(V, SplatIdx)) { | 
|  | EVT SVT = SrcVector.getValueType().getScalarType(); | 
|  | EVT LegalSVT = SVT; | 
|  | if (LegalTypes && !TLI->isTypeLegal(SVT)) { | 
|  | if (!SVT.isInteger()) | 
|  | return SDValue(); | 
|  | LegalSVT = TLI->getTypeToTransformTo(*getContext(), LegalSVT); | 
|  | if (LegalSVT.bitsLT(SVT)) | 
|  | return SDValue(); | 
|  | } | 
|  | return getExtractVectorElt(SDLoc(V), LegalSVT, SrcVector, SplatIdx); | 
|  | } | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | std::optional<ConstantRange> | 
|  | SelectionDAG::getValidShiftAmountRange(SDValue V, const APInt &DemandedElts, | 
|  | unsigned Depth) const { | 
|  | assert((V.getOpcode() == ISD::SHL || V.getOpcode() == ISD::SRL || | 
|  | V.getOpcode() == ISD::SRA) && | 
|  | "Unknown shift node"); | 
|  | // Shifting more than the bitwidth is not valid. | 
|  | unsigned BitWidth = V.getScalarValueSizeInBits(); | 
|  |  | 
|  | if (auto *Cst = dyn_cast<ConstantSDNode>(V.getOperand(1))) { | 
|  | const APInt &ShAmt = Cst->getAPIntValue(); | 
|  | if (ShAmt.uge(BitWidth)) | 
|  | return std::nullopt; | 
|  | return ConstantRange(ShAmt); | 
|  | } | 
|  |  | 
|  | if (auto *BV = dyn_cast<BuildVectorSDNode>(V.getOperand(1))) { | 
|  | const APInt *MinAmt = nullptr, *MaxAmt = nullptr; | 
|  | for (unsigned i = 0, e = BV->getNumOperands(); i != e; ++i) { | 
|  | if (!DemandedElts[i]) | 
|  | continue; | 
|  | auto *SA = dyn_cast<ConstantSDNode>(BV->getOperand(i)); | 
|  | if (!SA) { | 
|  | MinAmt = MaxAmt = nullptr; | 
|  | break; | 
|  | } | 
|  | const APInt &ShAmt = SA->getAPIntValue(); | 
|  | if (ShAmt.uge(BitWidth)) | 
|  | return std::nullopt; | 
|  | if (!MinAmt || MinAmt->ugt(ShAmt)) | 
|  | MinAmt = &ShAmt; | 
|  | if (!MaxAmt || MaxAmt->ult(ShAmt)) | 
|  | MaxAmt = &ShAmt; | 
|  | } | 
|  | assert(((!MinAmt && !MaxAmt) || (MinAmt && MaxAmt)) && | 
|  | "Failed to find matching min/max shift amounts"); | 
|  | if (MinAmt && MaxAmt) | 
|  | return ConstantRange(*MinAmt, *MaxAmt + 1); | 
|  | } | 
|  |  | 
|  | // Use computeKnownBits to find a hidden constant/knownbits (usually type | 
|  | // legalized). e.g. Hidden behind multiple bitcasts/build_vector/casts etc. | 
|  | KnownBits KnownAmt = computeKnownBits(V.getOperand(1), DemandedElts, Depth); | 
|  | if (KnownAmt.getMaxValue().ult(BitWidth)) | 
|  | return ConstantRange::fromKnownBits(KnownAmt, /*IsSigned=*/false); | 
|  |  | 
|  | return std::nullopt; | 
|  | } | 
|  |  | 
|  | std::optional<unsigned> | 
|  | SelectionDAG::getValidShiftAmount(SDValue V, const APInt &DemandedElts, | 
|  | unsigned Depth) const { | 
|  | assert((V.getOpcode() == ISD::SHL || V.getOpcode() == ISD::SRL || | 
|  | V.getOpcode() == ISD::SRA) && | 
|  | "Unknown shift node"); | 
|  | if (std::optional<ConstantRange> AmtRange = | 
|  | getValidShiftAmountRange(V, DemandedElts, Depth)) | 
|  | if (const APInt *ShAmt = AmtRange->getSingleElement()) | 
|  | return ShAmt->getZExtValue(); | 
|  | return std::nullopt; | 
|  | } | 
|  |  | 
|  | std::optional<unsigned> | 
|  | SelectionDAG::getValidShiftAmount(SDValue V, unsigned Depth) const { | 
|  | EVT VT = V.getValueType(); | 
|  | APInt DemandedElts = VT.isFixedLengthVector() | 
|  | ? APInt::getAllOnes(VT.getVectorNumElements()) | 
|  | : APInt(1, 1); | 
|  | return getValidShiftAmount(V, DemandedElts, Depth); | 
|  | } | 
|  |  | 
|  | std::optional<unsigned> | 
|  | SelectionDAG::getValidMinimumShiftAmount(SDValue V, const APInt &DemandedElts, | 
|  | unsigned Depth) const { | 
|  | assert((V.getOpcode() == ISD::SHL || V.getOpcode() == ISD::SRL || | 
|  | V.getOpcode() == ISD::SRA) && | 
|  | "Unknown shift node"); | 
|  | if (std::optional<ConstantRange> AmtRange = | 
|  | getValidShiftAmountRange(V, DemandedElts, Depth)) | 
|  | return AmtRange->getUnsignedMin().getZExtValue(); | 
|  | return std::nullopt; | 
|  | } | 
|  |  | 
|  | std::optional<unsigned> | 
|  | SelectionDAG::getValidMinimumShiftAmount(SDValue V, unsigned Depth) const { | 
|  | EVT VT = V.getValueType(); | 
|  | APInt DemandedElts = VT.isFixedLengthVector() | 
|  | ? APInt::getAllOnes(VT.getVectorNumElements()) | 
|  | : APInt(1, 1); | 
|  | return getValidMinimumShiftAmount(V, DemandedElts, Depth); | 
|  | } | 
|  |  | 
|  | std::optional<unsigned> | 
|  | SelectionDAG::getValidMaximumShiftAmount(SDValue V, const APInt &DemandedElts, | 
|  | unsigned Depth) const { | 
|  | assert((V.getOpcode() == ISD::SHL || V.getOpcode() == ISD::SRL || | 
|  | V.getOpcode() == ISD::SRA) && | 
|  | "Unknown shift node"); | 
|  | if (std::optional<ConstantRange> AmtRange = | 
|  | getValidShiftAmountRange(V, DemandedElts, Depth)) | 
|  | return AmtRange->getUnsignedMax().getZExtValue(); | 
|  | return std::nullopt; | 
|  | } | 
|  |  | 
|  | std::optional<unsigned> | 
|  | SelectionDAG::getValidMaximumShiftAmount(SDValue V, unsigned Depth) const { | 
|  | EVT VT = V.getValueType(); | 
|  | APInt DemandedElts = VT.isFixedLengthVector() | 
|  | ? APInt::getAllOnes(VT.getVectorNumElements()) | 
|  | : APInt(1, 1); | 
|  | return getValidMaximumShiftAmount(V, DemandedElts, Depth); | 
|  | } | 
|  |  | 
|  | /// Determine which bits of Op are known to be either zero or one and return | 
|  | /// them in Known. For vectors, the known bits are those that are shared by | 
|  | /// every vector element. | 
|  | KnownBits SelectionDAG::computeKnownBits(SDValue Op, unsigned Depth) const { | 
|  | EVT VT = Op.getValueType(); | 
|  |  | 
|  | // Since the number of lanes in a scalable vector is unknown at compile time, | 
|  | // we track one bit which is implicitly broadcast to all lanes.  This means | 
|  | // that all lanes in a scalable vector are considered demanded. | 
|  | APInt DemandedElts = VT.isFixedLengthVector() | 
|  | ? APInt::getAllOnes(VT.getVectorNumElements()) | 
|  | : APInt(1, 1); | 
|  | return computeKnownBits(Op, DemandedElts, Depth); | 
|  | } | 
|  |  | 
|  | /// Determine which bits of Op are known to be either zero or one and return | 
|  | /// them in Known. The DemandedElts argument allows us to only collect the known | 
|  | /// bits that are shared by the requested vector elements. | 
|  | KnownBits SelectionDAG::computeKnownBits(SDValue Op, const APInt &DemandedElts, | 
|  | unsigned Depth) const { | 
|  | unsigned BitWidth = Op.getScalarValueSizeInBits(); | 
|  |  | 
|  | KnownBits Known(BitWidth);   // Don't know anything. | 
|  |  | 
|  | if (auto OptAPInt = Op->bitcastToAPInt()) { | 
|  | // We know all of the bits for a constant! | 
|  | return KnownBits::makeConstant(*std::move(OptAPInt)); | 
|  | } | 
|  |  | 
|  | if (Depth >= MaxRecursionDepth) | 
|  | return Known;  // Limit search depth. | 
|  |  | 
|  | KnownBits Known2; | 
|  | unsigned NumElts = DemandedElts.getBitWidth(); | 
|  | assert((!Op.getValueType().isFixedLengthVector() || | 
|  | NumElts == Op.getValueType().getVectorNumElements()) && | 
|  | "Unexpected vector size"); | 
|  |  | 
|  | if (!DemandedElts) | 
|  | return Known;  // No demanded elts, better to assume we don't know anything. | 
|  |  | 
|  | unsigned Opcode = Op.getOpcode(); | 
|  | switch (Opcode) { | 
|  | case ISD::MERGE_VALUES: | 
|  | return computeKnownBits(Op.getOperand(Op.getResNo()), DemandedElts, | 
|  | Depth + 1); | 
|  | case ISD::SPLAT_VECTOR: { | 
|  | SDValue SrcOp = Op.getOperand(0); | 
|  | assert(SrcOp.getValueSizeInBits() >= BitWidth && | 
|  | "Expected SPLAT_VECTOR implicit truncation"); | 
|  | // Implicitly truncate the bits to match the official semantics of | 
|  | // SPLAT_VECTOR. | 
|  | Known = computeKnownBits(SrcOp, Depth + 1).trunc(BitWidth); | 
|  | break; | 
|  | } | 
|  | case ISD::SPLAT_VECTOR_PARTS: { | 
|  | unsigned ScalarSize = Op.getOperand(0).getScalarValueSizeInBits(); | 
|  | assert(ScalarSize * Op.getNumOperands() == BitWidth && | 
|  | "Expected SPLAT_VECTOR_PARTS scalars to cover element width"); | 
|  | for (auto [I, SrcOp] : enumerate(Op->ops())) { | 
|  | Known.insertBits(computeKnownBits(SrcOp, Depth + 1), ScalarSize * I); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case ISD::STEP_VECTOR: { | 
|  | const APInt &Step = Op.getConstantOperandAPInt(0); | 
|  |  | 
|  | if (Step.isPowerOf2()) | 
|  | Known.Zero.setLowBits(Step.logBase2()); | 
|  |  | 
|  | const Function &F = getMachineFunction().getFunction(); | 
|  |  | 
|  | if (!isUIntN(BitWidth, Op.getValueType().getVectorMinNumElements())) | 
|  | break; | 
|  | const APInt MinNumElts = | 
|  | APInt(BitWidth, Op.getValueType().getVectorMinNumElements()); | 
|  |  | 
|  | bool Overflow; | 
|  | const APInt MaxNumElts = getVScaleRange(&F, BitWidth) | 
|  | .getUnsignedMax() | 
|  | .umul_ov(MinNumElts, Overflow); | 
|  | if (Overflow) | 
|  | break; | 
|  |  | 
|  | const APInt MaxValue = (MaxNumElts - 1).umul_ov(Step, Overflow); | 
|  | if (Overflow) | 
|  | break; | 
|  |  | 
|  | Known.Zero.setHighBits(MaxValue.countl_zero()); | 
|  | break; | 
|  | } | 
|  | case ISD::BUILD_VECTOR: | 
|  | assert(!Op.getValueType().isScalableVector()); | 
|  | // Collect the known bits that are shared by every demanded vector element. | 
|  | Known.Zero.setAllBits(); Known.One.setAllBits(); | 
|  | for (unsigned i = 0, e = Op.getNumOperands(); i != e; ++i) { | 
|  | if (!DemandedElts[i]) | 
|  | continue; | 
|  |  | 
|  | SDValue SrcOp = Op.getOperand(i); | 
|  | Known2 = computeKnownBits(SrcOp, Depth + 1); | 
|  |  | 
|  | // BUILD_VECTOR can implicitly truncate sources, we must handle this. | 
|  | if (SrcOp.getValueSizeInBits() != BitWidth) { | 
|  | assert(SrcOp.getValueSizeInBits() > BitWidth && | 
|  | "Expected BUILD_VECTOR implicit truncation"); | 
|  | Known2 = Known2.trunc(BitWidth); | 
|  | } | 
|  |  | 
|  | // Known bits are the values that are shared by every demanded element. | 
|  | Known = Known.intersectWith(Known2); | 
|  |  | 
|  | // If we don't know any bits, early out. | 
|  | if (Known.isUnknown()) | 
|  | break; | 
|  | } | 
|  | break; | 
|  | case ISD::VECTOR_SHUFFLE: { | 
|  | assert(!Op.getValueType().isScalableVector()); | 
|  | // Collect the known bits that are shared by every vector element referenced | 
|  | // by the shuffle. | 
|  | APInt DemandedLHS, DemandedRHS; | 
|  | const ShuffleVectorSDNode *SVN = cast<ShuffleVectorSDNode>(Op); | 
|  | assert(NumElts == SVN->getMask().size() && "Unexpected vector size"); | 
|  | if (!getShuffleDemandedElts(NumElts, SVN->getMask(), DemandedElts, | 
|  | DemandedLHS, DemandedRHS)) | 
|  | break; | 
|  |  | 
|  | // Known bits are the values that are shared by every demanded element. | 
|  | Known.Zero.setAllBits(); Known.One.setAllBits(); | 
|  | if (!!DemandedLHS) { | 
|  | SDValue LHS = Op.getOperand(0); | 
|  | Known2 = computeKnownBits(LHS, DemandedLHS, Depth + 1); | 
|  | Known = Known.intersectWith(Known2); | 
|  | } | 
|  | // If we don't know any bits, early out. | 
|  | if (Known.isUnknown()) | 
|  | break; | 
|  | if (!!DemandedRHS) { | 
|  | SDValue RHS = Op.getOperand(1); | 
|  | Known2 = computeKnownBits(RHS, DemandedRHS, Depth + 1); | 
|  | Known = Known.intersectWith(Known2); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case ISD::VSCALE: { | 
|  | const Function &F = getMachineFunction().getFunction(); | 
|  | const APInt &Multiplier = Op.getConstantOperandAPInt(0); | 
|  | Known = getVScaleRange(&F, BitWidth).multiply(Multiplier).toKnownBits(); | 
|  | break; | 
|  | } | 
|  | case ISD::CONCAT_VECTORS: { | 
|  | if (Op.getValueType().isScalableVector()) | 
|  | break; | 
|  | // Split DemandedElts and test each of the demanded subvectors. | 
|  | Known.Zero.setAllBits(); Known.One.setAllBits(); | 
|  | EVT SubVectorVT = Op.getOperand(0).getValueType(); | 
|  | unsigned NumSubVectorElts = SubVectorVT.getVectorNumElements(); | 
|  | unsigned NumSubVectors = Op.getNumOperands(); | 
|  | for (unsigned i = 0; i != NumSubVectors; ++i) { | 
|  | APInt DemandedSub = | 
|  | DemandedElts.extractBits(NumSubVectorElts, i * NumSubVectorElts); | 
|  | if (!!DemandedSub) { | 
|  | SDValue Sub = Op.getOperand(i); | 
|  | Known2 = computeKnownBits(Sub, DemandedSub, Depth + 1); | 
|  | Known = Known.intersectWith(Known2); | 
|  | } | 
|  | // If we don't know any bits, early out. | 
|  | if (Known.isUnknown()) | 
|  | break; | 
|  | } | 
|  | break; | 
|  | } | 
|  | case ISD::INSERT_SUBVECTOR: { | 
|  | if (Op.getValueType().isScalableVector()) | 
|  | break; | 
|  | // Demand any elements from the subvector and the remainder from the src its | 
|  | // inserted into. | 
|  | SDValue Src = Op.getOperand(0); | 
|  | SDValue Sub = Op.getOperand(1); | 
|  | uint64_t Idx = Op.getConstantOperandVal(2); | 
|  | unsigned NumSubElts = Sub.getValueType().getVectorNumElements(); | 
|  | APInt DemandedSubElts = DemandedElts.extractBits(NumSubElts, Idx); | 
|  | APInt DemandedSrcElts = DemandedElts; | 
|  | DemandedSrcElts.clearBits(Idx, Idx + NumSubElts); | 
|  |  | 
|  | Known.One.setAllBits(); | 
|  | Known.Zero.setAllBits(); | 
|  | if (!!DemandedSubElts) { | 
|  | Known = computeKnownBits(Sub, DemandedSubElts, Depth + 1); | 
|  | if (Known.isUnknown()) | 
|  | break; // early-out. | 
|  | } | 
|  | if (!!DemandedSrcElts) { | 
|  | Known2 = computeKnownBits(Src, DemandedSrcElts, Depth + 1); | 
|  | Known = Known.intersectWith(Known2); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case ISD::EXTRACT_SUBVECTOR: { | 
|  | // Offset the demanded elts by the subvector index. | 
|  | SDValue Src = Op.getOperand(0); | 
|  | // Bail until we can represent demanded elements for scalable vectors. | 
|  | if (Op.getValueType().isScalableVector() || Src.getValueType().isScalableVector()) | 
|  | break; | 
|  | uint64_t Idx = Op.getConstantOperandVal(1); | 
|  | unsigned NumSrcElts = Src.getValueType().getVectorNumElements(); | 
|  | APInt DemandedSrcElts = DemandedElts.zext(NumSrcElts).shl(Idx); | 
|  | Known = computeKnownBits(Src, DemandedSrcElts, Depth + 1); | 
|  | break; | 
|  | } | 
|  | case ISD::SCALAR_TO_VECTOR: { | 
|  | if (Op.getValueType().isScalableVector()) | 
|  | break; | 
|  | // We know about scalar_to_vector as much as we know about it source, | 
|  | // which becomes the first element of otherwise unknown vector. | 
|  | if (DemandedElts != 1) | 
|  | break; | 
|  |  | 
|  | SDValue N0 = Op.getOperand(0); | 
|  | Known = computeKnownBits(N0, Depth + 1); | 
|  | if (N0.getValueSizeInBits() != BitWidth) | 
|  | Known = Known.trunc(BitWidth); | 
|  |  | 
|  | break; | 
|  | } | 
|  | case ISD::BITCAST: { | 
|  | if (Op.getValueType().isScalableVector()) | 
|  | break; | 
|  |  | 
|  | SDValue N0 = Op.getOperand(0); | 
|  | EVT SubVT = N0.getValueType(); | 
|  | unsigned SubBitWidth = SubVT.getScalarSizeInBits(); | 
|  |  | 
|  | // Ignore bitcasts from unsupported types. | 
|  | if (!(SubVT.isInteger() || SubVT.isFloatingPoint())) | 
|  | break; | 
|  |  | 
|  | // Fast handling of 'identity' bitcasts. | 
|  | if (BitWidth == SubBitWidth) { | 
|  | Known = computeKnownBits(N0, DemandedElts, Depth + 1); | 
|  | break; | 
|  | } | 
|  |  | 
|  | bool IsLE = getDataLayout().isLittleEndian(); | 
|  |  | 
|  | // Bitcast 'small element' vector to 'large element' scalar/vector. | 
|  | if ((BitWidth % SubBitWidth) == 0) { | 
|  | assert(N0.getValueType().isVector() && "Expected bitcast from vector"); | 
|  |  | 
|  | // Collect known bits for the (larger) output by collecting the known | 
|  | // bits from each set of sub elements and shift these into place. | 
|  | // We need to separately call computeKnownBits for each set of | 
|  | // sub elements as the knownbits for each is likely to be different. | 
|  | unsigned SubScale = BitWidth / SubBitWidth; | 
|  | APInt SubDemandedElts(NumElts * SubScale, 0); | 
|  | for (unsigned i = 0; i != NumElts; ++i) | 
|  | if (DemandedElts[i]) | 
|  | SubDemandedElts.setBit(i * SubScale); | 
|  |  | 
|  | for (unsigned i = 0; i != SubScale; ++i) { | 
|  | Known2 = computeKnownBits(N0, SubDemandedElts.shl(i), | 
|  | Depth + 1); | 
|  | unsigned Shifts = IsLE ? i : SubScale - 1 - i; | 
|  | Known.insertBits(Known2, SubBitWidth * Shifts); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Bitcast 'large element' scalar/vector to 'small element' vector. | 
|  | if ((SubBitWidth % BitWidth) == 0) { | 
|  | assert(Op.getValueType().isVector() && "Expected bitcast to vector"); | 
|  |  | 
|  | // Collect known bits for the (smaller) output by collecting the known | 
|  | // bits from the overlapping larger input elements and extracting the | 
|  | // sub sections we actually care about. | 
|  | unsigned SubScale = SubBitWidth / BitWidth; | 
|  | APInt SubDemandedElts = | 
|  | APIntOps::ScaleBitMask(DemandedElts, NumElts / SubScale); | 
|  | Known2 = computeKnownBits(N0, SubDemandedElts, Depth + 1); | 
|  |  | 
|  | Known.Zero.setAllBits(); Known.One.setAllBits(); | 
|  | for (unsigned i = 0; i != NumElts; ++i) | 
|  | if (DemandedElts[i]) { | 
|  | unsigned Shifts = IsLE ? i : NumElts - 1 - i; | 
|  | unsigned Offset = (Shifts % SubScale) * BitWidth; | 
|  | Known = Known.intersectWith(Known2.extractBits(BitWidth, Offset)); | 
|  | // If we don't know any bits, early out. | 
|  | if (Known.isUnknown()) | 
|  | break; | 
|  | } | 
|  | } | 
|  | break; | 
|  | } | 
|  | case ISD::AND: | 
|  | Known = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  |  | 
|  | Known &= Known2; | 
|  | break; | 
|  | case ISD::OR: | 
|  | Known = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  |  | 
|  | Known |= Known2; | 
|  | break; | 
|  | case ISD::XOR: | 
|  | Known = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  |  | 
|  | Known ^= Known2; | 
|  | break; | 
|  | case ISD::MUL: { | 
|  | Known = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | bool SelfMultiply = Op.getOperand(0) == Op.getOperand(1); | 
|  | // TODO: SelfMultiply can be poison, but not undef. | 
|  | if (SelfMultiply) | 
|  | SelfMultiply &= isGuaranteedNotToBeUndefOrPoison( | 
|  | Op.getOperand(0), DemandedElts, false, Depth + 1); | 
|  | Known = KnownBits::mul(Known, Known2, SelfMultiply); | 
|  |  | 
|  | // If the multiplication is known not to overflow, the product of a number | 
|  | // with itself is non-negative. Only do this if we didn't already computed | 
|  | // the opposite value for the sign bit. | 
|  | if (Op->getFlags().hasNoSignedWrap() && | 
|  | Op.getOperand(0) == Op.getOperand(1) && | 
|  | !Known.isNegative()) | 
|  | Known.makeNonNegative(); | 
|  | break; | 
|  | } | 
|  | case ISD::MULHU: { | 
|  | Known = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known = KnownBits::mulhu(Known, Known2); | 
|  | break; | 
|  | } | 
|  | case ISD::MULHS: { | 
|  | Known = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known = KnownBits::mulhs(Known, Known2); | 
|  | break; | 
|  | } | 
|  | case ISD::ABDU: { | 
|  | Known = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known = KnownBits::abdu(Known, Known2); | 
|  | break; | 
|  | } | 
|  | case ISD::ABDS: { | 
|  | Known = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known = KnownBits::abds(Known, Known2); | 
|  | unsigned SignBits1 = | 
|  | ComputeNumSignBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | if (SignBits1 == 1) | 
|  | break; | 
|  | unsigned SignBits0 = | 
|  | ComputeNumSignBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known.Zero.setHighBits(std::min(SignBits0, SignBits1) - 1); | 
|  | break; | 
|  | } | 
|  | case ISD::UMUL_LOHI: { | 
|  | assert((Op.getResNo() == 0 || Op.getResNo() == 1) && "Unknown result"); | 
|  | Known = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | bool SelfMultiply = Op.getOperand(0) == Op.getOperand(1); | 
|  | if (Op.getResNo() == 0) | 
|  | Known = KnownBits::mul(Known, Known2, SelfMultiply); | 
|  | else | 
|  | Known = KnownBits::mulhu(Known, Known2); | 
|  | break; | 
|  | } | 
|  | case ISD::SMUL_LOHI: { | 
|  | assert((Op.getResNo() == 0 || Op.getResNo() == 1) && "Unknown result"); | 
|  | Known = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | bool SelfMultiply = Op.getOperand(0) == Op.getOperand(1); | 
|  | if (Op.getResNo() == 0) | 
|  | Known = KnownBits::mul(Known, Known2, SelfMultiply); | 
|  | else | 
|  | Known = KnownBits::mulhs(Known, Known2); | 
|  | break; | 
|  | } | 
|  | case ISD::AVGFLOORU: { | 
|  | Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | Known = KnownBits::avgFloorU(Known, Known2); | 
|  | break; | 
|  | } | 
|  | case ISD::AVGCEILU: { | 
|  | Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | Known = KnownBits::avgCeilU(Known, Known2); | 
|  | break; | 
|  | } | 
|  | case ISD::AVGFLOORS: { | 
|  | Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | Known = KnownBits::avgFloorS(Known, Known2); | 
|  | break; | 
|  | } | 
|  | case ISD::AVGCEILS: { | 
|  | Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | Known = KnownBits::avgCeilS(Known, Known2); | 
|  | break; | 
|  | } | 
|  | case ISD::SELECT: | 
|  | case ISD::VSELECT: | 
|  | Known = computeKnownBits(Op.getOperand(2), DemandedElts, Depth+1); | 
|  | // If we don't know any bits, early out. | 
|  | if (Known.isUnknown()) | 
|  | break; | 
|  | Known2 = computeKnownBits(Op.getOperand(1), DemandedElts, Depth+1); | 
|  |  | 
|  | // Only known if known in both the LHS and RHS. | 
|  | Known = Known.intersectWith(Known2); | 
|  | break; | 
|  | case ISD::SELECT_CC: | 
|  | Known = computeKnownBits(Op.getOperand(3), DemandedElts, Depth+1); | 
|  | // If we don't know any bits, early out. | 
|  | if (Known.isUnknown()) | 
|  | break; | 
|  | Known2 = computeKnownBits(Op.getOperand(2), DemandedElts, Depth+1); | 
|  |  | 
|  | // Only known if known in both the LHS and RHS. | 
|  | Known = Known.intersectWith(Known2); | 
|  | break; | 
|  | case ISD::SMULO: | 
|  | case ISD::UMULO: | 
|  | if (Op.getResNo() != 1) | 
|  | break; | 
|  | // The boolean result conforms to getBooleanContents. | 
|  | // If we know the result of a setcc has the top bits zero, use this info. | 
|  | // We know that we have an integer-based boolean since these operations | 
|  | // are only available for integer. | 
|  | if (TLI->getBooleanContents(Op.getValueType().isVector(), false) == | 
|  | TargetLowering::ZeroOrOneBooleanContent && | 
|  | BitWidth > 1) | 
|  | Known.Zero.setBitsFrom(1); | 
|  | break; | 
|  | case ISD::SETCC: | 
|  | case ISD::SETCCCARRY: | 
|  | case ISD::STRICT_FSETCC: | 
|  | case ISD::STRICT_FSETCCS: { | 
|  | unsigned OpNo = Op->isStrictFPOpcode() ? 1 : 0; | 
|  | // If we know the result of a setcc has the top bits zero, use this info. | 
|  | if (TLI->getBooleanContents(Op.getOperand(OpNo).getValueType()) == | 
|  | TargetLowering::ZeroOrOneBooleanContent && | 
|  | BitWidth > 1) | 
|  | Known.Zero.setBitsFrom(1); | 
|  | break; | 
|  | } | 
|  | case ISD::SHL: { | 
|  | Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  |  | 
|  | bool NUW = Op->getFlags().hasNoUnsignedWrap(); | 
|  | bool NSW = Op->getFlags().hasNoSignedWrap(); | 
|  |  | 
|  | bool ShAmtNonZero = Known2.isNonZero(); | 
|  |  | 
|  | Known = KnownBits::shl(Known, Known2, NUW, NSW, ShAmtNonZero); | 
|  |  | 
|  | // Minimum shift low bits are known zero. | 
|  | if (std::optional<unsigned> ShMinAmt = | 
|  | getValidMinimumShiftAmount(Op, DemandedElts, Depth + 1)) | 
|  | Known.Zero.setLowBits(*ShMinAmt); | 
|  | break; | 
|  | } | 
|  | case ISD::SRL: | 
|  | Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | Known = KnownBits::lshr(Known, Known2, /*ShAmtNonZero=*/false, | 
|  | Op->getFlags().hasExact()); | 
|  |  | 
|  | // Minimum shift high bits are known zero. | 
|  | if (std::optional<unsigned> ShMinAmt = | 
|  | getValidMinimumShiftAmount(Op, DemandedElts, Depth + 1)) | 
|  | Known.Zero.setHighBits(*ShMinAmt); | 
|  | break; | 
|  | case ISD::SRA: | 
|  | Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | Known = KnownBits::ashr(Known, Known2, /*ShAmtNonZero=*/false, | 
|  | Op->getFlags().hasExact()); | 
|  | break; | 
|  | case ISD::ROTL: | 
|  | case ISD::ROTR: | 
|  | if (ConstantSDNode *C = | 
|  | isConstOrConstSplat(Op.getOperand(1), DemandedElts)) { | 
|  | unsigned Amt = C->getAPIntValue().urem(BitWidth); | 
|  |  | 
|  | Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  |  | 
|  | // Canonicalize to ROTR. | 
|  | if (Opcode == ISD::ROTL && Amt != 0) | 
|  | Amt = BitWidth - Amt; | 
|  |  | 
|  | Known.Zero = Known.Zero.rotr(Amt); | 
|  | Known.One = Known.One.rotr(Amt); | 
|  | } | 
|  | break; | 
|  | case ISD::FSHL: | 
|  | case ISD::FSHR: | 
|  | if (ConstantSDNode *C = isConstOrConstSplat(Op.getOperand(2), DemandedElts)) { | 
|  | unsigned Amt = C->getAPIntValue().urem(BitWidth); | 
|  |  | 
|  | // For fshl, 0-shift returns the 1st arg. | 
|  | // For fshr, 0-shift returns the 2nd arg. | 
|  | if (Amt == 0) { | 
|  | Known = computeKnownBits(Op.getOperand(Opcode == ISD::FSHL ? 0 : 1), | 
|  | DemandedElts, Depth + 1); | 
|  | break; | 
|  | } | 
|  |  | 
|  | // fshl: (X << (Z % BW)) | (Y >> (BW - (Z % BW))) | 
|  | // fshr: (X << (BW - (Z % BW))) | (Y >> (Z % BW)) | 
|  | Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | if (Opcode == ISD::FSHL) { | 
|  | Known <<= Amt; | 
|  | Known2 >>= BitWidth - Amt; | 
|  | } else { | 
|  | Known <<= BitWidth - Amt; | 
|  | Known2 >>= Amt; | 
|  | } | 
|  | Known = Known.unionWith(Known2); | 
|  | } | 
|  | break; | 
|  | case ISD::SHL_PARTS: | 
|  | case ISD::SRA_PARTS: | 
|  | case ISD::SRL_PARTS: { | 
|  | assert((Op.getResNo() == 0 || Op.getResNo() == 1) && "Unknown result"); | 
|  |  | 
|  | // Collect lo/hi source values and concatenate. | 
|  | unsigned LoBits = Op.getOperand(0).getScalarValueSizeInBits(); | 
|  | unsigned HiBits = Op.getOperand(1).getScalarValueSizeInBits(); | 
|  | Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | Known = Known2.concat(Known); | 
|  |  | 
|  | // Collect shift amount. | 
|  | Known2 = computeKnownBits(Op.getOperand(2), DemandedElts, Depth + 1); | 
|  |  | 
|  | if (Opcode == ISD::SHL_PARTS) | 
|  | Known = KnownBits::shl(Known, Known2); | 
|  | else if (Opcode == ISD::SRA_PARTS) | 
|  | Known = KnownBits::ashr(Known, Known2); | 
|  | else // if (Opcode == ISD::SRL_PARTS) | 
|  | Known = KnownBits::lshr(Known, Known2); | 
|  |  | 
|  | // TODO: Minimum shift low/high bits are known zero. | 
|  |  | 
|  | if (Op.getResNo() == 0) | 
|  | Known = Known.extractBits(LoBits, 0); | 
|  | else | 
|  | Known = Known.extractBits(HiBits, LoBits); | 
|  | break; | 
|  | } | 
|  | case ISD::SIGN_EXTEND_INREG: { | 
|  | Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | EVT EVT = cast<VTSDNode>(Op.getOperand(1))->getVT(); | 
|  | Known = Known.sextInReg(EVT.getScalarSizeInBits()); | 
|  | break; | 
|  | } | 
|  | case ISD::CTTZ: | 
|  | case ISD::CTTZ_ZERO_UNDEF: { | 
|  | Known2 = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | // If we have a known 1, its position is our upper bound. | 
|  | unsigned PossibleTZ = Known2.countMaxTrailingZeros(); | 
|  | unsigned LowBits = llvm::bit_width(PossibleTZ); | 
|  | Known.Zero.setBitsFrom(LowBits); | 
|  | break; | 
|  | } | 
|  | case ISD::CTLZ: | 
|  | case ISD::CTLZ_ZERO_UNDEF: { | 
|  | Known2 = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | // If we have a known 1, its position is our upper bound. | 
|  | unsigned PossibleLZ = Known2.countMaxLeadingZeros(); | 
|  | unsigned LowBits = llvm::bit_width(PossibleLZ); | 
|  | Known.Zero.setBitsFrom(LowBits); | 
|  | break; | 
|  | } | 
|  | case ISD::CTPOP: { | 
|  | Known2 = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | // If we know some of the bits are zero, they can't be one. | 
|  | unsigned PossibleOnes = Known2.countMaxPopulation(); | 
|  | Known.Zero.setBitsFrom(llvm::bit_width(PossibleOnes)); | 
|  | break; | 
|  | } | 
|  | case ISD::PARITY: { | 
|  | // Parity returns 0 everywhere but the LSB. | 
|  | Known.Zero.setBitsFrom(1); | 
|  | break; | 
|  | } | 
|  | case ISD::MGATHER: | 
|  | case ISD::MLOAD: { | 
|  | ISD::LoadExtType ETy = | 
|  | (Opcode == ISD::MGATHER) | 
|  | ? cast<MaskedGatherSDNode>(Op)->getExtensionType() | 
|  | : cast<MaskedLoadSDNode>(Op)->getExtensionType(); | 
|  | if (ETy == ISD::ZEXTLOAD) { | 
|  | EVT MemVT = cast<MemSDNode>(Op)->getMemoryVT(); | 
|  | KnownBits Known0(MemVT.getScalarSizeInBits()); | 
|  | return Known0.zext(BitWidth); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case ISD::LOAD: { | 
|  | LoadSDNode *LD = cast<LoadSDNode>(Op); | 
|  | const Constant *Cst = TLI->getTargetConstantFromLoad(LD); | 
|  | if (ISD::isNON_EXTLoad(LD) && Cst) { | 
|  | // Determine any common known bits from the loaded constant pool value. | 
|  | Type *CstTy = Cst->getType(); | 
|  | if ((NumElts * BitWidth) == CstTy->getPrimitiveSizeInBits() && | 
|  | !Op.getValueType().isScalableVector()) { | 
|  | // If its a vector splat, then we can (quickly) reuse the scalar path. | 
|  | // NOTE: We assume all elements match and none are UNDEF. | 
|  | if (CstTy->isVectorTy()) { | 
|  | if (const Constant *Splat = Cst->getSplatValue()) { | 
|  | Cst = Splat; | 
|  | CstTy = Cst->getType(); | 
|  | } | 
|  | } | 
|  | // TODO - do we need to handle different bitwidths? | 
|  | if (CstTy->isVectorTy() && BitWidth == CstTy->getScalarSizeInBits()) { | 
|  | // Iterate across all vector elements finding common known bits. | 
|  | Known.One.setAllBits(); | 
|  | Known.Zero.setAllBits(); | 
|  | for (unsigned i = 0; i != NumElts; ++i) { | 
|  | if (!DemandedElts[i]) | 
|  | continue; | 
|  | if (Constant *Elt = Cst->getAggregateElement(i)) { | 
|  | if (auto *CInt = dyn_cast<ConstantInt>(Elt)) { | 
|  | const APInt &Value = CInt->getValue(); | 
|  | Known.One &= Value; | 
|  | Known.Zero &= ~Value; | 
|  | continue; | 
|  | } | 
|  | if (auto *CFP = dyn_cast<ConstantFP>(Elt)) { | 
|  | APInt Value = CFP->getValueAPF().bitcastToAPInt(); | 
|  | Known.One &= Value; | 
|  | Known.Zero &= ~Value; | 
|  | continue; | 
|  | } | 
|  | } | 
|  | Known.One.clearAllBits(); | 
|  | Known.Zero.clearAllBits(); | 
|  | break; | 
|  | } | 
|  | } else if (BitWidth == CstTy->getPrimitiveSizeInBits()) { | 
|  | if (auto *CInt = dyn_cast<ConstantInt>(Cst)) { | 
|  | Known = KnownBits::makeConstant(CInt->getValue()); | 
|  | } else if (auto *CFP = dyn_cast<ConstantFP>(Cst)) { | 
|  | Known = | 
|  | KnownBits::makeConstant(CFP->getValueAPF().bitcastToAPInt()); | 
|  | } | 
|  | } | 
|  | } | 
|  | } else if (Op.getResNo() == 0) { | 
|  | unsigned ScalarMemorySize = LD->getMemoryVT().getScalarSizeInBits(); | 
|  | KnownBits KnownScalarMemory(ScalarMemorySize); | 
|  | if (const MDNode *MD = LD->getRanges()) | 
|  | computeKnownBitsFromRangeMetadata(*MD, KnownScalarMemory); | 
|  |  | 
|  | // Extend the Known bits from memory to the size of the scalar result. | 
|  | if (ISD::isZEXTLoad(Op.getNode())) | 
|  | Known = KnownScalarMemory.zext(BitWidth); | 
|  | else if (ISD::isSEXTLoad(Op.getNode())) | 
|  | Known = KnownScalarMemory.sext(BitWidth); | 
|  | else if (ISD::isEXTLoad(Op.getNode())) | 
|  | Known = KnownScalarMemory.anyext(BitWidth); | 
|  | else | 
|  | Known = KnownScalarMemory; | 
|  | assert(Known.getBitWidth() == BitWidth); | 
|  | return Known; | 
|  | } | 
|  | break; | 
|  | } | 
|  | case ISD::ZERO_EXTEND_VECTOR_INREG: { | 
|  | if (Op.getValueType().isScalableVector()) | 
|  | break; | 
|  | EVT InVT = Op.getOperand(0).getValueType(); | 
|  | APInt InDemandedElts = DemandedElts.zext(InVT.getVectorNumElements()); | 
|  | Known = computeKnownBits(Op.getOperand(0), InDemandedElts, Depth + 1); | 
|  | Known = Known.zext(BitWidth); | 
|  | break; | 
|  | } | 
|  | case ISD::ZERO_EXTEND: { | 
|  | Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known = Known.zext(BitWidth); | 
|  | break; | 
|  | } | 
|  | case ISD::SIGN_EXTEND_VECTOR_INREG: { | 
|  | if (Op.getValueType().isScalableVector()) | 
|  | break; | 
|  | EVT InVT = Op.getOperand(0).getValueType(); | 
|  | APInt InDemandedElts = DemandedElts.zext(InVT.getVectorNumElements()); | 
|  | Known = computeKnownBits(Op.getOperand(0), InDemandedElts, Depth + 1); | 
|  | // If the sign bit is known to be zero or one, then sext will extend | 
|  | // it to the top bits, else it will just zext. | 
|  | Known = Known.sext(BitWidth); | 
|  | break; | 
|  | } | 
|  | case ISD::SIGN_EXTEND: { | 
|  | Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | // If the sign bit is known to be zero or one, then sext will extend | 
|  | // it to the top bits, else it will just zext. | 
|  | Known = Known.sext(BitWidth); | 
|  | break; | 
|  | } | 
|  | case ISD::ANY_EXTEND_VECTOR_INREG: { | 
|  | if (Op.getValueType().isScalableVector()) | 
|  | break; | 
|  | EVT InVT = Op.getOperand(0).getValueType(); | 
|  | APInt InDemandedElts = DemandedElts.zext(InVT.getVectorNumElements()); | 
|  | Known = computeKnownBits(Op.getOperand(0), InDemandedElts, Depth + 1); | 
|  | Known = Known.anyext(BitWidth); | 
|  | break; | 
|  | } | 
|  | case ISD::ANY_EXTEND: { | 
|  | Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known = Known.anyext(BitWidth); | 
|  | break; | 
|  | } | 
|  | case ISD::TRUNCATE: { | 
|  | Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known = Known.trunc(BitWidth); | 
|  | break; | 
|  | } | 
|  | case ISD::AssertZext: { | 
|  | EVT VT = cast<VTSDNode>(Op.getOperand(1))->getVT(); | 
|  | APInt InMask = APInt::getLowBitsSet(BitWidth, VT.getSizeInBits()); | 
|  | Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known.Zero |= (~InMask); | 
|  | Known.One  &= (~Known.Zero); | 
|  | break; | 
|  | } | 
|  | case ISD::AssertAlign: { | 
|  | unsigned LogOfAlign = Log2(cast<AssertAlignSDNode>(Op)->getAlign()); | 
|  | assert(LogOfAlign != 0); | 
|  |  | 
|  | // TODO: Should use maximum with source | 
|  | // If a node is guaranteed to be aligned, set low zero bits accordingly as | 
|  | // well as clearing one bits. | 
|  | Known.Zero.setLowBits(LogOfAlign); | 
|  | Known.One.clearLowBits(LogOfAlign); | 
|  | break; | 
|  | } | 
|  | case ISD::FGETSIGN: | 
|  | // All bits are zero except the low bit. | 
|  | Known.Zero.setBitsFrom(1); | 
|  | break; | 
|  | case ISD::ADD: | 
|  | case ISD::SUB: { | 
|  | SDNodeFlags Flags = Op.getNode()->getFlags(); | 
|  | Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | Known = KnownBits::computeForAddSub( | 
|  | Op.getOpcode() == ISD::ADD, Flags.hasNoSignedWrap(), | 
|  | Flags.hasNoUnsignedWrap(), Known, Known2); | 
|  | break; | 
|  | } | 
|  | case ISD::USUBO: | 
|  | case ISD::SSUBO: | 
|  | case ISD::USUBO_CARRY: | 
|  | case ISD::SSUBO_CARRY: | 
|  | if (Op.getResNo() == 1) { | 
|  | // If we know the result of a setcc has the top bits zero, use this info. | 
|  | if (TLI->getBooleanContents(Op.getOperand(0).getValueType()) == | 
|  | TargetLowering::ZeroOrOneBooleanContent && | 
|  | BitWidth > 1) | 
|  | Known.Zero.setBitsFrom(1); | 
|  | break; | 
|  | } | 
|  | [[fallthrough]]; | 
|  | case ISD::SUBC: { | 
|  | assert(Op.getResNo() == 0 && | 
|  | "We only compute knownbits for the difference here."); | 
|  |  | 
|  | // With USUBO_CARRY and SSUBO_CARRY a borrow bit may be added in. | 
|  | KnownBits Borrow(1); | 
|  | if (Opcode == ISD::USUBO_CARRY || Opcode == ISD::SSUBO_CARRY) { | 
|  | Borrow = computeKnownBits(Op.getOperand(2), DemandedElts, Depth + 1); | 
|  | // Borrow has bit width 1 | 
|  | Borrow = Borrow.trunc(1); | 
|  | } else { | 
|  | Borrow.setAllZero(); | 
|  | } | 
|  |  | 
|  | Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | Known = KnownBits::computeForSubBorrow(Known, Known2, Borrow); | 
|  | break; | 
|  | } | 
|  | case ISD::UADDO: | 
|  | case ISD::SADDO: | 
|  | case ISD::UADDO_CARRY: | 
|  | case ISD::SADDO_CARRY: | 
|  | if (Op.getResNo() == 1) { | 
|  | // If we know the result of a setcc has the top bits zero, use this info. | 
|  | if (TLI->getBooleanContents(Op.getOperand(0).getValueType()) == | 
|  | TargetLowering::ZeroOrOneBooleanContent && | 
|  | BitWidth > 1) | 
|  | Known.Zero.setBitsFrom(1); | 
|  | break; | 
|  | } | 
|  | [[fallthrough]]; | 
|  | case ISD::ADDC: | 
|  | case ISD::ADDE: { | 
|  | assert(Op.getResNo() == 0 && "We only compute knownbits for the sum here."); | 
|  |  | 
|  | // With ADDE and UADDO_CARRY, a carry bit may be added in. | 
|  | KnownBits Carry(1); | 
|  | if (Opcode == ISD::ADDE) | 
|  | // Can't track carry from glue, set carry to unknown. | 
|  | Carry.resetAll(); | 
|  | else if (Opcode == ISD::UADDO_CARRY || Opcode == ISD::SADDO_CARRY) { | 
|  | Carry = computeKnownBits(Op.getOperand(2), DemandedElts, Depth + 1); | 
|  | // Carry has bit width 1 | 
|  | Carry = Carry.trunc(1); | 
|  | } else { | 
|  | Carry.setAllZero(); | 
|  | } | 
|  |  | 
|  | Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | Known = KnownBits::computeForAddCarry(Known, Known2, Carry); | 
|  | break; | 
|  | } | 
|  | case ISD::UDIV: { | 
|  | Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | Known = KnownBits::udiv(Known, Known2, Op->getFlags().hasExact()); | 
|  | break; | 
|  | } | 
|  | case ISD::SDIV: { | 
|  | Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | Known = KnownBits::sdiv(Known, Known2, Op->getFlags().hasExact()); | 
|  | break; | 
|  | } | 
|  | case ISD::SREM: { | 
|  | Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | Known = KnownBits::srem(Known, Known2); | 
|  | break; | 
|  | } | 
|  | case ISD::UREM: { | 
|  | Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | Known = KnownBits::urem(Known, Known2); | 
|  | break; | 
|  | } | 
|  | case ISD::EXTRACT_ELEMENT: { | 
|  | Known = computeKnownBits(Op.getOperand(0), Depth+1); | 
|  | const unsigned Index = Op.getConstantOperandVal(1); | 
|  | const unsigned EltBitWidth = Op.getValueSizeInBits(); | 
|  |  | 
|  | // Remove low part of known bits mask | 
|  | Known.Zero = Known.Zero.getHiBits(Known.getBitWidth() - Index * EltBitWidth); | 
|  | Known.One = Known.One.getHiBits(Known.getBitWidth() - Index * EltBitWidth); | 
|  |  | 
|  | // Remove high part of known bit mask | 
|  | Known = Known.trunc(EltBitWidth); | 
|  | break; | 
|  | } | 
|  | case ISD::EXTRACT_VECTOR_ELT: { | 
|  | SDValue InVec = Op.getOperand(0); | 
|  | SDValue EltNo = Op.getOperand(1); | 
|  | EVT VecVT = InVec.getValueType(); | 
|  | // computeKnownBits not yet implemented for scalable vectors. | 
|  | if (VecVT.isScalableVector()) | 
|  | break; | 
|  | const unsigned EltBitWidth = VecVT.getScalarSizeInBits(); | 
|  | const unsigned NumSrcElts = VecVT.getVectorNumElements(); | 
|  |  | 
|  | // If BitWidth > EltBitWidth the value is anyext:ed. So we do not know | 
|  | // anything about the extended bits. | 
|  | if (BitWidth > EltBitWidth) | 
|  | Known = Known.trunc(EltBitWidth); | 
|  |  | 
|  | // If we know the element index, just demand that vector element, else for | 
|  | // an unknown element index, ignore DemandedElts and demand them all. | 
|  | APInt DemandedSrcElts = APInt::getAllOnes(NumSrcElts); | 
|  | auto *ConstEltNo = dyn_cast<ConstantSDNode>(EltNo); | 
|  | if (ConstEltNo && ConstEltNo->getAPIntValue().ult(NumSrcElts)) | 
|  | DemandedSrcElts = | 
|  | APInt::getOneBitSet(NumSrcElts, ConstEltNo->getZExtValue()); | 
|  |  | 
|  | Known = computeKnownBits(InVec, DemandedSrcElts, Depth + 1); | 
|  | if (BitWidth > EltBitWidth) | 
|  | Known = Known.anyext(BitWidth); | 
|  | break; | 
|  | } | 
|  | case ISD::INSERT_VECTOR_ELT: { | 
|  | if (Op.getValueType().isScalableVector()) | 
|  | break; | 
|  |  | 
|  | // If we know the element index, split the demand between the | 
|  | // source vector and the inserted element, otherwise assume we need | 
|  | // the original demanded vector elements and the value. | 
|  | SDValue InVec = Op.getOperand(0); | 
|  | SDValue InVal = Op.getOperand(1); | 
|  | SDValue EltNo = Op.getOperand(2); | 
|  | bool DemandedVal = true; | 
|  | APInt DemandedVecElts = DemandedElts; | 
|  | auto *CEltNo = dyn_cast<ConstantSDNode>(EltNo); | 
|  | if (CEltNo && CEltNo->getAPIntValue().ult(NumElts)) { | 
|  | unsigned EltIdx = CEltNo->getZExtValue(); | 
|  | DemandedVal = !!DemandedElts[EltIdx]; | 
|  | DemandedVecElts.clearBit(EltIdx); | 
|  | } | 
|  | Known.One.setAllBits(); | 
|  | Known.Zero.setAllBits(); | 
|  | if (DemandedVal) { | 
|  | Known2 = computeKnownBits(InVal, Depth + 1); | 
|  | Known = Known.intersectWith(Known2.zextOrTrunc(BitWidth)); | 
|  | } | 
|  | if (!!DemandedVecElts) { | 
|  | Known2 = computeKnownBits(InVec, DemandedVecElts, Depth + 1); | 
|  | Known = Known.intersectWith(Known2); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case ISD::BITREVERSE: { | 
|  | Known2 = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known = Known2.reverseBits(); | 
|  | break; | 
|  | } | 
|  | case ISD::BSWAP: { | 
|  | Known2 = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known = Known2.byteSwap(); | 
|  | break; | 
|  | } | 
|  | case ISD::ABS: { | 
|  | Known2 = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known = Known2.abs(); | 
|  | Known.Zero.setHighBits( | 
|  | ComputeNumSignBits(Op.getOperand(0), DemandedElts, Depth + 1) - 1); | 
|  | break; | 
|  | } | 
|  | case ISD::USUBSAT: { | 
|  | Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | Known = KnownBits::usub_sat(Known, Known2); | 
|  | break; | 
|  | } | 
|  | case ISD::UMIN: { | 
|  | Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | Known = KnownBits::umin(Known, Known2); | 
|  | break; | 
|  | } | 
|  | case ISD::UMAX: { | 
|  | Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | Known = KnownBits::umax(Known, Known2); | 
|  | break; | 
|  | } | 
|  | case ISD::SMIN: | 
|  | case ISD::SMAX: { | 
|  | // If we have a clamp pattern, we know that the number of sign bits will be | 
|  | // the minimum of the clamp min/max range. | 
|  | bool IsMax = (Opcode == ISD::SMAX); | 
|  | ConstantSDNode *CstLow = nullptr, *CstHigh = nullptr; | 
|  | if ((CstLow = isConstOrConstSplat(Op.getOperand(1), DemandedElts))) | 
|  | if (Op.getOperand(0).getOpcode() == (IsMax ? ISD::SMIN : ISD::SMAX)) | 
|  | CstHigh = | 
|  | isConstOrConstSplat(Op.getOperand(0).getOperand(1), DemandedElts); | 
|  | if (CstLow && CstHigh) { | 
|  | if (!IsMax) | 
|  | std::swap(CstLow, CstHigh); | 
|  |  | 
|  | const APInt &ValueLow = CstLow->getAPIntValue(); | 
|  | const APInt &ValueHigh = CstHigh->getAPIntValue(); | 
|  | if (ValueLow.sle(ValueHigh)) { | 
|  | unsigned LowSignBits = ValueLow.getNumSignBits(); | 
|  | unsigned HighSignBits = ValueHigh.getNumSignBits(); | 
|  | unsigned MinSignBits = std::min(LowSignBits, HighSignBits); | 
|  | if (ValueLow.isNegative() && ValueHigh.isNegative()) { | 
|  | Known.One.setHighBits(MinSignBits); | 
|  | break; | 
|  | } | 
|  | if (ValueLow.isNonNegative() && ValueHigh.isNonNegative()) { | 
|  | Known.Zero.setHighBits(MinSignBits); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | Known2 = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | if (IsMax) | 
|  | Known = KnownBits::smax(Known, Known2); | 
|  | else | 
|  | Known = KnownBits::smin(Known, Known2); | 
|  |  | 
|  | // For SMAX, if CstLow is non-negative we know the result will be | 
|  | // non-negative and thus all sign bits are 0. | 
|  | // TODO: There's an equivalent of this for smin with negative constant for | 
|  | // known ones. | 
|  | if (IsMax && CstLow) { | 
|  | const APInt &ValueLow = CstLow->getAPIntValue(); | 
|  | if (ValueLow.isNonNegative()) { | 
|  | unsigned SignBits = ComputeNumSignBits(Op.getOperand(0), Depth + 1); | 
|  | Known.Zero.setHighBits(std::min(SignBits, ValueLow.getNumSignBits())); | 
|  | } | 
|  | } | 
|  |  | 
|  | break; | 
|  | } | 
|  | case ISD::UINT_TO_FP: { | 
|  | Known.makeNonNegative(); | 
|  | break; | 
|  | } | 
|  | case ISD::SINT_TO_FP: { | 
|  | Known2 = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | if (Known2.isNonNegative()) | 
|  | Known.makeNonNegative(); | 
|  | else if (Known2.isNegative()) | 
|  | Known.makeNegative(); | 
|  | break; | 
|  | } | 
|  | case ISD::FP_TO_UINT_SAT: { | 
|  | // FP_TO_UINT_SAT produces an unsigned value that fits in the saturating VT. | 
|  | EVT VT = cast<VTSDNode>(Op.getOperand(1))->getVT(); | 
|  | Known.Zero |= APInt::getBitsSetFrom(BitWidth, VT.getScalarSizeInBits()); | 
|  | break; | 
|  | } | 
|  | case ISD::ATOMIC_LOAD: { | 
|  | // If we are looking at the loaded value. | 
|  | if (Op.getResNo() == 0) { | 
|  | auto *AT = cast<AtomicSDNode>(Op); | 
|  | unsigned ScalarMemorySize = AT->getMemoryVT().getScalarSizeInBits(); | 
|  | KnownBits KnownScalarMemory(ScalarMemorySize); | 
|  | if (const MDNode *MD = AT->getRanges()) | 
|  | computeKnownBitsFromRangeMetadata(*MD, KnownScalarMemory); | 
|  |  | 
|  | switch (AT->getExtensionType()) { | 
|  | case ISD::ZEXTLOAD: | 
|  | Known = KnownScalarMemory.zext(BitWidth); | 
|  | break; | 
|  | case ISD::SEXTLOAD: | 
|  | Known = KnownScalarMemory.sext(BitWidth); | 
|  | break; | 
|  | case ISD::EXTLOAD: | 
|  | switch (TLI->getExtendForAtomicOps()) { | 
|  | case ISD::ZERO_EXTEND: | 
|  | Known = KnownScalarMemory.zext(BitWidth); | 
|  | break; | 
|  | case ISD::SIGN_EXTEND: | 
|  | Known = KnownScalarMemory.sext(BitWidth); | 
|  | break; | 
|  | default: | 
|  | Known = KnownScalarMemory.anyext(BitWidth); | 
|  | break; | 
|  | } | 
|  | break; | 
|  | case ISD::NON_EXTLOAD: | 
|  | Known = KnownScalarMemory; | 
|  | break; | 
|  | } | 
|  | assert(Known.getBitWidth() == BitWidth); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS: | 
|  | if (Op.getResNo() == 1) { | 
|  | // The boolean result conforms to getBooleanContents. | 
|  | // If we know the result of a setcc has the top bits zero, use this info. | 
|  | // We know that we have an integer-based boolean since these operations | 
|  | // are only available for integer. | 
|  | if (TLI->getBooleanContents(Op.getValueType().isVector(), false) == | 
|  | TargetLowering::ZeroOrOneBooleanContent && | 
|  | BitWidth > 1) | 
|  | Known.Zero.setBitsFrom(1); | 
|  | break; | 
|  | } | 
|  | [[fallthrough]]; | 
|  | case ISD::ATOMIC_CMP_SWAP: | 
|  | case ISD::ATOMIC_SWAP: | 
|  | case ISD::ATOMIC_LOAD_ADD: | 
|  | case ISD::ATOMIC_LOAD_SUB: | 
|  | case ISD::ATOMIC_LOAD_AND: | 
|  | case ISD::ATOMIC_LOAD_CLR: | 
|  | case ISD::ATOMIC_LOAD_OR: | 
|  | case ISD::ATOMIC_LOAD_XOR: | 
|  | case ISD::ATOMIC_LOAD_NAND: | 
|  | case ISD::ATOMIC_LOAD_MIN: | 
|  | case ISD::ATOMIC_LOAD_MAX: | 
|  | case ISD::ATOMIC_LOAD_UMIN: | 
|  | case ISD::ATOMIC_LOAD_UMAX: { | 
|  | // If we are looking at the loaded value. | 
|  | if (Op.getResNo() == 0) { | 
|  | auto *AT = cast<AtomicSDNode>(Op); | 
|  | unsigned MemBits = AT->getMemoryVT().getScalarSizeInBits(); | 
|  |  | 
|  | if (TLI->getExtendForAtomicOps() == ISD::ZERO_EXTEND) | 
|  | Known.Zero.setBitsFrom(MemBits); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case ISD::FrameIndex: | 
|  | case ISD::TargetFrameIndex: | 
|  | TLI->computeKnownBitsForFrameIndex(cast<FrameIndexSDNode>(Op)->getIndex(), | 
|  | Known, getMachineFunction()); | 
|  | break; | 
|  |  | 
|  | default: | 
|  | if (Opcode < ISD::BUILTIN_OP_END) | 
|  | break; | 
|  | [[fallthrough]]; | 
|  | case ISD::INTRINSIC_WO_CHAIN: | 
|  | case ISD::INTRINSIC_W_CHAIN: | 
|  | case ISD::INTRINSIC_VOID: | 
|  | // TODO: Probably okay to remove after audit; here to reduce change size | 
|  | // in initial enablement patch for scalable vectors | 
|  | if (Op.getValueType().isScalableVector()) | 
|  | break; | 
|  |  | 
|  | // Allow the target to implement this method for its nodes. | 
|  | TLI->computeKnownBitsForTargetNode(Op, Known, DemandedElts, *this, Depth); | 
|  | break; | 
|  | } | 
|  |  | 
|  | return Known; | 
|  | } | 
|  |  | 
|  | /// Convert ConstantRange OverflowResult into SelectionDAG::OverflowKind. | 
|  | static SelectionDAG::OverflowKind mapOverflowResult(ConstantRange::OverflowResult OR) { | 
|  | switch (OR) { | 
|  | case ConstantRange::OverflowResult::MayOverflow: | 
|  | return SelectionDAG::OFK_Sometime; | 
|  | case ConstantRange::OverflowResult::AlwaysOverflowsLow: | 
|  | case ConstantRange::OverflowResult::AlwaysOverflowsHigh: | 
|  | return SelectionDAG::OFK_Always; | 
|  | case ConstantRange::OverflowResult::NeverOverflows: | 
|  | return SelectionDAG::OFK_Never; | 
|  | } | 
|  | llvm_unreachable("Unknown OverflowResult"); | 
|  | } | 
|  |  | 
|  | SelectionDAG::OverflowKind | 
|  | SelectionDAG::computeOverflowForSignedAdd(SDValue N0, SDValue N1) const { | 
|  | // X + 0 never overflow | 
|  | if (isNullConstant(N1)) | 
|  | return OFK_Never; | 
|  |  | 
|  | // If both operands each have at least two sign bits, the addition | 
|  | // cannot overflow. | 
|  | if (ComputeNumSignBits(N0) > 1 && ComputeNumSignBits(N1) > 1) | 
|  | return OFK_Never; | 
|  |  | 
|  | // TODO: Add ConstantRange::signedAddMayOverflow handling. | 
|  | return OFK_Sometime; | 
|  | } | 
|  |  | 
|  | SelectionDAG::OverflowKind | 
|  | SelectionDAG::computeOverflowForUnsignedAdd(SDValue N0, SDValue N1) const { | 
|  | // X + 0 never overflow | 
|  | if (isNullConstant(N1)) | 
|  | return OFK_Never; | 
|  |  | 
|  | // mulhi + 1 never overflow | 
|  | KnownBits N1Known = computeKnownBits(N1); | 
|  | if (N0.getOpcode() == ISD::UMUL_LOHI && N0.getResNo() == 1 && | 
|  | N1Known.getMaxValue().ult(2)) | 
|  | return OFK_Never; | 
|  |  | 
|  | KnownBits N0Known = computeKnownBits(N0); | 
|  | if (N1.getOpcode() == ISD::UMUL_LOHI && N1.getResNo() == 1 && | 
|  | N0Known.getMaxValue().ult(2)) | 
|  | return OFK_Never; | 
|  |  | 
|  | // Fallback to ConstantRange::unsignedAddMayOverflow handling. | 
|  | ConstantRange N0Range = ConstantRange::fromKnownBits(N0Known, false); | 
|  | ConstantRange N1Range = ConstantRange::fromKnownBits(N1Known, false); | 
|  | return mapOverflowResult(N0Range.unsignedAddMayOverflow(N1Range)); | 
|  | } | 
|  |  | 
|  | SelectionDAG::OverflowKind | 
|  | SelectionDAG::computeOverflowForSignedSub(SDValue N0, SDValue N1) const { | 
|  | // X - 0 never overflow | 
|  | if (isNullConstant(N1)) | 
|  | return OFK_Never; | 
|  |  | 
|  | // If both operands each have at least two sign bits, the subtraction | 
|  | // cannot overflow. | 
|  | if (ComputeNumSignBits(N0) > 1 && ComputeNumSignBits(N1) > 1) | 
|  | return OFK_Never; | 
|  |  | 
|  | KnownBits N0Known = computeKnownBits(N0); | 
|  | KnownBits N1Known = computeKnownBits(N1); | 
|  | ConstantRange N0Range = ConstantRange::fromKnownBits(N0Known, true); | 
|  | ConstantRange N1Range = ConstantRange::fromKnownBits(N1Known, true); | 
|  | return mapOverflowResult(N0Range.signedSubMayOverflow(N1Range)); | 
|  | } | 
|  |  | 
|  | SelectionDAG::OverflowKind | 
|  | SelectionDAG::computeOverflowForUnsignedSub(SDValue N0, SDValue N1) const { | 
|  | // X - 0 never overflow | 
|  | if (isNullConstant(N1)) | 
|  | return OFK_Never; | 
|  |  | 
|  | KnownBits N0Known = computeKnownBits(N0); | 
|  | KnownBits N1Known = computeKnownBits(N1); | 
|  | ConstantRange N0Range = ConstantRange::fromKnownBits(N0Known, false); | 
|  | ConstantRange N1Range = ConstantRange::fromKnownBits(N1Known, false); | 
|  | return mapOverflowResult(N0Range.unsignedSubMayOverflow(N1Range)); | 
|  | } | 
|  |  | 
|  | SelectionDAG::OverflowKind | 
|  | SelectionDAG::computeOverflowForUnsignedMul(SDValue N0, SDValue N1) const { | 
|  | // X * 0 and X * 1 never overflow. | 
|  | if (isNullConstant(N1) || isOneConstant(N1)) | 
|  | return OFK_Never; | 
|  |  | 
|  | KnownBits N0Known = computeKnownBits(N0); | 
|  | KnownBits N1Known = computeKnownBits(N1); | 
|  | ConstantRange N0Range = ConstantRange::fromKnownBits(N0Known, false); | 
|  | ConstantRange N1Range = ConstantRange::fromKnownBits(N1Known, false); | 
|  | return mapOverflowResult(N0Range.unsignedMulMayOverflow(N1Range)); | 
|  | } | 
|  |  | 
|  | SelectionDAG::OverflowKind | 
|  | SelectionDAG::computeOverflowForSignedMul(SDValue N0, SDValue N1) const { | 
|  | // X * 0 and X * 1 never overflow. | 
|  | if (isNullConstant(N1) || isOneConstant(N1)) | 
|  | return OFK_Never; | 
|  |  | 
|  | // Get the size of the result. | 
|  | unsigned BitWidth = N0.getScalarValueSizeInBits(); | 
|  |  | 
|  | // Sum of the sign bits. | 
|  | unsigned SignBits = ComputeNumSignBits(N0) + ComputeNumSignBits(N1); | 
|  |  | 
|  | // If we have enough sign bits, then there's no overflow. | 
|  | if (SignBits > BitWidth + 1) | 
|  | return OFK_Never; | 
|  |  | 
|  | if (SignBits == BitWidth + 1) { | 
|  | // The overflow occurs when the true multiplication of the | 
|  | // the operands is the minimum negative number. | 
|  | KnownBits N0Known = computeKnownBits(N0); | 
|  | KnownBits N1Known = computeKnownBits(N1); | 
|  | // If one of the operands is non-negative, then there's no | 
|  | // overflow. | 
|  | if (N0Known.isNonNegative() || N1Known.isNonNegative()) | 
|  | return OFK_Never; | 
|  | } | 
|  |  | 
|  | return OFK_Sometime; | 
|  | } | 
|  |  | 
|  | bool SelectionDAG::isKnownToBeAPowerOfTwo(SDValue Val, unsigned Depth) const { | 
|  | if (Depth >= MaxRecursionDepth) | 
|  | return false; // Limit search depth. | 
|  |  | 
|  | EVT OpVT = Val.getValueType(); | 
|  | unsigned BitWidth = OpVT.getScalarSizeInBits(); | 
|  |  | 
|  | // Is the constant a known power of 2? | 
|  | if (ISD::matchUnaryPredicate(Val, [BitWidth](ConstantSDNode *C) { | 
|  | return C->getAPIntValue().zextOrTrunc(BitWidth).isPowerOf2(); | 
|  | })) | 
|  | return true; | 
|  |  | 
|  | // A left-shift of a constant one will have exactly one bit set because | 
|  | // shifting the bit off the end is undefined. | 
|  | if (Val.getOpcode() == ISD::SHL) { | 
|  | auto *C = isConstOrConstSplat(Val.getOperand(0)); | 
|  | if (C && C->getAPIntValue() == 1) | 
|  | return true; | 
|  | return isKnownToBeAPowerOfTwo(Val.getOperand(0), Depth + 1) && | 
|  | isKnownNeverZero(Val, Depth); | 
|  | } | 
|  |  | 
|  | // Similarly, a logical right-shift of a constant sign-bit will have exactly | 
|  | // one bit set. | 
|  | if (Val.getOpcode() == ISD::SRL) { | 
|  | auto *C = isConstOrConstSplat(Val.getOperand(0)); | 
|  | if (C && C->getAPIntValue().isSignMask()) | 
|  | return true; | 
|  | return isKnownToBeAPowerOfTwo(Val.getOperand(0), Depth + 1) && | 
|  | isKnownNeverZero(Val, Depth); | 
|  | } | 
|  |  | 
|  | if (Val.getOpcode() == ISD::ROTL || Val.getOpcode() == ISD::ROTR) | 
|  | return isKnownToBeAPowerOfTwo(Val.getOperand(0), Depth + 1); | 
|  |  | 
|  | // Are all operands of a build vector constant powers of two? | 
|  | if (Val.getOpcode() == ISD::BUILD_VECTOR) | 
|  | if (llvm::all_of(Val->ops(), [BitWidth](SDValue E) { | 
|  | if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(E)) | 
|  | return C->getAPIntValue().zextOrTrunc(BitWidth).isPowerOf2(); | 
|  | return false; | 
|  | })) | 
|  | return true; | 
|  |  | 
|  | // Is the operand of a splat vector a constant power of two? | 
|  | if (Val.getOpcode() == ISD::SPLAT_VECTOR) | 
|  | if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Val->getOperand(0))) | 
|  | if (C->getAPIntValue().zextOrTrunc(BitWidth).isPowerOf2()) | 
|  | return true; | 
|  |  | 
|  | // vscale(power-of-two) is a power-of-two for some targets | 
|  | if (Val.getOpcode() == ISD::VSCALE && | 
|  | getTargetLoweringInfo().isVScaleKnownToBeAPowerOfTwo() && | 
|  | isKnownToBeAPowerOfTwo(Val.getOperand(0), Depth + 1)) | 
|  | return true; | 
|  |  | 
|  | if (Val.getOpcode() == ISD::SMIN || Val.getOpcode() == ISD::SMAX || | 
|  | Val.getOpcode() == ISD::UMIN || Val.getOpcode() == ISD::UMAX) | 
|  | return isKnownToBeAPowerOfTwo(Val.getOperand(1), Depth + 1) && | 
|  | isKnownToBeAPowerOfTwo(Val.getOperand(0), Depth + 1); | 
|  |  | 
|  | if (Val.getOpcode() == ISD::SELECT || Val.getOpcode() == ISD::VSELECT) | 
|  | return isKnownToBeAPowerOfTwo(Val.getOperand(2), Depth + 1) && | 
|  | isKnownToBeAPowerOfTwo(Val.getOperand(1), Depth + 1); | 
|  |  | 
|  | // Looking for `x & -x` pattern: | 
|  | // If x == 0: | 
|  | //    x & -x -> 0 | 
|  | // If x != 0: | 
|  | //    x & -x -> non-zero pow2 | 
|  | // so if we find the pattern return whether we know `x` is non-zero. | 
|  | SDValue X; | 
|  | if (sd_match(Val, m_And(m_Value(X), m_Neg(m_Deferred(X))))) | 
|  | return isKnownNeverZero(X, Depth); | 
|  |  | 
|  | if (Val.getOpcode() == ISD::ZERO_EXTEND) | 
|  | return isKnownToBeAPowerOfTwo(Val.getOperand(0), Depth + 1); | 
|  |  | 
|  | // More could be done here, though the above checks are enough | 
|  | // to handle some common cases. | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool SelectionDAG::isKnownToBeAPowerOfTwoFP(SDValue Val, unsigned Depth) const { | 
|  | if (ConstantFPSDNode *C1 = isConstOrConstSplatFP(Val, true)) | 
|  | return C1->getValueAPF().getExactLog2Abs() >= 0; | 
|  |  | 
|  | if (Val.getOpcode() == ISD::UINT_TO_FP || Val.getOpcode() == ISD::SINT_TO_FP) | 
|  | return isKnownToBeAPowerOfTwo(Val.getOperand(0), Depth + 1); | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | unsigned SelectionDAG::ComputeNumSignBits(SDValue Op, unsigned Depth) const { | 
|  | EVT VT = Op.getValueType(); | 
|  |  | 
|  | // Since the number of lanes in a scalable vector is unknown at compile time, | 
|  | // we track one bit which is implicitly broadcast to all lanes.  This means | 
|  | // that all lanes in a scalable vector are considered demanded. | 
|  | APInt DemandedElts = VT.isFixedLengthVector() | 
|  | ? APInt::getAllOnes(VT.getVectorNumElements()) | 
|  | : APInt(1, 1); | 
|  | return ComputeNumSignBits(Op, DemandedElts, Depth); | 
|  | } | 
|  |  | 
|  | unsigned SelectionDAG::ComputeNumSignBits(SDValue Op, const APInt &DemandedElts, | 
|  | unsigned Depth) const { | 
|  | EVT VT = Op.getValueType(); | 
|  | assert((VT.isInteger() || VT.isFloatingPoint()) && "Invalid VT!"); | 
|  | unsigned VTBits = VT.getScalarSizeInBits(); | 
|  | unsigned NumElts = DemandedElts.getBitWidth(); | 
|  | unsigned Tmp, Tmp2; | 
|  | unsigned FirstAnswer = 1; | 
|  |  | 
|  | if (auto *C = dyn_cast<ConstantSDNode>(Op)) { | 
|  | const APInt &Val = C->getAPIntValue(); | 
|  | return Val.getNumSignBits(); | 
|  | } | 
|  |  | 
|  | if (Depth >= MaxRecursionDepth) | 
|  | return 1;  // Limit search depth. | 
|  |  | 
|  | if (!DemandedElts) | 
|  | return 1;  // No demanded elts, better to assume we don't know anything. | 
|  |  | 
|  | unsigned Opcode = Op.getOpcode(); | 
|  | switch (Opcode) { | 
|  | default: break; | 
|  | case ISD::AssertSext: | 
|  | Tmp = cast<VTSDNode>(Op.getOperand(1))->getVT().getSizeInBits(); | 
|  | return VTBits-Tmp+1; | 
|  | case ISD::AssertZext: | 
|  | Tmp = cast<VTSDNode>(Op.getOperand(1))->getVT().getSizeInBits(); | 
|  | return VTBits-Tmp; | 
|  | case ISD::MERGE_VALUES: | 
|  | return ComputeNumSignBits(Op.getOperand(Op.getResNo()), DemandedElts, | 
|  | Depth + 1); | 
|  | case ISD::SPLAT_VECTOR: { | 
|  | // Check if the sign bits of source go down as far as the truncated value. | 
|  | unsigned NumSrcBits = Op.getOperand(0).getValueSizeInBits(); | 
|  | unsigned NumSrcSignBits = ComputeNumSignBits(Op.getOperand(0), Depth + 1); | 
|  | if (NumSrcSignBits > (NumSrcBits - VTBits)) | 
|  | return NumSrcSignBits - (NumSrcBits - VTBits); | 
|  | break; | 
|  | } | 
|  | case ISD::BUILD_VECTOR: | 
|  | assert(!VT.isScalableVector()); | 
|  | Tmp = VTBits; | 
|  | for (unsigned i = 0, e = Op.getNumOperands(); (i < e) && (Tmp > 1); ++i) { | 
|  | if (!DemandedElts[i]) | 
|  | continue; | 
|  |  | 
|  | SDValue SrcOp = Op.getOperand(i); | 
|  | // BUILD_VECTOR can implicitly truncate sources, we handle this specially | 
|  | // for constant nodes to ensure we only look at the sign bits. | 
|  | if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(SrcOp)) { | 
|  | APInt T = C->getAPIntValue().trunc(VTBits); | 
|  | Tmp2 = T.getNumSignBits(); | 
|  | } else { | 
|  | Tmp2 = ComputeNumSignBits(SrcOp, Depth + 1); | 
|  |  | 
|  | if (SrcOp.getValueSizeInBits() != VTBits) { | 
|  | assert(SrcOp.getValueSizeInBits() > VTBits && | 
|  | "Expected BUILD_VECTOR implicit truncation"); | 
|  | unsigned ExtraBits = SrcOp.getValueSizeInBits() - VTBits; | 
|  | Tmp2 = (Tmp2 > ExtraBits ? Tmp2 - ExtraBits : 1); | 
|  | } | 
|  | } | 
|  | Tmp = std::min(Tmp, Tmp2); | 
|  | } | 
|  | return Tmp; | 
|  |  | 
|  | case ISD::VECTOR_SHUFFLE: { | 
|  | // Collect the minimum number of sign bits that are shared by every vector | 
|  | // element referenced by the shuffle. | 
|  | APInt DemandedLHS, DemandedRHS; | 
|  | const ShuffleVectorSDNode *SVN = cast<ShuffleVectorSDNode>(Op); | 
|  | assert(NumElts == SVN->getMask().size() && "Unexpected vector size"); | 
|  | if (!getShuffleDemandedElts(NumElts, SVN->getMask(), DemandedElts, | 
|  | DemandedLHS, DemandedRHS)) | 
|  | return 1; | 
|  |  | 
|  | Tmp = std::numeric_limits<unsigned>::max(); | 
|  | if (!!DemandedLHS) | 
|  | Tmp = ComputeNumSignBits(Op.getOperand(0), DemandedLHS, Depth + 1); | 
|  | if (!!DemandedRHS) { | 
|  | Tmp2 = ComputeNumSignBits(Op.getOperand(1), DemandedRHS, Depth + 1); | 
|  | Tmp = std::min(Tmp, Tmp2); | 
|  | } | 
|  | // If we don't know anything, early out and try computeKnownBits fall-back. | 
|  | if (Tmp == 1) | 
|  | break; | 
|  | assert(Tmp <= VTBits && "Failed to determine minimum sign bits"); | 
|  | return Tmp; | 
|  | } | 
|  |  | 
|  | case ISD::BITCAST: { | 
|  | if (VT.isScalableVector()) | 
|  | break; | 
|  | SDValue N0 = Op.getOperand(0); | 
|  | EVT SrcVT = N0.getValueType(); | 
|  | unsigned SrcBits = SrcVT.getScalarSizeInBits(); | 
|  |  | 
|  | // Ignore bitcasts from unsupported types.. | 
|  | if (!(SrcVT.isInteger() || SrcVT.isFloatingPoint())) | 
|  | break; | 
|  |  | 
|  | // Fast handling of 'identity' bitcasts. | 
|  | if (VTBits == SrcBits) | 
|  | return ComputeNumSignBits(N0, DemandedElts, Depth + 1); | 
|  |  | 
|  | bool IsLE = getDataLayout().isLittleEndian(); | 
|  |  | 
|  | // Bitcast 'large element' scalar/vector to 'small element' vector. | 
|  | if ((SrcBits % VTBits) == 0) { | 
|  | assert(VT.isVector() && "Expected bitcast to vector"); | 
|  |  | 
|  | unsigned Scale = SrcBits / VTBits; | 
|  | APInt SrcDemandedElts = | 
|  | APIntOps::ScaleBitMask(DemandedElts, NumElts / Scale); | 
|  |  | 
|  | // Fast case - sign splat can be simply split across the small elements. | 
|  | Tmp = ComputeNumSignBits(N0, SrcDemandedElts, Depth + 1); | 
|  | if (Tmp == SrcBits) | 
|  | return VTBits; | 
|  |  | 
|  | // Slow case - determine how far the sign extends into each sub-element. | 
|  | Tmp2 = VTBits; | 
|  | for (unsigned i = 0; i != NumElts; ++i) | 
|  | if (DemandedElts[i]) { | 
|  | unsigned SubOffset = i % Scale; | 
|  | SubOffset = (IsLE ? ((Scale - 1) - SubOffset) : SubOffset); | 
|  | SubOffset = SubOffset * VTBits; | 
|  | if (Tmp <= SubOffset) | 
|  | return 1; | 
|  | Tmp2 = std::min(Tmp2, Tmp - SubOffset); | 
|  | } | 
|  | return Tmp2; | 
|  | } | 
|  | break; | 
|  | } | 
|  |  | 
|  | case ISD::FP_TO_SINT_SAT: | 
|  | // FP_TO_SINT_SAT produces a signed value that fits in the saturating VT. | 
|  | Tmp = cast<VTSDNode>(Op.getOperand(1))->getVT().getScalarSizeInBits(); | 
|  | return VTBits - Tmp + 1; | 
|  | case ISD::SIGN_EXTEND: | 
|  | Tmp = VTBits - Op.getOperand(0).getScalarValueSizeInBits(); | 
|  | return ComputeNumSignBits(Op.getOperand(0), DemandedElts, Depth+1) + Tmp; | 
|  | case ISD::SIGN_EXTEND_INREG: | 
|  | // Max of the input and what this extends. | 
|  | Tmp = cast<VTSDNode>(Op.getOperand(1))->getVT().getScalarSizeInBits(); | 
|  | Tmp = VTBits-Tmp+1; | 
|  | Tmp2 = ComputeNumSignBits(Op.getOperand(0), DemandedElts, Depth+1); | 
|  | return std::max(Tmp, Tmp2); | 
|  | case ISD::SIGN_EXTEND_VECTOR_INREG: { | 
|  | if (VT.isScalableVector()) | 
|  | break; | 
|  | SDValue Src = Op.getOperand(0); | 
|  | EVT SrcVT = Src.getValueType(); | 
|  | APInt DemandedSrcElts = DemandedElts.zext(SrcVT.getVectorNumElements()); | 
|  | Tmp = VTBits - SrcVT.getScalarSizeInBits(); | 
|  | return ComputeNumSignBits(Src, DemandedSrcElts, Depth+1) + Tmp; | 
|  | } | 
|  | case ISD::SRA: | 
|  | Tmp = ComputeNumSignBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | // SRA X, C -> adds C sign bits. | 
|  | if (std::optional<unsigned> ShAmt = | 
|  | getValidMinimumShiftAmount(Op, DemandedElts, Depth + 1)) | 
|  | Tmp = std::min(Tmp + *ShAmt, VTBits); | 
|  | return Tmp; | 
|  | case ISD::SHL: | 
|  | if (std::optional<ConstantRange> ShAmtRange = | 
|  | getValidShiftAmountRange(Op, DemandedElts, Depth + 1)) { | 
|  | unsigned MaxShAmt = ShAmtRange->getUnsignedMax().getZExtValue(); | 
|  | unsigned MinShAmt = ShAmtRange->getUnsignedMin().getZExtValue(); | 
|  | // Try to look through ZERO/SIGN/ANY_EXTEND. If all extended bits are | 
|  | // shifted out, then we can compute the number of sign bits for the | 
|  | // operand being extended. A future improvement could be to pass along the | 
|  | // "shifted left by" information in the recursive calls to | 
|  | // ComputeKnownSignBits. Allowing us to handle this more generically. | 
|  | if (ISD::isExtOpcode(Op.getOperand(0).getOpcode())) { | 
|  | SDValue Ext = Op.getOperand(0); | 
|  | EVT ExtVT = Ext.getValueType(); | 
|  | SDValue Extendee = Ext.getOperand(0); | 
|  | EVT ExtendeeVT = Extendee.getValueType(); | 
|  | unsigned SizeDifference = | 
|  | ExtVT.getScalarSizeInBits() - ExtendeeVT.getScalarSizeInBits(); | 
|  | if (SizeDifference <= MinShAmt) { | 
|  | Tmp = SizeDifference + | 
|  | ComputeNumSignBits(Extendee, DemandedElts, Depth + 1); | 
|  | if (MaxShAmt < Tmp) | 
|  | return Tmp - MaxShAmt; | 
|  | } | 
|  | } | 
|  | // shl destroys sign bits, ensure it doesn't shift out all sign bits. | 
|  | Tmp = ComputeNumSignBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | if (MaxShAmt < Tmp) | 
|  | return Tmp - MaxShAmt; | 
|  | } | 
|  | break; | 
|  | case ISD::AND: | 
|  | case ISD::OR: | 
|  | case ISD::XOR:    // NOT is handled here. | 
|  | // Logical binary ops preserve the number of sign bits at the worst. | 
|  | Tmp = ComputeNumSignBits(Op.getOperand(0), DemandedElts, Depth+1); | 
|  | if (Tmp != 1) { | 
|  | Tmp2 = ComputeNumSignBits(Op.getOperand(1), DemandedElts, Depth+1); | 
|  | FirstAnswer = std::min(Tmp, Tmp2); | 
|  | // We computed what we know about the sign bits as our first | 
|  | // answer. Now proceed to the generic code that uses | 
|  | // computeKnownBits, and pick whichever answer is better. | 
|  | } | 
|  | break; | 
|  |  | 
|  | case ISD::SELECT: | 
|  | case ISD::VSELECT: | 
|  | Tmp = ComputeNumSignBits(Op.getOperand(1), DemandedElts, Depth+1); | 
|  | if (Tmp == 1) return 1;  // Early out. | 
|  | Tmp2 = ComputeNumSignBits(Op.getOperand(2), DemandedElts, Depth+1); | 
|  | return std::min(Tmp, Tmp2); | 
|  | case ISD::SELECT_CC: | 
|  | Tmp = ComputeNumSignBits(Op.getOperand(2), DemandedElts, Depth+1); | 
|  | if (Tmp == 1) return 1;  // Early out. | 
|  | Tmp2 = ComputeNumSignBits(Op.getOperand(3), DemandedElts, Depth+1); | 
|  | return std::min(Tmp, Tmp2); | 
|  |  | 
|  | case ISD::SMIN: | 
|  | case ISD::SMAX: { | 
|  | // If we have a clamp pattern, we know that the number of sign bits will be | 
|  | // the minimum of the clamp min/max range. | 
|  | bool IsMax = (Opcode == ISD::SMAX); | 
|  | ConstantSDNode *CstLow = nullptr, *CstHigh = nullptr; | 
|  | if ((CstLow = isConstOrConstSplat(Op.getOperand(1), DemandedElts))) | 
|  | if (Op.getOperand(0).getOpcode() == (IsMax ? ISD::SMIN : ISD::SMAX)) | 
|  | CstHigh = | 
|  | isConstOrConstSplat(Op.getOperand(0).getOperand(1), DemandedElts); | 
|  | if (CstLow && CstHigh) { | 
|  | if (!IsMax) | 
|  | std::swap(CstLow, CstHigh); | 
|  | if (CstLow->getAPIntValue().sle(CstHigh->getAPIntValue())) { | 
|  | Tmp = CstLow->getAPIntValue().getNumSignBits(); | 
|  | Tmp2 = CstHigh->getAPIntValue().getNumSignBits(); | 
|  | return std::min(Tmp, Tmp2); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Fallback - just get the minimum number of sign bits of the operands. | 
|  | Tmp = ComputeNumSignBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | if (Tmp == 1) | 
|  | return 1;  // Early out. | 
|  | Tmp2 = ComputeNumSignBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | return std::min(Tmp, Tmp2); | 
|  | } | 
|  | case ISD::UMIN: | 
|  | case ISD::UMAX: | 
|  | Tmp = ComputeNumSignBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | if (Tmp == 1) | 
|  | return 1;  // Early out. | 
|  | Tmp2 = ComputeNumSignBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | return std::min(Tmp, Tmp2); | 
|  | case ISD::SSUBO_CARRY: | 
|  | case ISD::USUBO_CARRY: | 
|  | // sub_carry(x,x,c) -> 0/-1 (sext carry) | 
|  | if (Op.getResNo() == 0 && Op.getOperand(0) == Op.getOperand(1)) | 
|  | return VTBits; | 
|  | [[fallthrough]]; | 
|  | case ISD::SADDO: | 
|  | case ISD::UADDO: | 
|  | case ISD::SADDO_CARRY: | 
|  | case ISD::UADDO_CARRY: | 
|  | case ISD::SSUBO: | 
|  | case ISD::USUBO: | 
|  | case ISD::SMULO: | 
|  | case ISD::UMULO: | 
|  | if (Op.getResNo() != 1) | 
|  | break; | 
|  | // The boolean result conforms to getBooleanContents.  Fall through. | 
|  | // If setcc returns 0/-1, all bits are sign bits. | 
|  | // We know that we have an integer-based boolean since these operations | 
|  | // are only available for integer. | 
|  | if (TLI->getBooleanContents(VT.isVector(), false) == | 
|  | TargetLowering::ZeroOrNegativeOneBooleanContent) | 
|  | return VTBits; | 
|  | break; | 
|  | case ISD::SETCC: | 
|  | case ISD::SETCCCARRY: | 
|  | case ISD::STRICT_FSETCC: | 
|  | case ISD::STRICT_FSETCCS: { | 
|  | unsigned OpNo = Op->isStrictFPOpcode() ? 1 : 0; | 
|  | // If setcc returns 0/-1, all bits are sign bits. | 
|  | if (TLI->getBooleanContents(Op.getOperand(OpNo).getValueType()) == | 
|  | TargetLowering::ZeroOrNegativeOneBooleanContent) | 
|  | return VTBits; | 
|  | break; | 
|  | } | 
|  | case ISD::ROTL: | 
|  | case ISD::ROTR: | 
|  | Tmp = ComputeNumSignBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  |  | 
|  | // If we're rotating an 0/-1 value, then it stays an 0/-1 value. | 
|  | if (Tmp == VTBits) | 
|  | return VTBits; | 
|  |  | 
|  | if (ConstantSDNode *C = | 
|  | isConstOrConstSplat(Op.getOperand(1), DemandedElts)) { | 
|  | unsigned RotAmt = C->getAPIntValue().urem(VTBits); | 
|  |  | 
|  | // Handle rotate right by N like a rotate left by 32-N. | 
|  | if (Opcode == ISD::ROTR) | 
|  | RotAmt = (VTBits - RotAmt) % VTBits; | 
|  |  | 
|  | // If we aren't rotating out all of the known-in sign bits, return the | 
|  | // number that are left.  This handles rotl(sext(x), 1) for example. | 
|  | if (Tmp > (RotAmt + 1)) return (Tmp - RotAmt); | 
|  | } | 
|  | break; | 
|  | case ISD::ADD: | 
|  | case ISD::ADDC: | 
|  | // Add can have at most one carry bit.  Thus we know that the output | 
|  | // is, at worst, one more bit than the inputs. | 
|  | Tmp = ComputeNumSignBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | if (Tmp == 1) return 1; // Early out. | 
|  |  | 
|  | // Special case decrementing a value (ADD X, -1): | 
|  | if (ConstantSDNode *CRHS = | 
|  | isConstOrConstSplat(Op.getOperand(1), DemandedElts)) | 
|  | if (CRHS->isAllOnes()) { | 
|  | KnownBits Known = | 
|  | computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  |  | 
|  | // If the input is known to be 0 or 1, the output is 0/-1, which is all | 
|  | // sign bits set. | 
|  | if ((Known.Zero | 1).isAllOnes()) | 
|  | return VTBits; | 
|  |  | 
|  | // If we are subtracting one from a positive number, there is no carry | 
|  | // out of the result. | 
|  | if (Known.isNonNegative()) | 
|  | return Tmp; | 
|  | } | 
|  |  | 
|  | Tmp2 = ComputeNumSignBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | if (Tmp2 == 1) return 1; // Early out. | 
|  | return std::min(Tmp, Tmp2) - 1; | 
|  | case ISD::SUB: | 
|  | Tmp2 = ComputeNumSignBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | if (Tmp2 == 1) return 1; // Early out. | 
|  |  | 
|  | // Handle NEG. | 
|  | if (ConstantSDNode *CLHS = | 
|  | isConstOrConstSplat(Op.getOperand(0), DemandedElts)) | 
|  | if (CLHS->isZero()) { | 
|  | KnownBits Known = | 
|  | computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | // If the input is known to be 0 or 1, the output is 0/-1, which is all | 
|  | // sign bits set. | 
|  | if ((Known.Zero | 1).isAllOnes()) | 
|  | return VTBits; | 
|  |  | 
|  | // If the input is known to be positive (the sign bit is known clear), | 
|  | // the output of the NEG has the same number of sign bits as the input. | 
|  | if (Known.isNonNegative()) | 
|  | return Tmp2; | 
|  |  | 
|  | // Otherwise, we treat this like a SUB. | 
|  | } | 
|  |  | 
|  | // Sub can have at most one carry bit.  Thus we know that the output | 
|  | // is, at worst, one more bit than the inputs. | 
|  | Tmp = ComputeNumSignBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | if (Tmp == 1) return 1; // Early out. | 
|  | return std::min(Tmp, Tmp2) - 1; | 
|  | case ISD::MUL: { | 
|  | // The output of the Mul can be at most twice the valid bits in the inputs. | 
|  | unsigned SignBitsOp0 = ComputeNumSignBits(Op.getOperand(0), Depth + 1); | 
|  | if (SignBitsOp0 == 1) | 
|  | break; | 
|  | unsigned SignBitsOp1 = ComputeNumSignBits(Op.getOperand(1), Depth + 1); | 
|  | if (SignBitsOp1 == 1) | 
|  | break; | 
|  | unsigned OutValidBits = | 
|  | (VTBits - SignBitsOp0 + 1) + (VTBits - SignBitsOp1 + 1); | 
|  | return OutValidBits > VTBits ? 1 : VTBits - OutValidBits + 1; | 
|  | } | 
|  | case ISD::AVGCEILS: | 
|  | case ISD::AVGFLOORS: | 
|  | Tmp = ComputeNumSignBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | if (Tmp == 1) | 
|  | return 1; // Early out. | 
|  | Tmp2 = ComputeNumSignBits(Op.getOperand(1), DemandedElts, Depth + 1); | 
|  | return std::min(Tmp, Tmp2); | 
|  | case ISD::SREM: | 
|  | // The sign bit is the LHS's sign bit, except when the result of the | 
|  | // remainder is zero. The magnitude of the result should be less than or | 
|  | // equal to the magnitude of the LHS. Therefore, the result should have | 
|  | // at least as many sign bits as the left hand side. | 
|  | return ComputeNumSignBits(Op.getOperand(0), DemandedElts, Depth + 1); | 
|  | case ISD::TRUNCATE: { | 
|  | // Check if the sign bits of source go down as far as the truncated value. | 
|  | unsigned NumSrcBits = Op.getOperand(0).getScalarValueSizeInBits(); | 
|  | unsigned NumSrcSignBits = ComputeNumSignBits(Op.getOperand(0), Depth + 1); | 
|  | if (NumSrcSignBits > (NumSrcBits - VTBits)) | 
|  | return NumSrcSignBits - (NumSrcBits - VTBits); | 
|  | break; | 
|  | } | 
|  | case ISD::EXTRACT_ELEMENT: { | 
|  | if (VT.isScalableVector()) | 
|  | break; | 
|  | const int KnownSign = ComputeNumSignBits(Op.getOperand(0), Depth+1); | 
|  | const int BitWidth = Op.getValueSizeInBits(); | 
|  | const int Items = Op.getOperand(0).getValueSizeInBits() / BitWidth; | 
|  |  | 
|  | // Get reverse index (starting from 1), Op1 value indexes elements from | 
|  | // little end. Sign starts at big end. | 
|  | const int rIndex = Items - 1 - Op.getConstantOperandVal(1); | 
|  |  | 
|  | // If the sign portion ends in our element the subtraction gives correct | 
|  | // result. Otherwise it gives either negative or > bitwidth result | 
|  | return std::clamp(KnownSign - rIndex * BitWidth, 1, BitWidth); | 
|  | } | 
|  | case ISD::INSERT_VECTOR_ELT: { | 
|  | if (VT.isScalableVector()) | 
|  | break; | 
|  | // If we know the element index, split the demand between the | 
|  | // source vector and the inserted element, otherwise assume we need | 
|  | // the original demanded vector elements and the value. | 
|  | SDValue InVec = Op.getOperand(0); | 
|  | SDValue InVal = Op.getOperand(1); | 
|  | SDValue EltNo = Op.getOperand(2); | 
|  | bool DemandedVal = true; | 
|  | APInt DemandedVecElts = DemandedElts; | 
|  | auto *CEltNo = dyn_cast<ConstantSDNode>(EltNo); | 
|  | if (CEltNo && CEltNo->getAPIntValue().ult(NumElts)) { | 
|  | unsigned EltIdx = CEltNo->getZExtValue(); | 
|  | DemandedVal = !!DemandedElts[EltIdx]; | 
|  | DemandedVecElts.clearBit(EltIdx); | 
|  | } | 
|  | Tmp = std::numeric_limits<unsigned>::max(); | 
|  | if (DemandedVal) { | 
|  | // TODO - handle implicit truncation of inserted elements. | 
|  | if (InVal.getScalarValueSizeInBits() != VTBits) | 
|  | break; | 
|  | Tmp2 = ComputeNumSignBits(InVal, Depth + 1); | 
|  | Tmp = std::min(Tmp, Tmp2); | 
|  | } | 
|  | if (!!DemandedVecElts) { | 
|  | Tmp2 = ComputeNumSignBits(InVec, DemandedVecElts, Depth + 1); | 
|  | Tmp = std::min(Tmp, Tmp2); | 
|  | } | 
|  | assert(Tmp <= VTBits && "Failed to determine minimum sign bits"); | 
|  | return Tmp; | 
|  | } | 
|  | case ISD::EXTRACT_VECTOR_ELT: { | 
|  | assert(!VT.isScalableVector()); | 
|  | SDValue InVec = Op.getOperand(0); | 
|  | SDValue EltNo = Op.getOperand(1); | 
|  | EVT VecVT = InVec.getValueType(); | 
|  | // ComputeNumSignBits not yet implemented for scalable vectors. | 
|  | if (VecVT.isScalableVector()) | 
|  | break; | 
|  | const unsigned BitWidth = Op.getValueSizeInBits(); | 
|  | const unsigned EltBitWidth = Op.getOperand(0).getScalarValueSizeInBits(); | 
|  | const unsigned NumSrcElts = VecVT.getVectorNumElements(); | 
|  |  | 
|  | // If BitWidth > EltBitWidth the value is anyext:ed, and we do not know | 
|  | // anything about sign bits. But if the sizes match we can derive knowledge | 
|  | // about sign bits from the vector operand. | 
|  | if (BitWidth != EltBitWidth) | 
|  | break; | 
|  |  | 
|  | // If we know the element index, just demand that vector element, else for | 
|  | // an unknown element index, ignore DemandedElts and demand them all. | 
|  | APInt DemandedSrcElts = APInt::getAllOnes(NumSrcElts); | 
|  | auto *ConstEltNo = dyn_cast<ConstantSDNode>(EltNo); | 
|  | if (ConstEltNo && ConstEltNo->getAPIntValue().ult(NumSrcElts)) | 
|  | DemandedSrcElts = | 
|  | APInt::getOneBitSet(NumSrcElts, ConstEltNo->getZExtValue()); | 
|  |  | 
|  | return ComputeNumSignBits(InVec, DemandedSrcElts, Depth + 1); | 
|  | } | 
|  | case ISD::EXTRACT_SUBVECTOR: { | 
|  | // Offset the demanded elts by the subvector index. | 
|  | SDValue Src = Op.getOperand(0); | 
|  | // Bail until we can represent demanded elements for scalable vectors. | 
|  | if (Src.getValueType().isScalableVector()) | 
|  | break; | 
|  | uint64_t Idx = Op.getConstantOperandVal(1); | 
|  | unsigned NumSrcElts = Src.getValueType().getVectorNumElements(); | 
|  | APInt DemandedSrcElts = DemandedElts.zext(NumSrcElts).shl(Idx); | 
|  | return ComputeNumSignBits(Src, DemandedSrcElts, Depth + 1); | 
|  | } | 
|  | case ISD::CONCAT_VECTORS: { | 
|  | if (VT.isScalableVector()) | 
|  | break; | 
|  | // Determine the minimum number of sign bits across all demanded | 
|  | // elts of the input vectors. Early out if the result is already 1. | 
|  | Tmp = std::numeric_limits<unsigned>::max(); | 
|  | EVT SubVectorVT = Op.getOperand(0).getValueType(); | 
|  | unsigned NumSubVectorElts = SubVectorVT.getVectorNumElements(); | 
|  | unsigned NumSubVectors = Op.getNumOperands(); | 
|  | for (unsigned i = 0; (i < NumSubVectors) && (Tmp > 1); ++i) { | 
|  | APInt DemandedSub = | 
|  | DemandedElts.extractBits(NumSubVectorElts, i * NumSubVectorElts); | 
|  | if (!DemandedSub) | 
|  | continue; | 
|  | Tmp2 = ComputeNumSignBits(Op.getOperand(i), DemandedSub, Depth + 1); | 
|  | Tmp = std::min(Tmp, Tmp2); | 
|  | } | 
|  | assert(Tmp <= VTBits && "Failed to determine minimum sign bits"); | 
|  | return Tmp; | 
|  | } | 
|  | case ISD::INSERT_SUBVECTOR: { | 
|  | if (VT.isScalableVector()) | 
|  | break; | 
|  | // Demand any elements from the subvector and the remainder from the src its | 
|  | // inserted into. | 
|  | SDValue Src = Op.getOperand(0); | 
|  | SDValue Sub = Op.getOperand(1); | 
|  | uint64_t Idx = Op.getConstantOperandVal(2); | 
|  | unsigned NumSubElts = Sub.getValueType().getVectorNumElements(); | 
|  | APInt DemandedSubElts = DemandedElts.extractBits(NumSubElts, Idx); | 
|  | APInt DemandedSrcElts = DemandedElts; | 
|  | DemandedSrcElts.clearBits(Idx, Idx + NumSubElts); | 
|  |  | 
|  | Tmp = std::numeric_limits<unsigned>::max(); | 
|  | if (!!DemandedSubElts) { | 
|  | Tmp = ComputeNumSignBits(Sub, DemandedSubElts, Depth + 1); | 
|  | if (Tmp == 1) | 
|  | return 1; // early-out | 
|  | } | 
|  | if (!!DemandedSrcElts) { | 
|  | Tmp2 = ComputeNumSignBits(Src, DemandedSrcElts, Depth + 1); | 
|  | Tmp = std::min(Tmp, Tmp2); | 
|  | } | 
|  | assert(Tmp <= VTBits && "Failed to determine minimum sign bits"); | 
|  | return Tmp; | 
|  | } | 
|  | case ISD::LOAD: { | 
|  | LoadSDNode *LD = cast<LoadSDNode>(Op); | 
|  | if (const MDNode *Ranges = LD->getRanges()) { | 
|  | if (DemandedElts != 1) | 
|  | break; | 
|  |  | 
|  | ConstantRange CR = getConstantRangeFromMetadata(*Ranges); | 
|  | if (VTBits > CR.getBitWidth()) { | 
|  | switch (LD->getExtensionType()) { | 
|  | case ISD::SEXTLOAD: | 
|  | CR = CR.signExtend(VTBits); | 
|  | break; | 
|  | case ISD::ZEXTLOAD: | 
|  | CR = CR.zeroExtend(VTBits); | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (VTBits != CR.getBitWidth()) | 
|  | break; | 
|  | return std::min(CR.getSignedMin().getNumSignBits(), | 
|  | CR.getSignedMax().getNumSignBits()); | 
|  | } | 
|  |  | 
|  | break; | 
|  | } | 
|  | case ISD::ATOMIC_CMP_SWAP: | 
|  | case ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS: | 
|  | case ISD::ATOMIC_SWAP: | 
|  | case ISD::ATOMIC_LOAD_ADD: | 
|  | case ISD::ATOMIC_LOAD_SUB: | 
|  | case ISD::ATOMIC_LOAD_AND: | 
|  | case ISD::ATOMIC_LOAD_CLR: | 
|  | case ISD::ATOMIC_LOAD_OR: | 
|  | case ISD::ATOMIC_LOAD_XOR: | 
|  | case ISD::ATOMIC_LOAD_NAND: | 
|  | case ISD::ATOMIC_LOAD_MIN: | 
|  | case ISD::ATOMIC_LOAD_MAX: | 
|  | case ISD::ATOMIC_LOAD_UMIN: | 
|  | case ISD::ATOMIC_LOAD_UMAX: | 
|  | case ISD::ATOMIC_LOAD: { | 
|  | auto *AT = cast<AtomicSDNode>(Op); | 
|  | // If we are looking at the loaded value. | 
|  | if (Op.getResNo() == 0) { | 
|  | Tmp = AT->getMemoryVT().getScalarSizeInBits(); | 
|  | if (Tmp == VTBits) | 
|  | return 1; // early-out | 
|  |  | 
|  | // For atomic_load, prefer to use the extension type. | 
|  | if (Op->getOpcode() == ISD::ATOMIC_LOAD) { | 
|  | switch (AT->getExtensionType()) { | 
|  | default: | 
|  | break; | 
|  | case ISD::SEXTLOAD: | 
|  | return VTBits - Tmp + 1; | 
|  | case ISD::ZEXTLOAD: | 
|  | return VTBits - Tmp; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (TLI->getExtendForAtomicOps() == ISD::SIGN_EXTEND) | 
|  | return VTBits - Tmp + 1; | 
|  | if (TLI->getExtendForAtomicOps() == ISD::ZERO_EXTEND) | 
|  | return VTBits - Tmp; | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | // If we are looking at the loaded value of the SDNode. | 
|  | if (Op.getResNo() == 0) { | 
|  | // Handle LOADX separately here. EXTLOAD case will fallthrough. | 
|  | if (LoadSDNode *LD = dyn_cast<LoadSDNode>(Op)) { | 
|  | unsigned ExtType = LD->getExtensionType(); | 
|  | switch (ExtType) { | 
|  | default: break; | 
|  | case ISD::SEXTLOAD: // e.g. i16->i32 = '17' bits known. | 
|  | Tmp = LD->getMemoryVT().getScalarSizeInBits(); | 
|  | return VTBits - Tmp + 1; | 
|  | case ISD::ZEXTLOAD: // e.g. i16->i32 = '16' bits known. | 
|  | Tmp = LD->getMemoryVT().getScalarSizeInBits(); | 
|  | return VTBits - Tmp; | 
|  | case ISD::NON_EXTLOAD: | 
|  | if (const Constant *Cst = TLI->getTargetConstantFromLoad(LD)) { | 
|  | // We only need to handle vectors - computeKnownBits should handle | 
|  | // scalar cases. | 
|  | Type *CstTy = Cst->getType(); | 
|  | if (CstTy->isVectorTy() && !VT.isScalableVector() && | 
|  | (NumElts * VTBits) == CstTy->getPrimitiveSizeInBits() && | 
|  | VTBits == CstTy->getScalarSizeInBits()) { | 
|  | Tmp = VTBits; | 
|  | for (unsigned i = 0; i != NumElts; ++i) { | 
|  | if (!DemandedElts[i]) | 
|  | continue; | 
|  | if (Constant *Elt = Cst->getAggregateElement(i)) { | 
|  | if (auto *CInt = dyn_cast<ConstantInt>(Elt)) { | 
|  | const APInt &Value = CInt->getValue(); | 
|  | Tmp = std::min(Tmp, Value.getNumSignBits()); | 
|  | continue; | 
|  | } | 
|  | if (auto *CFP = dyn_cast<ConstantFP>(Elt)) { | 
|  | APInt Value = CFP->getValueAPF().bitcastToAPInt(); | 
|  | Tmp = std::min(Tmp, Value.getNumSignBits()); | 
|  | continue; | 
|  | } | 
|  | } | 
|  | // Unknown type. Conservatively assume no bits match sign bit. | 
|  | return 1; | 
|  | } | 
|  | return Tmp; | 
|  | } | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Allow the target to implement this method for its nodes. | 
|  | if (Opcode >= ISD::BUILTIN_OP_END || | 
|  | Opcode == ISD::INTRINSIC_WO_CHAIN || | 
|  | Opcode == ISD::INTRINSIC_W_CHAIN || | 
|  | Opcode == ISD::INTRINSIC_VOID) { | 
|  | // TODO: This can probably be removed once target code is audited.  This | 
|  | // is here purely to reduce patch size and review complexity. | 
|  | if (!VT.isScalableVector()) { | 
|  | unsigned NumBits = | 
|  | TLI->ComputeNumSignBitsForTargetNode(Op, DemandedElts, *this, Depth); | 
|  | if (NumBits > 1) | 
|  | FirstAnswer = std::max(FirstAnswer, NumBits); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Finally, if we can prove that the top bits of the result are 0's or 1's, | 
|  | // use this information. | 
|  | KnownBits Known = computeKnownBits(Op, DemandedElts, Depth); | 
|  | return std::max(FirstAnswer, Known.countMinSignBits()); | 
|  | } | 
|  |  | 
|  | unsigned SelectionDAG::ComputeMaxSignificantBits(SDValue Op, | 
|  | unsigned Depth) const { | 
|  | unsigned SignBits = ComputeNumSignBits(Op, Depth); | 
|  | return Op.getScalarValueSizeInBits() - SignBits + 1; | 
|  | } | 
|  |  | 
|  | unsigned SelectionDAG::ComputeMaxSignificantBits(SDValue Op, | 
|  | const APInt &DemandedElts, | 
|  | unsigned Depth) const { | 
|  | unsigned SignBits = ComputeNumSignBits(Op, DemandedElts, Depth); | 
|  | return Op.getScalarValueSizeInBits() - SignBits + 1; | 
|  | } | 
|  |  | 
|  | bool SelectionDAG::isGuaranteedNotToBeUndefOrPoison(SDValue Op, bool PoisonOnly, | 
|  | unsigned Depth) const { | 
|  | // Early out for FREEZE. | 
|  | if (Op.getOpcode() == ISD::FREEZE) | 
|  | return true; | 
|  |  | 
|  | EVT VT = Op.getValueType(); | 
|  | APInt DemandedElts = VT.isFixedLengthVector() | 
|  | ? APInt::getAllOnes(VT.getVectorNumElements()) | 
|  | : APInt(1, 1); | 
|  | return isGuaranteedNotToBeUndefOrPoison(Op, DemandedElts, PoisonOnly, Depth); | 
|  | } | 
|  |  | 
|  | bool SelectionDAG::isGuaranteedNotToBeUndefOrPoison(SDValue Op, | 
|  | const APInt &DemandedElts, | 
|  | bool PoisonOnly, | 
|  | unsigned Depth) const { | 
|  | unsigned Opcode = Op.getOpcode(); | 
|  |  | 
|  | // Early out for FREEZE. | 
|  | if (Opcode == ISD::FREEZE) | 
|  | return true; | 
|  |  | 
|  | if (Depth >= MaxRecursionDepth) | 
|  | return false; // Limit search depth. | 
|  |  | 
|  | if (isIntOrFPConstant(Op)) | 
|  | return true; | 
|  |  | 
|  | switch (Opcode) { | 
|  | case ISD::CONDCODE: | 
|  | case ISD::VALUETYPE: | 
|  | case ISD::FrameIndex: | 
|  | case ISD::TargetFrameIndex: | 
|  | case ISD::CopyFromReg: | 
|  | return true; | 
|  |  | 
|  | case ISD::POISON: | 
|  | return false; | 
|  |  | 
|  | case ISD::UNDEF: | 
|  | return PoisonOnly; | 
|  |  | 
|  | case ISD::BUILD_VECTOR: | 
|  | // NOTE: BUILD_VECTOR has implicit truncation of wider scalar elements - | 
|  | // this shouldn't affect the result. | 
|  | for (unsigned i = 0, e = Op.getNumOperands(); i < e; ++i) { | 
|  | if (!DemandedElts[i]) | 
|  | continue; | 
|  | if (!isGuaranteedNotToBeUndefOrPoison(Op.getOperand(i), PoisonOnly, | 
|  | Depth + 1)) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  |  | 
|  | case ISD::EXTRACT_SUBVECTOR: { | 
|  | SDValue Src = Op.getOperand(0); | 
|  | if (Src.getValueType().isScalableVector()) | 
|  | break; | 
|  | uint64_t Idx = Op.getConstantOperandVal(1); | 
|  | unsigned NumSrcElts = Src.getValueType().getVectorNumElements(); | 
|  | APInt DemandedSrcElts = DemandedElts.zext(NumSrcElts).shl(Idx); | 
|  | return isGuaranteedNotToBeUndefOrPoison(Src, DemandedSrcElts, PoisonOnly, | 
|  | Depth + 1); | 
|  | } | 
|  |  | 
|  | case ISD::INSERT_SUBVECTOR: { | 
|  | if (Op.getValueType().isScalableVector()) | 
|  | break; | 
|  | SDValue Src = Op.getOperand(0); | 
|  | SDValue Sub = Op.getOperand(1); | 
|  | uint64_t Idx = Op.getConstantOperandVal(2); | 
|  | unsigned NumSubElts = Sub.getValueType().getVectorNumElements(); | 
|  | APInt DemandedSubElts = DemandedElts.extractBits(NumSubElts, Idx); | 
|  | APInt DemandedSrcElts = DemandedElts; | 
|  | DemandedSrcElts.clearBits(Idx, Idx + NumSubElts); | 
|  |  | 
|  | if (!!DemandedSubElts && !isGuaranteedNotToBeUndefOrPoison( | 
|  | Sub, DemandedSubElts, PoisonOnly, Depth + 1)) | 
|  | return false; | 
|  | if (!!DemandedSrcElts && !isGuaranteedNotToBeUndefOrPoison( | 
|  | Src, DemandedSrcElts, PoisonOnly, Depth + 1)) | 
|  | return false; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | case ISD::EXTRACT_VECTOR_ELT: { | 
|  | SDValue Src = Op.getOperand(0); | 
|  | auto *IndexC = dyn_cast<ConstantSDNode>(Op.getOperand(1)); | 
|  | EVT SrcVT = Src.getValueType(); | 
|  | if (SrcVT.isFixedLengthVector() && IndexC && | 
|  | IndexC->getAPIntValue().ult(SrcVT.getVectorNumElements())) { | 
|  | APInt DemandedSrcElts = APInt::getOneBitSet(SrcVT.getVectorNumElements(), | 
|  | IndexC->getZExtValue()); | 
|  | return isGuaranteedNotToBeUndefOrPoison(Src, DemandedSrcElts, PoisonOnly, | 
|  | Depth + 1); | 
|  | } | 
|  | break; | 
|  | } | 
|  |  | 
|  | case ISD::INSERT_VECTOR_ELT: { | 
|  | SDValue InVec = Op.getOperand(0); | 
|  | SDValue InVal = Op.getOperand(1); | 
|  | SDValue EltNo = Op.getOperand(2); | 
|  | EVT VT = InVec.getValueType(); | 
|  | auto *IndexC = dyn_cast<ConstantSDNode>(EltNo); | 
|  | if (IndexC && VT.isFixedLengthVector() && | 
|  | IndexC->getAPIntValue().ult(VT.getVectorNumElements())) { | 
|  | if (DemandedElts[IndexC->getZExtValue()] && | 
|  | !isGuaranteedNotToBeUndefOrPoison(InVal, PoisonOnly, Depth + 1)) | 
|  | return false; | 
|  | APInt InVecDemandedElts = DemandedElts; | 
|  | InVecDemandedElts.clearBit(IndexC->getZExtValue()); | 
|  | if (!!InVecDemandedElts && | 
|  | !isGuaranteedNotToBeUndefOrPoison(InVec, InVecDemandedElts, | 
|  | PoisonOnly, Depth + 1)) | 
|  | return false; | 
|  | return true; | 
|  | } | 
|  | break; | 
|  | } | 
|  |  | 
|  | case ISD::SCALAR_TO_VECTOR: | 
|  | // Check upper (known undef) elements. | 
|  | if (DemandedElts.ugt(1) && !PoisonOnly) | 
|  | return false; | 
|  | // Check element zero. | 
|  | if (DemandedElts[0] && !isGuaranteedNotToBeUndefOrPoison( | 
|  | Op.getOperand(0), PoisonOnly, Depth + 1)) | 
|  | return false; | 
|  | return true; | 
|  |  | 
|  | case ISD::SPLAT_VECTOR: | 
|  | return isGuaranteedNotToBeUndefOrPoison(Op.getOperand(0), PoisonOnly, | 
|  | Depth + 1); | 
|  |  | 
|  | case ISD::VECTOR_SHUFFLE: { | 
|  | APInt DemandedLHS, DemandedRHS; | 
|  | auto *SVN = cast<ShuffleVectorSDNode>(Op); | 
|  | if (!getShuffleDemandedElts(DemandedElts.getBitWidth(), SVN->getMask(), | 
|  | DemandedElts, DemandedLHS, DemandedRHS, | 
|  | /*AllowUndefElts=*/false)) | 
|  | return false; | 
|  | if (!DemandedLHS.isZero() && | 
|  | !isGuaranteedNotToBeUndefOrPoison(Op.getOperand(0), DemandedLHS, | 
|  | PoisonOnly, Depth + 1)) | 
|  | return false; | 
|  | if (!DemandedRHS.isZero() && | 
|  | !isGuaranteedNotToBeUndefOrPoison(Op.getOperand(1), DemandedRHS, | 
|  | PoisonOnly, Depth + 1)) | 
|  | return false; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | case ISD::SHL: | 
|  | case ISD::SRL: | 
|  | case ISD::SRA: | 
|  | // Shift amount operand is checked by canCreateUndefOrPoison. So it is | 
|  | // enough to check operand 0 if Op can't create undef/poison. | 
|  | return !canCreateUndefOrPoison(Op, DemandedElts, PoisonOnly, | 
|  | /*ConsiderFlags*/ true, Depth) && | 
|  | isGuaranteedNotToBeUndefOrPoison(Op.getOperand(0), DemandedElts, | 
|  | PoisonOnly, Depth + 1); | 
|  |  | 
|  | case ISD::BSWAP: | 
|  | case ISD::CTPOP: | 
|  | case ISD::BITREVERSE: | 
|  | case ISD::AND: | 
|  | case ISD::OR: | 
|  | case ISD::XOR: | 
|  | case ISD::ADD: | 
|  | case ISD::SUB: | 
|  | case ISD::MUL: | 
|  | case ISD::SADDSAT: | 
|  | case ISD::UADDSAT: | 
|  | case ISD::SSUBSAT: | 
|  | case ISD::USUBSAT: | 
|  | case ISD::SSHLSAT: | 
|  | case ISD::USHLSAT: | 
|  | case ISD::SMIN: | 
|  | case ISD::SMAX: | 
|  | case ISD::UMIN: | 
|  | case ISD::UMAX: | 
|  | case ISD::ZERO_EXTEND: | 
|  | case ISD::SIGN_EXTEND: | 
|  | case ISD::ANY_EXTEND: | 
|  | case ISD::TRUNCATE: | 
|  | case ISD::VSELECT: { | 
|  | // If Op can't create undef/poison and none of its operands are undef/poison | 
|  | // then Op is never undef/poison. A difference from the more common check | 
|  | // below, outside the switch, is that we handle elementwise operations for | 
|  | // which the DemandedElts mask is valid for all operands here. | 
|  | return !canCreateUndefOrPoison(Op, DemandedElts, PoisonOnly, | 
|  | /*ConsiderFlags*/ true, Depth) && | 
|  | all_of(Op->ops(), [&](SDValue V) { | 
|  | return isGuaranteedNotToBeUndefOrPoison(V, DemandedElts, | 
|  | PoisonOnly, Depth + 1); | 
|  | }); | 
|  | } | 
|  |  | 
|  | // TODO: Search for noundef attributes from library functions. | 
|  |  | 
|  | // TODO: Pointers dereferenced by ISD::LOAD/STORE ops are noundef. | 
|  |  | 
|  | default: | 
|  | // Allow the target to implement this method for its nodes. | 
|  | if (Opcode >= ISD::BUILTIN_OP_END || Opcode == ISD::INTRINSIC_WO_CHAIN || | 
|  | Opcode == ISD::INTRINSIC_W_CHAIN || Opcode == ISD::INTRINSIC_VOID) | 
|  | return TLI->isGuaranteedNotToBeUndefOrPoisonForTargetNode( | 
|  | Op, DemandedElts, *this, PoisonOnly, Depth); | 
|  | break; | 
|  | } | 
|  |  | 
|  | // If Op can't create undef/poison and none of its operands are undef/poison | 
|  | // then Op is never undef/poison. | 
|  | // NOTE: TargetNodes can handle this in themselves in | 
|  | // isGuaranteedNotToBeUndefOrPoisonForTargetNode or let | 
|  | // TargetLowering::isGuaranteedNotToBeUndefOrPoisonForTargetNode handle it. | 
|  | return !canCreateUndefOrPoison(Op, PoisonOnly, /*ConsiderFlags*/ true, | 
|  | Depth) && | 
|  | all_of(Op->ops(), [&](SDValue V) { | 
|  | return isGuaranteedNotToBeUndefOrPoison(V, PoisonOnly, Depth + 1); | 
|  | }); | 
|  | } | 
|  |  | 
|  | bool SelectionDAG::canCreateUndefOrPoison(SDValue Op, bool PoisonOnly, | 
|  | bool ConsiderFlags, | 
|  | unsigned Depth) const { | 
|  | EVT VT = Op.getValueType(); | 
|  | APInt DemandedElts = VT.isFixedLengthVector() | 
|  | ? APInt::getAllOnes(VT.getVectorNumElements()) | 
|  | : APInt(1, 1); | 
|  | return canCreateUndefOrPoison(Op, DemandedElts, PoisonOnly, ConsiderFlags, | 
|  | Depth); | 
|  | } | 
|  |  | 
|  | bool SelectionDAG::canCreateUndefOrPoison(SDValue Op, const APInt &DemandedElts, | 
|  | bool PoisonOnly, bool ConsiderFlags, | 
|  | unsigned Depth) const { | 
|  | if (ConsiderFlags && Op->hasPoisonGeneratingFlags()) | 
|  | return true; | 
|  |  | 
|  | unsigned Opcode = Op.getOpcode(); | 
|  | switch (Opcode) { | 
|  | case ISD::AssertSext: | 
|  | case ISD::AssertZext: | 
|  | case ISD::AssertAlign: | 
|  | case ISD::AssertNoFPClass: | 
|  | // Assertion nodes can create poison if the assertion fails. | 
|  | return true; | 
|  |  | 
|  | case ISD::FREEZE: | 
|  | case ISD::CONCAT_VECTORS: | 
|  | case ISD::INSERT_SUBVECTOR: | 
|  | case ISD::EXTRACT_SUBVECTOR: | 
|  | case ISD::SADDSAT: | 
|  | case ISD::UADDSAT: | 
|  | case ISD::SSUBSAT: | 
|  | case ISD::USUBSAT: | 
|  | case ISD::MULHU: | 
|  | case ISD::MULHS: | 
|  | case ISD::AVGFLOORS: | 
|  | case ISD::AVGFLOORU: | 
|  | case ISD::AVGCEILS: | 
|  | case ISD::AVGCEILU: | 
|  | case ISD::ABDU: | 
|  | case ISD::ABDS: | 
|  | case ISD::SMIN: | 
|  | case ISD::SMAX: | 
|  | case ISD::SCMP: | 
|  | case ISD::UMIN: | 
|  | case ISD::UMAX: | 
|  | case ISD::UCMP: | 
|  | case ISD::AND: | 
|  | case ISD::XOR: | 
|  | case ISD::ROTL: | 
|  | case ISD::ROTR: | 
|  | case ISD::FSHL: | 
|  | case ISD::FSHR: | 
|  | case ISD::BSWAP: | 
|  | case ISD::CTTZ: | 
|  | case ISD::CTLZ: | 
|  | case ISD::CTPOP: | 
|  | case ISD::BITREVERSE: | 
|  | case ISD::PARITY: | 
|  | case ISD::SIGN_EXTEND: | 
|  | case ISD::TRUNCATE: | 
|  | case ISD::SIGN_EXTEND_INREG: | 
|  | case ISD::SIGN_EXTEND_VECTOR_INREG: | 
|  | case ISD::ZERO_EXTEND_VECTOR_INREG: | 
|  | case ISD::BITCAST: | 
|  | case ISD::BUILD_VECTOR: | 
|  | case ISD::BUILD_PAIR: | 
|  | case ISD::SPLAT_VECTOR: | 
|  | case ISD::FABS: | 
|  | return false; | 
|  |  | 
|  | case ISD::ABS: | 
|  | // ISD::ABS defines abs(INT_MIN) -> INT_MIN and never generates poison. | 
|  | // Different to Intrinsic::abs. | 
|  | return false; | 
|  |  | 
|  | case ISD::ADDC: | 
|  | case ISD::SUBC: | 
|  | case ISD::ADDE: | 
|  | case ISD::SUBE: | 
|  | case ISD::SADDO: | 
|  | case ISD::SSUBO: | 
|  | case ISD::SMULO: | 
|  | case ISD::SADDO_CARRY: | 
|  | case ISD::SSUBO_CARRY: | 
|  | case ISD::UADDO: | 
|  | case ISD::USUBO: | 
|  | case ISD::UMULO: | 
|  | case ISD::UADDO_CARRY: | 
|  | case ISD::USUBO_CARRY: | 
|  | // No poison on result or overflow flags. | 
|  | return false; | 
|  |  | 
|  | case ISD::SELECT_CC: | 
|  | case ISD::SETCC: { | 
|  | // Integer setcc cannot create undef or poison. | 
|  | if (Op.getOperand(0).getValueType().isInteger()) | 
|  | return false; | 
|  |  | 
|  | // FP compares are more complicated. They can create poison for nan/infinity | 
|  | // based on options and flags. The options and flags also cause special | 
|  | // nonan condition codes to be used. Those condition codes may be preserved | 
|  | // even if the nonan flag is dropped somewhere. | 
|  | unsigned CCOp = Opcode == ISD::SETCC ? 2 : 4; | 
|  | ISD::CondCode CCCode = cast<CondCodeSDNode>(Op.getOperand(CCOp))->get(); | 
|  | if (((unsigned)CCCode & 0x10U)) | 
|  | return true; | 
|  |  | 
|  | const TargetOptions &Options = getTarget().Options; | 
|  | return Options.NoNaNsFPMath || Options.NoInfsFPMath; | 
|  | } | 
|  |  | 
|  | case ISD::OR: | 
|  | case ISD::ZERO_EXTEND: | 
|  | case ISD::SELECT: | 
|  | case ISD::VSELECT: | 
|  | case ISD::ADD: | 
|  | case ISD::SUB: | 
|  | case ISD::MUL: | 
|  | case ISD::FNEG: | 
|  | case ISD::FADD: | 
|  | case ISD::FSUB: | 
|  | case ISD::FMUL: | 
|  | case ISD::FDIV: | 
|  | case ISD::FREM: | 
|  | case ISD::FCOPYSIGN: | 
|  | case ISD::FMA: | 
|  | case ISD::FMAD: | 
|  | case ISD::FP_EXTEND: | 
|  | case ISD::FP_TO_SINT_SAT: | 
|  | case ISD::FP_TO_UINT_SAT: | 
|  | // No poison except from flags (which is handled above) | 
|  | return false; | 
|  |  | 
|  | case ISD::SHL: | 
|  | case ISD::SRL: | 
|  | case ISD::SRA: | 
|  | // If the max shift amount isn't in range, then the shift can | 
|  | // create poison. | 
|  | return !getValidMaximumShiftAmount(Op, DemandedElts, Depth + 1); | 
|  |  | 
|  | case ISD::CTTZ_ZERO_UNDEF: | 
|  | case ISD::CTLZ_ZERO_UNDEF: | 
|  | // If the amount is zero then the result will be poison. | 
|  | // TODO: Add isKnownNeverZero DemandedElts handling. | 
|  | return !isKnownNeverZero(Op.getOperand(0), Depth + 1); | 
|  |  | 
|  | case ISD::SCALAR_TO_VECTOR: | 
|  | // Check if we demand any upper (undef) elements. | 
|  | return !PoisonOnly && DemandedElts.ugt(1); | 
|  |  | 
|  | case ISD::INSERT_VECTOR_ELT: | 
|  | case ISD::EXTRACT_VECTOR_ELT: { | 
|  | // Ensure that the element index is in bounds. | 
|  | EVT VecVT = Op.getOperand(0).getValueType(); | 
|  | SDValue Idx = Op.getOperand(Opcode == ISD::INSERT_VECTOR_ELT ? 2 : 1); | 
|  | KnownBits KnownIdx = computeKnownBits(Idx, Depth + 1); | 
|  | return KnownIdx.getMaxValue().uge(VecVT.getVectorMinNumElements()); | 
|  | } | 
|  |  | 
|  | case ISD::VECTOR_SHUFFLE: { | 
|  | // Check for any demanded shuffle element that is undef. | 
|  | auto *SVN = cast<ShuffleVectorSDNode>(Op); | 
|  | for (auto [Idx, Elt] : enumerate(SVN->getMask())) | 
|  | if (Elt < 0 && DemandedElts[Idx]) | 
|  | return true; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | default: | 
|  | // Allow the target to implement this method for its nodes. | 
|  | if (Opcode >= ISD::BUILTIN_OP_END || Opcode == ISD::INTRINSIC_WO_CHAIN || | 
|  | Opcode == ISD::INTRINSIC_W_CHAIN || Opcode == ISD::INTRINSIC_VOID) | 
|  | return TLI->canCreateUndefOrPoisonForTargetNode( | 
|  | Op, DemandedElts, *this, PoisonOnly, ConsiderFlags, Depth); | 
|  | break; | 
|  | } | 
|  |  | 
|  | // Be conservative and return true. | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool SelectionDAG::isADDLike(SDValue Op, bool NoWrap) const { | 
|  | unsigned Opcode = Op.getOpcode(); | 
|  | if (Opcode == ISD::OR) | 
|  | return Op->getFlags().hasDisjoint() || | 
|  | haveNoCommonBitsSet(Op.getOperand(0), Op.getOperand(1)); | 
|  | if (Opcode == ISD::XOR) | 
|  | return !NoWrap && isMinSignedConstant(Op.getOperand(1)); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool SelectionDAG::isBaseWithConstantOffset(SDValue Op) const { | 
|  | return Op.getNumOperands() == 2 && isa<ConstantSDNode>(Op.getOperand(1)) && | 
|  | (Op.isAnyAdd() || isADDLike(Op)); | 
|  | } | 
|  |  | 
|  | bool SelectionDAG::isKnownNeverNaN(SDValue Op, bool SNaN, | 
|  | unsigned Depth) const { | 
|  | EVT VT = Op.getValueType(); | 
|  |  | 
|  | // Since the number of lanes in a scalable vector is unknown at compile time, | 
|  | // we track one bit which is implicitly broadcast to all lanes.  This means | 
|  | // that all lanes in a scalable vector are considered demanded. | 
|  | APInt DemandedElts = VT.isFixedLengthVector() | 
|  | ? APInt::getAllOnes(VT.getVectorNumElements()) | 
|  | : APInt(1, 1); | 
|  |  | 
|  | return isKnownNeverNaN(Op, DemandedElts, SNaN, Depth); | 
|  | } | 
|  |  | 
|  | bool SelectionDAG::isKnownNeverNaN(SDValue Op, const APInt &DemandedElts, | 
|  | bool SNaN, unsigned Depth) const { | 
|  | assert(!DemandedElts.isZero() && "No demanded elements"); | 
|  |  | 
|  | // If we're told that NaNs won't happen, assume they won't. | 
|  | if (getTarget().Options.NoNaNsFPMath || Op->getFlags().hasNoNaNs()) | 
|  | return true; | 
|  |  | 
|  | if (Depth >= MaxRecursionDepth) | 
|  | return false; // Limit search depth. | 
|  |  | 
|  | // If the value is a constant, we can obviously see if it is a NaN or not. | 
|  | if (const ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(Op)) { | 
|  | return !C->getValueAPF().isNaN() || | 
|  | (SNaN && !C->getValueAPF().isSignaling()); | 
|  | } | 
|  |  | 
|  | unsigned Opcode = Op.getOpcode(); | 
|  | switch (Opcode) { | 
|  | case ISD::FADD: | 
|  | case ISD::FSUB: | 
|  | case ISD::FMUL: | 
|  | case ISD::FDIV: | 
|  | case ISD::FREM: | 
|  | case ISD::FSIN: | 
|  | case ISD::FCOS: | 
|  | case ISD::FTAN: | 
|  | case ISD::FASIN: | 
|  | case ISD::FACOS: | 
|  | case ISD::FATAN: | 
|  | case ISD::FATAN2: | 
|  | case ISD::FSINH: | 
|  | case ISD::FCOSH: | 
|  | case ISD::FTANH: | 
|  | case ISD::FMA: | 
|  | case ISD::FMAD: { | 
|  | if (SNaN) | 
|  | return true; | 
|  | // TODO: Need isKnownNeverInfinity | 
|  | return false; | 
|  | } | 
|  | case ISD::FCANONICALIZE: | 
|  | case ISD::FEXP: | 
|  | case ISD::FEXP2: | 
|  | case ISD::FEXP10: | 
|  | case ISD::FTRUNC: | 
|  | case ISD::FFLOOR: | 
|  | case ISD::FCEIL: | 
|  | case ISD::FROUND: | 
|  | case ISD::FROUNDEVEN: | 
|  | case ISD::LROUND: | 
|  | case ISD::LLROUND: | 
|  | case ISD::FRINT: | 
|  | case ISD::LRINT: | 
|  | case ISD::LLRINT: | 
|  | case ISD::FNEARBYINT: | 
|  | case ISD::FLDEXP: { | 
|  | if (SNaN) | 
|  | return true; | 
|  | return isKnownNeverNaN(Op.getOperand(0), DemandedElts, SNaN, Depth + 1); | 
|  | } | 
|  | case ISD::FABS: | 
|  | case ISD::FNEG: | 
|  | case ISD::FCOPYSIGN: { | 
|  | return isKnownNeverNaN(Op.getOperand(0), DemandedElts, SNaN, Depth + 1); | 
|  | } | 
|  | case ISD::SELECT: | 
|  | return isKnownNeverNaN(Op.getOperand(1), DemandedElts, SNaN, Depth + 1) && | 
|  | isKnownNeverNaN(Op.getOperand(2), DemandedElts, SNaN, Depth + 1); | 
|  | case ISD::FP_EXTEND: | 
|  | case ISD::FP_ROUND: { | 
|  | if (SNaN) | 
|  | return true; | 
|  | return isKnownNeverNaN(Op.getOperand(0), DemandedElts, SNaN, Depth + 1); | 
|  | } | 
|  | case ISD::SINT_TO_FP: | 
|  | case ISD::UINT_TO_FP: | 
|  | return true; | 
|  | case ISD::FSQRT: // Need is known positive | 
|  | case ISD::FLOG: | 
|  | case ISD::FLOG2: | 
|  | case ISD::FLOG10: | 
|  | case ISD::FPOWI: | 
|  | case ISD::FPOW: { | 
|  | if (SNaN) | 
|  | return true; | 
|  | // TODO: Refine on operand | 
|  | return false; | 
|  | } | 
|  | case ISD::FMINNUM: | 
|  | case ISD::FMAXNUM: | 
|  | case ISD::FMINIMUMNUM: | 
|  | case ISD::FMAXIMUMNUM: { | 
|  | // Only one needs to be known not-nan, since it will be returned if the | 
|  | // other ends up being one. | 
|  | return isKnownNeverNaN(Op.getOperand(0), DemandedElts, SNaN, Depth + 1) || | 
|  | isKnownNeverNaN(Op.getOperand(1), DemandedElts, SNaN, Depth + 1); | 
|  | } | 
|  | case ISD::FMINNUM_IEEE: | 
|  | case ISD::FMAXNUM_IEEE: { | 
|  | if (SNaN) | 
|  | return true; | 
|  | // This can return a NaN if either operand is an sNaN, or if both operands | 
|  | // are NaN. | 
|  | return (isKnownNeverNaN(Op.getOperand(0), DemandedElts, false, Depth + 1) && | 
|  | isKnownNeverSNaN(Op.getOperand(1), DemandedElts, Depth + 1)) || | 
|  | (isKnownNeverNaN(Op.getOperand(1), DemandedElts, false, Depth + 1) && | 
|  | isKnownNeverSNaN(Op.getOperand(0), DemandedElts, Depth + 1)); | 
|  | } | 
|  | case ISD::FMINIMUM: | 
|  | case ISD::FMAXIMUM: { | 
|  | // TODO: Does this quiet or return the origina NaN as-is? | 
|  | return isKnownNeverNaN(Op.getOperand(0), DemandedElts, SNaN, Depth + 1) && | 
|  | isKnownNeverNaN(Op.getOperand(1), DemandedElts, SNaN, Depth + 1); | 
|  | } | 
|  | case ISD::EXTRACT_VECTOR_ELT: { | 
|  | SDValue Src = Op.getOperand(0); | 
|  | auto *Idx = dyn_cast<ConstantSDNode>(Op.getOperand(1)); | 
|  | EVT SrcVT = Src.getValueType(); | 
|  | if (SrcVT.isFixedLengthVector() && Idx && | 
|  | Idx->getAPIntValue().ult(SrcVT.getVectorNumElements())) { | 
|  | APInt DemandedSrcElts = APInt::getOneBitSet(SrcVT.getVectorNumElements(), | 
|  | Idx->getZExtValue()); | 
|  | return isKnownNeverNaN(Src, DemandedSrcElts, SNaN, Depth + 1); | 
|  | } | 
|  | return isKnownNeverNaN(Src, SNaN, Depth + 1); | 
|  | } | 
|  | case ISD::EXTRACT_SUBVECTOR: { | 
|  | SDValue Src = Op.getOperand(0); | 
|  | if (Src.getValueType().isFixedLengthVector()) { | 
|  | unsigned Idx = Op.getConstantOperandVal(1); | 
|  | unsigned NumSrcElts = Src.getValueType().getVectorNumElements(); | 
|  | APInt DemandedSrcElts = DemandedElts.zext(NumSrcElts).shl(Idx); | 
|  | return isKnownNeverNaN(Src, DemandedSrcElts, SNaN, Depth + 1); | 
|  | } | 
|  | return isKnownNeverNaN(Src, SNaN, Depth + 1); | 
|  | } | 
|  | case ISD::INSERT_SUBVECTOR: { | 
|  | SDValue BaseVector = Op.getOperand(0); | 
|  | SDValue SubVector = Op.getOperand(1); | 
|  | EVT BaseVectorVT = BaseVector.getValueType(); | 
|  | if (BaseVectorVT.isFixedLengthVector()) { | 
|  | unsigned Idx = Op.getConstantOperandVal(2); | 
|  | unsigned NumBaseElts = BaseVectorVT.getVectorNumElements(); | 
|  | unsigned NumSubElts = SubVector.getValueType().getVectorNumElements(); | 
|  |  | 
|  | // Clear/Extract the bits at the position where the subvector will be | 
|  | // inserted. | 
|  | APInt DemandedMask = | 
|  | APInt::getBitsSet(NumBaseElts, Idx, Idx + NumSubElts); | 
|  | APInt DemandedSrcElts = DemandedElts & ~DemandedMask; | 
|  | APInt DemandedSubElts = DemandedElts.extractBits(NumSubElts, Idx); | 
|  |  | 
|  | bool NeverNaN = true; | 
|  | if (!DemandedSrcElts.isZero()) | 
|  | NeverNaN &= | 
|  | isKnownNeverNaN(BaseVector, DemandedSrcElts, SNaN, Depth + 1); | 
|  | if (NeverNaN && !DemandedSubElts.isZero()) | 
|  | NeverNaN &= | 
|  | isKnownNeverNaN(SubVector, DemandedSubElts, SNaN, Depth + 1); | 
|  | return NeverNaN; | 
|  | } | 
|  | return isKnownNeverNaN(BaseVector, SNaN, Depth + 1) && | 
|  | isKnownNeverNaN(SubVector, SNaN, Depth + 1); | 
|  | } | 
|  | case ISD::BUILD_VECTOR: { | 
|  | unsigned NumElts = Op.getNumOperands(); | 
|  | for (unsigned I = 0; I != NumElts; ++I) | 
|  | if (DemandedElts[I] && | 
|  | !isKnownNeverNaN(Op.getOperand(I), SNaN, Depth + 1)) | 
|  | return false; | 
|  | return true; | 
|  | } | 
|  | case ISD::AssertNoFPClass: { | 
|  | FPClassTest NoFPClass = | 
|  | static_cast<FPClassTest>(Op.getConstantOperandVal(1)); | 
|  | if ((NoFPClass & fcNan) == fcNan) | 
|  | return true; | 
|  | if (SNaN && (NoFPClass & fcSNan) == fcSNan) | 
|  | return true; | 
|  | return isKnownNeverNaN(Op.getOperand(0), DemandedElts, SNaN, Depth + 1); | 
|  | } | 
|  | default: | 
|  | if (Opcode >= ISD::BUILTIN_OP_END || Opcode == ISD::INTRINSIC_WO_CHAIN || | 
|  | Opcode == ISD::INTRINSIC_W_CHAIN || Opcode == ISD::INTRINSIC_VOID) { | 
|  | return TLI->isKnownNeverNaNForTargetNode(Op, DemandedElts, *this, SNaN, | 
|  | Depth); | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | bool SelectionDAG::isKnownNeverZeroFloat(SDValue Op) const { | 
|  | assert(Op.getValueType().isFloatingPoint() && | 
|  | "Floating point type expected"); | 
|  |  | 
|  | // If the value is a constant, we can obviously see if it is a zero or not. | 
|  | return ISD::matchUnaryFpPredicate( | 
|  | Op, [](ConstantFPSDNode *C) { return !C->isZero(); }); | 
|  | } | 
|  |  | 
|  | bool SelectionDAG::isKnownNeverZero(SDValue Op, unsigned Depth) const { | 
|  | if (Depth >= MaxRecursionDepth) | 
|  | return false; // Limit search depth. | 
|  |  | 
|  | assert(!Op.getValueType().isFloatingPoint() && | 
|  | "Floating point types unsupported - use isKnownNeverZeroFloat"); | 
|  |  | 
|  | // If the value is a constant, we can obviously see if it is a zero or not. | 
|  | if (ISD::matchUnaryPredicate(Op, | 
|  | [](ConstantSDNode *C) { return !C->isZero(); })) | 
|  | return true; | 
|  |  | 
|  | // TODO: Recognize more cases here. Most of the cases are also incomplete to | 
|  | // some degree. | 
|  | switch (Op.getOpcode()) { | 
|  | default: | 
|  | break; | 
|  |  | 
|  | case ISD::OR: | 
|  | return isKnownNeverZero(Op.getOperand(1), Depth + 1) || | 
|  | isKnownNeverZero(Op.getOperand(0), Depth + 1); | 
|  |  | 
|  | case ISD::VSELECT: | 
|  | case ISD::SELECT: | 
|  | return isKnownNeverZero(Op.getOperand(1), Depth + 1) && | 
|  | isKnownNeverZero(Op.getOperand(2), Depth + 1); | 
|  |  | 
|  | case ISD::SHL: { | 
|  | if (Op->getFlags().hasNoSignedWrap() || Op->getFlags().hasNoUnsignedWrap()) | 
|  | return isKnownNeverZero(Op.getOperand(0), Depth + 1); | 
|  | KnownBits ValKnown = computeKnownBits(Op.getOperand(0), Depth + 1); | 
|  | // 1 << X is never zero. | 
|  | if (ValKnown.One[0]) | 
|  | return true; | 
|  | // If max shift cnt of known ones is non-zero, result is non-zero. | 
|  | APInt MaxCnt = computeKnownBits(Op.getOperand(1), Depth + 1).getMaxValue(); | 
|  | if (MaxCnt.ult(ValKnown.getBitWidth()) && | 
|  | !ValKnown.One.shl(MaxCnt).isZero()) | 
|  | return true; | 
|  | break; | 
|  | } | 
|  | case ISD::UADDSAT: | 
|  | case ISD::UMAX: | 
|  | return isKnownNeverZero(Op.getOperand(1), Depth + 1) || | 
|  | isKnownNeverZero(Op.getOperand(0), Depth + 1); | 
|  |  | 
|  | // For smin/smax: If either operand is known negative/positive | 
|  | // respectively we don't need the other to be known at all. | 
|  | case ISD::SMAX: { | 
|  | KnownBits Op1 = computeKnownBits(Op.getOperand(1), Depth + 1); | 
|  | if (Op1.isStrictlyPositive()) | 
|  | return true; | 
|  |  | 
|  | KnownBits Op0 = computeKnownBits(Op.getOperand(0), Depth + 1); | 
|  | if (Op0.isStrictlyPositive()) | 
|  | return true; | 
|  |  | 
|  | if (Op1.isNonZero() && Op0.isNonZero()) | 
|  | return true; | 
|  |  | 
|  | return isKnownNeverZero(Op.getOperand(1), Depth + 1) && | 
|  | isKnownNeverZero(Op.getOperand(0), Depth + 1); | 
|  | } | 
|  | case ISD::SMIN: { | 
|  | KnownBits Op1 = computeKnownBits(Op.getOperand(1), Depth + 1); | 
|  | if (Op1.isNegative()) | 
|  | return true; | 
|  |  | 
|  | KnownBits Op0 = computeKnownBits(Op.getOperand(0), Depth + 1); | 
|  | if (Op0.isNegative()) | 
|  | return true; | 
|  |  | 
|  | if (Op1.isNonZero() && Op0.isNonZero()) | 
|  | return true; | 
|  |  | 
|  | return isKnownNeverZero(Op.getOperand(1), Depth + 1) && | 
|  | isKnownNeverZero(Op.getOperand(0), Depth + 1); | 
|  | } | 
|  | case ISD::UMIN: | 
|  | return isKnownNeverZero(Op.getOperand(1), Depth + 1) && | 
|  | isKnownNeverZero(Op.getOperand(0), Depth + 1); | 
|  |  | 
|  | case ISD::ROTL: | 
|  | case ISD::ROTR: | 
|  | case ISD::BITREVERSE: | 
|  | case ISD::BSWAP: | 
|  | case ISD::CTPOP: | 
|  | case ISD::ABS: | 
|  | return isKnownNeverZero(Op.getOperand(0), Depth + 1); | 
|  |  | 
|  | case ISD::SRA: | 
|  | case ISD::SRL: { | 
|  | if (Op->getFlags().hasExact()) | 
|  | return isKnownNeverZero(Op.getOperand(0), Depth + 1); | 
|  | KnownBits ValKnown = computeKnownBits(Op.getOperand(0), Depth + 1); | 
|  | if (ValKnown.isNegative()) | 
|  | return true; | 
|  | // If max shift cnt of known ones is non-zero, result is non-zero. | 
|  | APInt MaxCnt = computeKnownBits(Op.getOperand(1), Depth + 1).getMaxValue(); | 
|  | if (MaxCnt.ult(ValKnown.getBitWidth()) && | 
|  | !ValKnown.One.lshr(MaxCnt).isZero()) | 
|  | return true; | 
|  | break; | 
|  | } | 
|  | case ISD::UDIV: | 
|  | case ISD::SDIV: | 
|  | // div exact can only produce a zero if the dividend is zero. | 
|  | // TODO: For udiv this is also true if Op1 u<= Op0 | 
|  | if (Op->getFlags().hasExact()) | 
|  | return isKnownNeverZero(Op.getOperand(0), Depth + 1); | 
|  | break; | 
|  |  | 
|  | case ISD::ADD: | 
|  | if (Op->getFlags().hasNoUnsignedWrap()) | 
|  | if (isKnownNeverZero(Op.getOperand(1), Depth + 1) || | 
|  | isKnownNeverZero(Op.getOperand(0), Depth + 1)) | 
|  | return true; | 
|  | // TODO: There are a lot more cases we can prove for add. | 
|  | break; | 
|  |  | 
|  | case ISD::SUB: { | 
|  | if (isNullConstant(Op.getOperand(0))) | 
|  | return isKnownNeverZero(Op.getOperand(1), Depth + 1); | 
|  |  | 
|  | std::optional<bool> ne = | 
|  | KnownBits::ne(computeKnownBits(Op.getOperand(0), Depth + 1), | 
|  | computeKnownBits(Op.getOperand(1), Depth + 1)); | 
|  | return ne && *ne; | 
|  | } | 
|  |  | 
|  | case ISD::MUL: | 
|  | if (Op->getFlags().hasNoSignedWrap() || Op->getFlags().hasNoUnsignedWrap()) | 
|  | if (isKnownNeverZero(Op.getOperand(1), Depth + 1) && | 
|  | isKnownNeverZero(Op.getOperand(0), Depth + 1)) | 
|  | return true; | 
|  | break; | 
|  |  | 
|  | case ISD::ZERO_EXTEND: | 
|  | case ISD::SIGN_EXTEND: | 
|  | return isKnownNeverZero(Op.getOperand(0), Depth + 1); | 
|  | case ISD::VSCALE: { | 
|  | const Function &F = getMachineFunction().getFunction(); | 
|  | const APInt &Multiplier = Op.getConstantOperandAPInt(0); | 
|  | ConstantRange CR = | 
|  | getVScaleRange(&F, Op.getScalarValueSizeInBits()).multiply(Multiplier); | 
|  | if (!CR.contains(APInt(CR.getBitWidth(), 0))) | 
|  | return true; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | return computeKnownBits(Op, Depth).isNonZero(); | 
|  | } | 
|  |  | 
|  | bool SelectionDAG::cannotBeOrderedNegativeFP(SDValue Op) const { | 
|  | if (ConstantFPSDNode *C1 = isConstOrConstSplatFP(Op, true)) | 
|  | return !C1->isNegative(); | 
|  |  | 
|  | return Op.getOpcode() == ISD::FABS; | 
|  | } | 
|  |  | 
|  | bool SelectionDAG::isEqualTo(SDValue A, SDValue B) const { | 
|  | // Check the obvious case. | 
|  | if (A == B) return true; | 
|  |  | 
|  | // For negative and positive zero. | 
|  | if (const ConstantFPSDNode *CA = dyn_cast<ConstantFPSDNode>(A)) | 
|  | if (const ConstantFPSDNode *CB = dyn_cast<ConstantFPSDNode>(B)) | 
|  | if (CA->isZero() && CB->isZero()) return true; | 
|  |  | 
|  | // Otherwise they may not be equal. | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Only bits set in Mask must be negated, other bits may be arbitrary. | 
|  | SDValue llvm::getBitwiseNotOperand(SDValue V, SDValue Mask, bool AllowUndefs) { | 
|  | if (isBitwiseNot(V, AllowUndefs)) | 
|  | return V.getOperand(0); | 
|  |  | 
|  | // Handle any_extend (not (truncate X)) pattern, where Mask only sets | 
|  | // bits in the non-extended part. | 
|  | ConstantSDNode *MaskC = isConstOrConstSplat(Mask); | 
|  | if (!MaskC || V.getOpcode() != ISD::ANY_EXTEND) | 
|  | return SDValue(); | 
|  | SDValue ExtArg = V.getOperand(0); | 
|  | if (ExtArg.getScalarValueSizeInBits() >= | 
|  | MaskC->getAPIntValue().getActiveBits() && | 
|  | isBitwiseNot(ExtArg, AllowUndefs) && | 
|  | ExtArg.getOperand(0).getOpcode() == ISD::TRUNCATE && | 
|  | ExtArg.getOperand(0).getOperand(0).getValueType() == V.getValueType()) | 
|  | return ExtArg.getOperand(0).getOperand(0); | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static bool haveNoCommonBitsSetCommutative(SDValue A, SDValue B) { | 
|  | // Match masked merge pattern (X & ~M) op (Y & M) | 
|  | // Including degenerate case (X & ~M) op M | 
|  | auto MatchNoCommonBitsPattern = [&](SDValue Not, SDValue Mask, | 
|  | SDValue Other) { | 
|  | if (SDValue NotOperand = | 
|  | getBitwiseNotOperand(Not, Mask, /* AllowUndefs */ true)) { | 
|  | if (NotOperand->getOpcode() == ISD::ZERO_EXTEND || | 
|  | NotOperand->getOpcode() == ISD::TRUNCATE) | 
|  | NotOperand = NotOperand->getOperand(0); | 
|  |  | 
|  | if (Other == NotOperand) | 
|  | return true; | 
|  | if (Other->getOpcode() == ISD::AND) | 
|  | return NotOperand == Other->getOperand(0) || | 
|  | NotOperand == Other->getOperand(1); | 
|  | } | 
|  | return false; | 
|  | }; | 
|  |  | 
|  | if (A->getOpcode() == ISD::ZERO_EXTEND || A->getOpcode() == ISD::TRUNCATE) | 
|  | A = A->getOperand(0); | 
|  |  | 
|  | if (B->getOpcode() == ISD::ZERO_EXTEND || B->getOpcode() == ISD::TRUNCATE) | 
|  | B = B->getOperand(0); | 
|  |  | 
|  | if (A->getOpcode() == ISD::AND) | 
|  | return MatchNoCommonBitsPattern(A->getOperand(0), A->getOperand(1), B) || | 
|  | MatchNoCommonBitsPattern(A->getOperand(1), A->getOperand(0), B); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // FIXME: unify with llvm::haveNoCommonBitsSet. | 
|  | bool SelectionDAG::haveNoCommonBitsSet(SDValue A, SDValue B) const { | 
|  | assert(A.getValueType() == B.getValueType() && | 
|  | "Values must have the same type"); | 
|  | if (haveNoCommonBitsSetCommutative(A, B) || | 
|  | haveNoCommonBitsSetCommutative(B, A)) | 
|  | return true; | 
|  | return KnownBits::haveNoCommonBitsSet(computeKnownBits(A), | 
|  | computeKnownBits(B)); | 
|  | } | 
|  |  | 
|  | static SDValue FoldSTEP_VECTOR(const SDLoc &DL, EVT VT, SDValue Step, | 
|  | SelectionDAG &DAG) { | 
|  | if (cast<ConstantSDNode>(Step)->isZero()) | 
|  | return DAG.getConstant(0, DL, VT); | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | static SDValue FoldBUILD_VECTOR(const SDLoc &DL, EVT VT, | 
|  | ArrayRef<SDValue> Ops, | 
|  | SelectionDAG &DAG) { | 
|  | int NumOps = Ops.size(); | 
|  | assert(NumOps != 0 && "Can't build an empty vector!"); | 
|  | assert(!VT.isScalableVector() && | 
|  | "BUILD_VECTOR cannot be used with scalable types"); | 
|  | assert(VT.getVectorNumElements() == (unsigned)NumOps && | 
|  | "Incorrect element count in BUILD_VECTOR!"); | 
|  |  | 
|  | // BUILD_VECTOR of UNDEFs is UNDEF. | 
|  | if (llvm::all_of(Ops, [](SDValue Op) { return Op.isUndef(); })) | 
|  | return DAG.getUNDEF(VT); | 
|  |  | 
|  | // BUILD_VECTOR of seq extract/insert from the same vector + type is Identity. | 
|  | SDValue IdentitySrc; | 
|  | bool IsIdentity = true; | 
|  | for (int i = 0; i != NumOps; ++i) { | 
|  | if (Ops[i].getOpcode() != ISD::EXTRACT_VECTOR_ELT || | 
|  | Ops[i].getOperand(0).getValueType() != VT || | 
|  | (IdentitySrc && Ops[i].getOperand(0) != IdentitySrc) || | 
|  | !isa<ConstantSDNode>(Ops[i].getOperand(1)) || | 
|  | Ops[i].getConstantOperandAPInt(1) != i) { | 
|  | IsIdentity = false; | 
|  | break; | 
|  | } | 
|  | IdentitySrc = Ops[i].getOperand(0); | 
|  | } | 
|  | if (IsIdentity) | 
|  | return IdentitySrc; | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | /// Try to simplify vector concatenation to an input value, undef, or build | 
|  | /// vector. | 
|  | static SDValue foldCONCAT_VECTORS(const SDLoc &DL, EVT VT, | 
|  | ArrayRef<SDValue> Ops, | 
|  | SelectionDAG &DAG) { | 
|  | assert(!Ops.empty() && "Can't concatenate an empty list of vectors!"); | 
|  | assert(llvm::all_of(Ops, | 
|  | [Ops](SDValue Op) { | 
|  | return Ops[0].getValueType() == Op.getValueType(); | 
|  | }) && | 
|  | "Concatenation of vectors with inconsistent value types!"); | 
|  | assert((Ops[0].getValueType().getVectorElementCount() * Ops.size()) == | 
|  | VT.getVectorElementCount() && | 
|  | "Incorrect element count in vector concatenation!"); | 
|  |  | 
|  | if (Ops.size() == 1) | 
|  | return Ops[0]; | 
|  |  | 
|  | // Concat of UNDEFs is UNDEF. | 
|  | if (llvm::all_of(Ops, [](SDValue Op) { return Op.isUndef(); })) | 
|  | return DAG.getUNDEF(VT); | 
|  |  | 
|  | // Scan the operands and look for extract operations from a single source | 
|  | // that correspond to insertion at the same location via this concatenation: | 
|  | // concat (extract X, 0*subvec_elts), (extract X, 1*subvec_elts), ... | 
|  | SDValue IdentitySrc; | 
|  | bool IsIdentity = true; | 
|  | for (unsigned i = 0, e = Ops.size(); i != e; ++i) { | 
|  | SDValue Op = Ops[i]; | 
|  | unsigned IdentityIndex = i * Op.getValueType().getVectorMinNumElements(); | 
|  | if (Op.getOpcode() != ISD::EXTRACT_SUBVECTOR || | 
|  | Op.getOperand(0).getValueType() != VT || | 
|  | (IdentitySrc && Op.getOperand(0) != IdentitySrc) || | 
|  | Op.getConstantOperandVal(1) != IdentityIndex) { | 
|  | IsIdentity = false; | 
|  | break; | 
|  | } | 
|  | assert((!IdentitySrc || IdentitySrc == Op.getOperand(0)) && | 
|  | "Unexpected identity source vector for concat of extracts"); | 
|  | IdentitySrc = Op.getOperand(0); | 
|  | } | 
|  | if (IsIdentity) { | 
|  | assert(IdentitySrc && "Failed to set source vector of extracts"); | 
|  | return IdentitySrc; | 
|  | } | 
|  |  | 
|  | // The code below this point is only designed to work for fixed width | 
|  | // vectors, so we bail out for now. | 
|  | if (VT.isScalableVector()) | 
|  | return SDValue(); | 
|  |  | 
|  | // A CONCAT_VECTOR with all UNDEF/BUILD_VECTOR operands can be | 
|  | // simplified to one big BUILD_VECTOR. | 
|  | // FIXME: Add support for SCALAR_TO_VECTOR as well. | 
|  | EVT SVT = VT.getScalarType(); | 
|  | SmallVector<SDValue, 16> Elts; | 
|  | for (SDValue Op : Ops) { | 
|  | EVT OpVT = Op.getValueType(); | 
|  | if (Op.isUndef()) | 
|  | Elts.append(OpVT.getVectorNumElements(), DAG.getUNDEF(SVT)); | 
|  | else if (Op.getOpcode() == ISD::BUILD_VECTOR) | 
|  | Elts.append(Op->op_begin(), Op->op_end()); | 
|  | else | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | // BUILD_VECTOR requires all inputs to be of the same type, find the | 
|  | // maximum type and extend them all. | 
|  | for (SDValue Op : Elts) | 
|  | SVT = (SVT.bitsLT(Op.getValueType()) ? Op.getValueType() : SVT); | 
|  |  | 
|  | if (SVT.bitsGT(VT.getScalarType())) { | 
|  | for (SDValue &Op : Elts) { | 
|  | if (Op.isUndef()) | 
|  | Op = DAG.getUNDEF(SVT); | 
|  | else | 
|  | Op = DAG.getTargetLoweringInfo().isZExtFree(Op.getValueType(), SVT) | 
|  | ? DAG.getZExtOrTrunc(Op, DL, SVT) | 
|  | : DAG.getSExtOrTrunc(Op, DL, SVT); | 
|  | } | 
|  | } | 
|  |  | 
|  | SDValue V = DAG.getBuildVector(VT, DL, Elts); | 
|  | NewSDValueDbgMsg(V, "New node fold concat vectors: ", &DAG); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | /// Gets or creates the specified node. | 
|  | SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT) { | 
|  | SDVTList VTs = getVTList(VT); | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, Opcode, VTs, {}); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, DL, IP)) | 
|  | return SDValue(E, 0); | 
|  |  | 
|  | auto *N = newSDNode<SDNode>(Opcode, DL.getIROrder(), DL.getDebugLoc(), VTs); | 
|  | CSEMap.InsertNode(N, IP); | 
|  |  | 
|  | InsertNode(N); | 
|  | SDValue V = SDValue(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT, | 
|  | SDValue N1) { | 
|  | SDNodeFlags Flags; | 
|  | if (Inserter) | 
|  | Flags = Inserter->getFlags(); | 
|  | return getNode(Opcode, DL, VT, N1, Flags); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT, | 
|  | SDValue N1, const SDNodeFlags Flags) { | 
|  | assert(N1.getOpcode() != ISD::DELETED_NODE && "Operand is DELETED_NODE!"); | 
|  |  | 
|  | // Constant fold unary operations with a vector integer or float operand. | 
|  | switch (Opcode) { | 
|  | default: | 
|  | // FIXME: Entirely reasonable to perform folding of other unary | 
|  | // operations here as the need arises. | 
|  | break; | 
|  | case ISD::FNEG: | 
|  | case ISD::FABS: | 
|  | case ISD::FCEIL: | 
|  | case ISD::FTRUNC: | 
|  | case ISD::FFLOOR: | 
|  | case ISD::FP_EXTEND: | 
|  | case ISD::FP_TO_SINT: | 
|  | case ISD::FP_TO_UINT: | 
|  | case ISD::FP_TO_FP16: | 
|  | case ISD::FP_TO_BF16: | 
|  | case ISD::TRUNCATE: | 
|  | case ISD::ANY_EXTEND: | 
|  | case ISD::ZERO_EXTEND: | 
|  | case ISD::SIGN_EXTEND: | 
|  | case ISD::UINT_TO_FP: | 
|  | case ISD::SINT_TO_FP: | 
|  | case ISD::FP16_TO_FP: | 
|  | case ISD::BF16_TO_FP: | 
|  | case ISD::BITCAST: | 
|  | case ISD::ABS: | 
|  | case ISD::BITREVERSE: | 
|  | case ISD::BSWAP: | 
|  | case ISD::CTLZ: | 
|  | case ISD::CTLZ_ZERO_UNDEF: | 
|  | case ISD::CTTZ: | 
|  | case ISD::CTTZ_ZERO_UNDEF: | 
|  | case ISD::CTPOP: | 
|  | case ISD::STEP_VECTOR: { | 
|  | SDValue Ops = {N1}; | 
|  | if (SDValue Fold = FoldConstantArithmetic(Opcode, DL, VT, Ops)) | 
|  | return Fold; | 
|  | } | 
|  | } | 
|  |  | 
|  | unsigned OpOpcode = N1.getNode()->getOpcode(); | 
|  | switch (Opcode) { | 
|  | case ISD::STEP_VECTOR: | 
|  | assert(VT.isScalableVector() && | 
|  | "STEP_VECTOR can only be used with scalable types"); | 
|  | assert(OpOpcode == ISD::TargetConstant && | 
|  | VT.getVectorElementType() == N1.getValueType() && | 
|  | "Unexpected step operand"); | 
|  | break; | 
|  | case ISD::FREEZE: | 
|  | assert(VT == N1.getValueType() && "Unexpected VT!"); | 
|  | if (isGuaranteedNotToBeUndefOrPoison(N1, /*PoisonOnly=*/false)) | 
|  | return N1; | 
|  | break; | 
|  | case ISD::TokenFactor: | 
|  | case ISD::MERGE_VALUES: | 
|  | case ISD::CONCAT_VECTORS: | 
|  | return N1;         // Factor, merge or concat of one node?  No need. | 
|  | case ISD::BUILD_VECTOR: { | 
|  | // Attempt to simplify BUILD_VECTOR. | 
|  | SDValue Ops[] = {N1}; | 
|  | if (SDValue V = FoldBUILD_VECTOR(DL, VT, Ops, *this)) | 
|  | return V; | 
|  | break; | 
|  | } | 
|  | case ISD::FP_ROUND: llvm_unreachable("Invalid method to make FP_ROUND node"); | 
|  | case ISD::FP_EXTEND: | 
|  | assert(VT.isFloatingPoint() && N1.getValueType().isFloatingPoint() && | 
|  | "Invalid FP cast!"); | 
|  | if (N1.getValueType() == VT) return N1;  // noop conversion. | 
|  | assert((!VT.isVector() || VT.getVectorElementCount() == | 
|  | N1.getValueType().getVectorElementCount()) && | 
|  | "Vector element count mismatch!"); | 
|  | assert(N1.getValueType().bitsLT(VT) && "Invalid fpext node, dst < src!"); | 
|  | if (N1.isUndef()) | 
|  | return getUNDEF(VT); | 
|  | break; | 
|  | case ISD::FP_TO_SINT: | 
|  | case ISD::FP_TO_UINT: | 
|  | if (N1.isUndef()) | 
|  | return getUNDEF(VT); | 
|  | break; | 
|  | case ISD::SINT_TO_FP: | 
|  | case ISD::UINT_TO_FP: | 
|  | // [us]itofp(undef) = 0, because the result value is bounded. | 
|  | if (N1.isUndef()) | 
|  | return getConstantFP(0.0, DL, VT); | 
|  | break; | 
|  | case ISD::SIGN_EXTEND: | 
|  | assert(VT.isInteger() && N1.getValueType().isInteger() && | 
|  | "Invalid SIGN_EXTEND!"); | 
|  | assert(VT.isVector() == N1.getValueType().isVector() && | 
|  | "SIGN_EXTEND result type type should be vector iff the operand " | 
|  | "type is vector!"); | 
|  | if (N1.getValueType() == VT) return N1;   // noop extension | 
|  | assert((!VT.isVector() || VT.getVectorElementCount() == | 
|  | N1.getValueType().getVectorElementCount()) && | 
|  | "Vector element count mismatch!"); | 
|  | assert(N1.getValueType().bitsLT(VT) && "Invalid sext node, dst < src!"); | 
|  | if (OpOpcode == ISD::SIGN_EXTEND || OpOpcode == ISD::ZERO_EXTEND) { | 
|  | SDNodeFlags Flags; | 
|  | if (OpOpcode == ISD::ZERO_EXTEND) | 
|  | Flags.setNonNeg(N1->getFlags().hasNonNeg()); | 
|  | SDValue NewVal = getNode(OpOpcode, DL, VT, N1.getOperand(0), Flags); | 
|  | transferDbgValues(N1, NewVal); | 
|  | return NewVal; | 
|  | } | 
|  |  | 
|  | if (OpOpcode == ISD::POISON) | 
|  | return getPOISON(VT); | 
|  |  | 
|  | if (N1.isUndef()) | 
|  | // sext(undef) = 0, because the top bits will all be the same. | 
|  | return getConstant(0, DL, VT); | 
|  |  | 
|  | // Skip unnecessary sext_inreg pattern: | 
|  | // (sext (trunc x)) -> x iff the upper bits are all signbits. | 
|  | if (OpOpcode == ISD::TRUNCATE) { | 
|  | SDValue OpOp = N1.getOperand(0); | 
|  | if (OpOp.getValueType() == VT) { | 
|  | unsigned NumSignExtBits = | 
|  | VT.getScalarSizeInBits() - N1.getScalarValueSizeInBits(); | 
|  | if (ComputeNumSignBits(OpOp) > NumSignExtBits) { | 
|  | transferDbgValues(N1, OpOp); | 
|  | return OpOp; | 
|  | } | 
|  | } | 
|  | } | 
|  | break; | 
|  | case ISD::ZERO_EXTEND: | 
|  | assert(VT.isInteger() && N1.getValueType().isInteger() && | 
|  | "Invalid ZERO_EXTEND!"); | 
|  | assert(VT.isVector() == N1.getValueType().isVector() && | 
|  | "ZERO_EXTEND result type type should be vector iff the operand " | 
|  | "type is vector!"); | 
|  | if (N1.getValueType() == VT) return N1;   // noop extension | 
|  | assert((!VT.isVector() || VT.getVectorElementCount() == | 
|  | N1.getValueType().getVectorElementCount()) && | 
|  | "Vector element count mismatch!"); | 
|  | assert(N1.getValueType().bitsLT(VT) && "Invalid zext node, dst < src!"); | 
|  | if (OpOpcode == ISD::ZERO_EXTEND) { // (zext (zext x)) -> (zext x) | 
|  | SDNodeFlags Flags; | 
|  | Flags.setNonNeg(N1->getFlags().hasNonNeg()); | 
|  | SDValue NewVal = | 
|  | getNode(ISD::ZERO_EXTEND, DL, VT, N1.getOperand(0), Flags); | 
|  | transferDbgValues(N1, NewVal); | 
|  | return NewVal; | 
|  | } | 
|  |  | 
|  | if (OpOpcode == ISD::POISON) | 
|  | return getPOISON(VT); | 
|  |  | 
|  | if (N1.isUndef()) | 
|  | // zext(undef) = 0, because the top bits will be zero. | 
|  | return getConstant(0, DL, VT); | 
|  |  | 
|  | // Skip unnecessary zext_inreg pattern: | 
|  | // (zext (trunc x)) -> x iff the upper bits are known zero. | 
|  | // TODO: Remove (zext (trunc (and x, c))) exception which some targets | 
|  | // use to recognise zext_inreg patterns. | 
|  | if (OpOpcode == ISD::TRUNCATE) { | 
|  | SDValue OpOp = N1.getOperand(0); | 
|  | if (OpOp.getValueType() == VT) { | 
|  | if (OpOp.getOpcode() != ISD::AND) { | 
|  | APInt HiBits = APInt::getBitsSetFrom(VT.getScalarSizeInBits(), | 
|  | N1.getScalarValueSizeInBits()); | 
|  | if (MaskedValueIsZero(OpOp, HiBits)) { | 
|  | transferDbgValues(N1, OpOp); | 
|  | return OpOp; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | break; | 
|  | case ISD::ANY_EXTEND: | 
|  | assert(VT.isInteger() && N1.getValueType().isInteger() && | 
|  | "Invalid ANY_EXTEND!"); | 
|  | assert(VT.isVector() == N1.getValueType().isVector() && | 
|  | "ANY_EXTEND result type type should be vector iff the operand " | 
|  | "type is vector!"); | 
|  | if (N1.getValueType() == VT) return N1;   // noop extension | 
|  | assert((!VT.isVector() || VT.getVectorElementCount() == | 
|  | N1.getValueType().getVectorElementCount()) && | 
|  | "Vector element count mismatch!"); | 
|  | assert(N1.getValueType().bitsLT(VT) && "Invalid anyext node, dst < src!"); | 
|  |  | 
|  | if (OpOpcode == ISD::ZERO_EXTEND || OpOpcode == ISD::SIGN_EXTEND || | 
|  | OpOpcode == ISD::ANY_EXTEND) { | 
|  | SDNodeFlags Flags; | 
|  | if (OpOpcode == ISD::ZERO_EXTEND) | 
|  | Flags.setNonNeg(N1->getFlags().hasNonNeg()); | 
|  | // (ext (zext x)) -> (zext x)  and  (ext (sext x)) -> (sext x) | 
|  | return getNode(OpOpcode, DL, VT, N1.getOperand(0), Flags); | 
|  | } | 
|  | if (N1.isUndef()) | 
|  | return getUNDEF(VT); | 
|  |  | 
|  | // (ext (trunc x)) -> x | 
|  | if (OpOpcode == ISD::TRUNCATE) { | 
|  | SDValue OpOp = N1.getOperand(0); | 
|  | if (OpOp.getValueType() == VT) { | 
|  | transferDbgValues(N1, OpOp); | 
|  | return OpOp; | 
|  | } | 
|  | } | 
|  | break; | 
|  | case ISD::TRUNCATE: | 
|  | assert(VT.isInteger() && N1.getValueType().isInteger() && | 
|  | "Invalid TRUNCATE!"); | 
|  | assert(VT.isVector() == N1.getValueType().isVector() && | 
|  | "TRUNCATE result type type should be vector iff the operand " | 
|  | "type is vector!"); | 
|  | if (N1.getValueType() == VT) return N1;   // noop truncate | 
|  | assert((!VT.isVector() || VT.getVectorElementCount() == | 
|  | N1.getValueType().getVectorElementCount()) && | 
|  | "Vector element count mismatch!"); | 
|  | assert(N1.getValueType().bitsGT(VT) && "Invalid truncate node, src < dst!"); | 
|  | if (OpOpcode == ISD::TRUNCATE) | 
|  | return getNode(ISD::TRUNCATE, DL, VT, N1.getOperand(0)); | 
|  | if (OpOpcode == ISD::ZERO_EXTEND || OpOpcode == ISD::SIGN_EXTEND || | 
|  | OpOpcode == ISD::ANY_EXTEND) { | 
|  | // If the source is smaller than the dest, we still need an extend. | 
|  | if (N1.getOperand(0).getValueType().getScalarType().bitsLT( | 
|  | VT.getScalarType())) { | 
|  | SDNodeFlags Flags; | 
|  | if (OpOpcode == ISD::ZERO_EXTEND) | 
|  | Flags.setNonNeg(N1->getFlags().hasNonNeg()); | 
|  | return getNode(OpOpcode, DL, VT, N1.getOperand(0), Flags); | 
|  | } | 
|  | if (N1.getOperand(0).getValueType().bitsGT(VT)) | 
|  | return getNode(ISD::TRUNCATE, DL, VT, N1.getOperand(0)); | 
|  | return N1.getOperand(0); | 
|  | } | 
|  | if (N1.isUndef()) | 
|  | return getUNDEF(VT); | 
|  | if (OpOpcode == ISD::VSCALE && !NewNodesMustHaveLegalTypes) | 
|  | return getVScale(DL, VT, | 
|  | N1.getConstantOperandAPInt(0).trunc(VT.getSizeInBits())); | 
|  | break; | 
|  | case ISD::ANY_EXTEND_VECTOR_INREG: | 
|  | case ISD::ZERO_EXTEND_VECTOR_INREG: | 
|  | case ISD::SIGN_EXTEND_VECTOR_INREG: | 
|  | assert(VT.isVector() && "This DAG node is restricted to vector types."); | 
|  | assert(N1.getValueType().bitsLE(VT) && | 
|  | "The input must be the same size or smaller than the result."); | 
|  | assert(VT.getVectorMinNumElements() < | 
|  | N1.getValueType().getVectorMinNumElements() && | 
|  | "The destination vector type must have fewer lanes than the input."); | 
|  | break; | 
|  | case ISD::ABS: | 
|  | assert(VT.isInteger() && VT == N1.getValueType() && "Invalid ABS!"); | 
|  | if (N1.isUndef()) | 
|  | return getConstant(0, DL, VT); | 
|  | break; | 
|  | case ISD::BSWAP: | 
|  | assert(VT.isInteger() && VT == N1.getValueType() && "Invalid BSWAP!"); | 
|  | assert((VT.getScalarSizeInBits() % 16 == 0) && | 
|  | "BSWAP types must be a multiple of 16 bits!"); | 
|  | if (N1.isUndef()) | 
|  | return getUNDEF(VT); | 
|  | // bswap(bswap(X)) -> X. | 
|  | if (OpOpcode == ISD::BSWAP) | 
|  | return N1.getOperand(0); | 
|  | break; | 
|  | case ISD::BITREVERSE: | 
|  | assert(VT.isInteger() && VT == N1.getValueType() && "Invalid BITREVERSE!"); | 
|  | if (N1.isUndef()) | 
|  | return getUNDEF(VT); | 
|  | break; | 
|  | case ISD::BITCAST: | 
|  | assert(VT.getSizeInBits() == N1.getValueSizeInBits() && | 
|  | "Cannot BITCAST between types of different sizes!"); | 
|  | if (VT == N1.getValueType()) return N1;   // noop conversion. | 
|  | if (OpOpcode == ISD::BITCAST) // bitconv(bitconv(x)) -> bitconv(x) | 
|  | return getNode(ISD::BITCAST, DL, VT, N1.getOperand(0)); | 
|  | if (N1.isUndef()) | 
|  | return getUNDEF(VT); | 
|  | break; | 
|  | case ISD::SCALAR_TO_VECTOR: | 
|  | assert(VT.isVector() && !N1.getValueType().isVector() && | 
|  | (VT.getVectorElementType() == N1.getValueType() || | 
|  | (VT.getVectorElementType().isInteger() && | 
|  | N1.getValueType().isInteger() && | 
|  | VT.getVectorElementType().bitsLE(N1.getValueType()))) && | 
|  | "Illegal SCALAR_TO_VECTOR node!"); | 
|  | if (N1.isUndef()) | 
|  | return getUNDEF(VT); | 
|  | // scalar_to_vector(extract_vector_elt V, 0) -> V, top bits are undefined. | 
|  | if (OpOpcode == ISD::EXTRACT_VECTOR_ELT && | 
|  | isa<ConstantSDNode>(N1.getOperand(1)) && | 
|  | N1.getConstantOperandVal(1) == 0 && | 
|  | N1.getOperand(0).getValueType() == VT) | 
|  | return N1.getOperand(0); | 
|  | break; | 
|  | case ISD::FNEG: | 
|  | // Negation of an unknown bag of bits is still completely undefined. | 
|  | if (N1.isUndef()) | 
|  | return getUNDEF(VT); | 
|  |  | 
|  | if (OpOpcode == ISD::FNEG) // --X -> X | 
|  | return N1.getOperand(0); | 
|  | break; | 
|  | case ISD::FABS: | 
|  | if (OpOpcode == ISD::FNEG) // abs(-X) -> abs(X) | 
|  | return getNode(ISD::FABS, DL, VT, N1.getOperand(0)); | 
|  | break; | 
|  | case ISD::VSCALE: | 
|  | assert(VT == N1.getValueType() && "Unexpected VT!"); | 
|  | break; | 
|  | case ISD::CTPOP: | 
|  | if (N1.getValueType().getScalarType() == MVT::i1) | 
|  | return N1; | 
|  | break; | 
|  | case ISD::CTLZ: | 
|  | case ISD::CTTZ: | 
|  | if (N1.getValueType().getScalarType() == MVT::i1) | 
|  | return getNOT(DL, N1, N1.getValueType()); | 
|  | break; | 
|  | case ISD::VECREDUCE_ADD: | 
|  | if (N1.getValueType().getScalarType() == MVT::i1) | 
|  | return getNode(ISD::VECREDUCE_XOR, DL, VT, N1); | 
|  | break; | 
|  | case ISD::VECREDUCE_SMIN: | 
|  | case ISD::VECREDUCE_UMAX: | 
|  | if (N1.getValueType().getScalarType() == MVT::i1) | 
|  | return getNode(ISD::VECREDUCE_OR, DL, VT, N1); | 
|  | break; | 
|  | case ISD::VECREDUCE_SMAX: | 
|  | case ISD::VECREDUCE_UMIN: | 
|  | if (N1.getValueType().getScalarType() == MVT::i1) | 
|  | return getNode(ISD::VECREDUCE_AND, DL, VT, N1); | 
|  | break; | 
|  | case ISD::SPLAT_VECTOR: | 
|  | assert(VT.isVector() && "Wrong return type!"); | 
|  | // FIXME: Hexagon uses i32 scalar for a floating point zero vector so allow | 
|  | // that for now. | 
|  | assert((VT.getVectorElementType() == N1.getValueType() || | 
|  | (VT.isFloatingPoint() && N1.getValueType() == MVT::i32) || | 
|  | (VT.getVectorElementType().isInteger() && | 
|  | N1.getValueType().isInteger() && | 
|  | VT.getVectorElementType().bitsLE(N1.getValueType()))) && | 
|  | "Wrong operand type!"); | 
|  | break; | 
|  | } | 
|  |  | 
|  | SDNode *N; | 
|  | SDVTList VTs = getVTList(VT); | 
|  | SDValue Ops[] = {N1}; | 
|  | if (VT != MVT::Glue) { // Don't CSE glue producing nodes | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, Opcode, VTs, Ops); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, DL, IP)) { | 
|  | E->intersectFlagsWith(Flags); | 
|  | return SDValue(E, 0); | 
|  | } | 
|  |  | 
|  | N = newSDNode<SDNode>(Opcode, DL.getIROrder(), DL.getDebugLoc(), VTs); | 
|  | N->setFlags(Flags); | 
|  | createOperands(N, Ops); | 
|  | CSEMap.InsertNode(N, IP); | 
|  | } else { | 
|  | N = newSDNode<SDNode>(Opcode, DL.getIROrder(), DL.getDebugLoc(), VTs); | 
|  | createOperands(N, Ops); | 
|  | } | 
|  |  | 
|  | InsertNode(N); | 
|  | SDValue V = SDValue(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | static std::optional<APInt> FoldValue(unsigned Opcode, const APInt &C1, | 
|  | const APInt &C2) { | 
|  | switch (Opcode) { | 
|  | case ISD::ADD:  return C1 + C2; | 
|  | case ISD::SUB:  return C1 - C2; | 
|  | case ISD::MUL:  return C1 * C2; | 
|  | case ISD::AND:  return C1 & C2; | 
|  | case ISD::OR:   return C1 | C2; | 
|  | case ISD::XOR:  return C1 ^ C2; | 
|  | case ISD::SHL:  return C1 << C2; | 
|  | case ISD::SRL:  return C1.lshr(C2); | 
|  | case ISD::SRA:  return C1.ashr(C2); | 
|  | case ISD::ROTL: return C1.rotl(C2); | 
|  | case ISD::ROTR: return C1.rotr(C2); | 
|  | case ISD::SMIN: return C1.sle(C2) ? C1 : C2; | 
|  | case ISD::SMAX: return C1.sge(C2) ? C1 : C2; | 
|  | case ISD::UMIN: return C1.ule(C2) ? C1 : C2; | 
|  | case ISD::UMAX: return C1.uge(C2) ? C1 : C2; | 
|  | case ISD::SADDSAT: return C1.sadd_sat(C2); | 
|  | case ISD::UADDSAT: return C1.uadd_sat(C2); | 
|  | case ISD::SSUBSAT: return C1.ssub_sat(C2); | 
|  | case ISD::USUBSAT: return C1.usub_sat(C2); | 
|  | case ISD::SSHLSAT: return C1.sshl_sat(C2); | 
|  | case ISD::USHLSAT: return C1.ushl_sat(C2); | 
|  | case ISD::UDIV: | 
|  | if (!C2.getBoolValue()) | 
|  | break; | 
|  | return C1.udiv(C2); | 
|  | case ISD::UREM: | 
|  | if (!C2.getBoolValue()) | 
|  | break; | 
|  | return C1.urem(C2); | 
|  | case ISD::SDIV: | 
|  | if (!C2.getBoolValue()) | 
|  | break; | 
|  | return C1.sdiv(C2); | 
|  | case ISD::SREM: | 
|  | if (!C2.getBoolValue()) | 
|  | break; | 
|  | return C1.srem(C2); | 
|  | case ISD::AVGFLOORS: | 
|  | return APIntOps::avgFloorS(C1, C2); | 
|  | case ISD::AVGFLOORU: | 
|  | return APIntOps::avgFloorU(C1, C2); | 
|  | case ISD::AVGCEILS: | 
|  | return APIntOps::avgCeilS(C1, C2); | 
|  | case ISD::AVGCEILU: | 
|  | return APIntOps::avgCeilU(C1, C2); | 
|  | case ISD::ABDS: | 
|  | return APIntOps::abds(C1, C2); | 
|  | case ISD::ABDU: | 
|  | return APIntOps::abdu(C1, C2); | 
|  | case ISD::MULHS: | 
|  | return APIntOps::mulhs(C1, C2); | 
|  | case ISD::MULHU: | 
|  | return APIntOps::mulhu(C1, C2); | 
|  | } | 
|  | return std::nullopt; | 
|  | } | 
|  | // Handle constant folding with UNDEF. | 
|  | // TODO: Handle more cases. | 
|  | static std::optional<APInt> FoldValueWithUndef(unsigned Opcode, const APInt &C1, | 
|  | bool IsUndef1, const APInt &C2, | 
|  | bool IsUndef2) { | 
|  | if (!(IsUndef1 || IsUndef2)) | 
|  | return FoldValue(Opcode, C1, C2); | 
|  |  | 
|  | // Fold and(x, undef) -> 0 | 
|  | // Fold mul(x, undef) -> 0 | 
|  | if (Opcode == ISD::AND || Opcode == ISD::MUL) | 
|  | return APInt::getZero(C1.getBitWidth()); | 
|  |  | 
|  | return std::nullopt; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::FoldSymbolOffset(unsigned Opcode, EVT VT, | 
|  | const GlobalAddressSDNode *GA, | 
|  | const SDNode *N2) { | 
|  | if (GA->getOpcode() != ISD::GlobalAddress) | 
|  | return SDValue(); | 
|  | if (!TLI->isOffsetFoldingLegal(GA)) | 
|  | return SDValue(); | 
|  | auto *C2 = dyn_cast<ConstantSDNode>(N2); | 
|  | if (!C2) | 
|  | return SDValue(); | 
|  | int64_t Offset = C2->getSExtValue(); | 
|  | switch (Opcode) { | 
|  | case ISD::ADD: | 
|  | case ISD::PTRADD: | 
|  | break; | 
|  | case ISD::SUB: Offset = -uint64_t(Offset); break; | 
|  | default: return SDValue(); | 
|  | } | 
|  | return getGlobalAddress(GA->getGlobal(), SDLoc(C2), VT, | 
|  | GA->getOffset() + uint64_t(Offset)); | 
|  | } | 
|  |  | 
|  | bool SelectionDAG::isUndef(unsigned Opcode, ArrayRef<SDValue> Ops) { | 
|  | switch (Opcode) { | 
|  | case ISD::SDIV: | 
|  | case ISD::UDIV: | 
|  | case ISD::SREM: | 
|  | case ISD::UREM: { | 
|  | // If a divisor is zero/undef or any element of a divisor vector is | 
|  | // zero/undef, the whole op is undef. | 
|  | assert(Ops.size() == 2 && "Div/rem should have 2 operands"); | 
|  | SDValue Divisor = Ops[1]; | 
|  | if (Divisor.isUndef() || isNullConstant(Divisor)) | 
|  | return true; | 
|  |  | 
|  | return ISD::isBuildVectorOfConstantSDNodes(Divisor.getNode()) && | 
|  | llvm::any_of(Divisor->op_values(), | 
|  | [](SDValue V) { return V.isUndef() || | 
|  | isNullConstant(V); }); | 
|  | // TODO: Handle signed overflow. | 
|  | } | 
|  | // TODO: Handle oversized shifts. | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::FoldConstantArithmetic(unsigned Opcode, const SDLoc &DL, | 
|  | EVT VT, ArrayRef<SDValue> Ops, | 
|  | SDNodeFlags Flags) { | 
|  | // If the opcode is a target-specific ISD node, there's nothing we can | 
|  | // do here and the operand rules may not line up with the below, so | 
|  | // bail early. | 
|  | // We can't create a scalar CONCAT_VECTORS so skip it. It will break | 
|  | // for concats involving SPLAT_VECTOR. Concats of BUILD_VECTORS are handled by | 
|  | // foldCONCAT_VECTORS in getNode before this is called. | 
|  | if (Opcode >= ISD::BUILTIN_OP_END || Opcode == ISD::CONCAT_VECTORS) | 
|  | return SDValue(); | 
|  |  | 
|  | unsigned NumOps = Ops.size(); | 
|  | if (NumOps == 0) | 
|  | return SDValue(); | 
|  |  | 
|  | if (isUndef(Opcode, Ops)) | 
|  | return getUNDEF(VT); | 
|  |  | 
|  | // Handle unary special cases. | 
|  | if (NumOps == 1) { | 
|  | SDValue N1 = Ops[0]; | 
|  |  | 
|  | // Constant fold unary operations with an integer constant operand. Even | 
|  | // opaque constant will be folded, because the folding of unary operations | 
|  | // doesn't create new constants with different values. Nevertheless, the | 
|  | // opaque flag is preserved during folding to prevent future folding with | 
|  | // other constants. | 
|  | if (auto *C = dyn_cast<ConstantSDNode>(N1)) { | 
|  | const APInt &Val = C->getAPIntValue(); | 
|  | switch (Opcode) { | 
|  | case ISD::SIGN_EXTEND: | 
|  | return getConstant(Val.sextOrTrunc(VT.getSizeInBits()), DL, VT, | 
|  | C->isTargetOpcode(), C->isOpaque()); | 
|  | case ISD::TRUNCATE: | 
|  | if (C->isOpaque()) | 
|  | break; | 
|  | [[fallthrough]]; | 
|  | case ISD::ZERO_EXTEND: | 
|  | return getConstant(Val.zextOrTrunc(VT.getSizeInBits()), DL, VT, | 
|  | C->isTargetOpcode(), C->isOpaque()); | 
|  | case ISD::ANY_EXTEND: | 
|  | // Some targets like RISCV prefer to sign extend some types. | 
|  | if (TLI->isSExtCheaperThanZExt(N1.getValueType(), VT)) | 
|  | return getConstant(Val.sextOrTrunc(VT.getSizeInBits()), DL, VT, | 
|  | C->isTargetOpcode(), C->isOpaque()); | 
|  | return getConstant(Val.zextOrTrunc(VT.getSizeInBits()), DL, VT, | 
|  | C->isTargetOpcode(), C->isOpaque()); | 
|  | case ISD::ABS: | 
|  | return getConstant(Val.abs(), DL, VT, C->isTargetOpcode(), | 
|  | C->isOpaque()); | 
|  | case ISD::BITREVERSE: | 
|  | return getConstant(Val.reverseBits(), DL, VT, C->isTargetOpcode(), | 
|  | C->isOpaque()); | 
|  | case ISD::BSWAP: | 
|  | return getConstant(Val.byteSwap(), DL, VT, C->isTargetOpcode(), | 
|  | C->isOpaque()); | 
|  | case ISD::CTPOP: | 
|  | return getConstant(Val.popcount(), DL, VT, C->isTargetOpcode(), | 
|  | C->isOpaque()); | 
|  | case ISD::CTLZ: | 
|  | case ISD::CTLZ_ZERO_UNDEF: | 
|  | return getConstant(Val.countl_zero(), DL, VT, C->isTargetOpcode(), | 
|  | C->isOpaque()); | 
|  | case ISD::CTTZ: | 
|  | case ISD::CTTZ_ZERO_UNDEF: | 
|  | return getConstant(Val.countr_zero(), DL, VT, C->isTargetOpcode(), | 
|  | C->isOpaque()); | 
|  | case ISD::UINT_TO_FP: | 
|  | case ISD::SINT_TO_FP: { | 
|  | APFloat FPV(VT.getFltSemantics(), APInt::getZero(VT.getSizeInBits())); | 
|  | (void)FPV.convertFromAPInt(Val, Opcode == ISD::SINT_TO_FP, | 
|  | APFloat::rmNearestTiesToEven); | 
|  | return getConstantFP(FPV, DL, VT); | 
|  | } | 
|  | case ISD::FP16_TO_FP: | 
|  | case ISD::BF16_TO_FP: { | 
|  | bool Ignored; | 
|  | APFloat FPV(Opcode == ISD::FP16_TO_FP ? APFloat::IEEEhalf() | 
|  | : APFloat::BFloat(), | 
|  | (Val.getBitWidth() == 16) ? Val : Val.trunc(16)); | 
|  |  | 
|  | // This can return overflow, underflow, or inexact; we don't care. | 
|  | // FIXME need to be more flexible about rounding mode. | 
|  | (void)FPV.convert(VT.getFltSemantics(), APFloat::rmNearestTiesToEven, | 
|  | &Ignored); | 
|  | return getConstantFP(FPV, DL, VT); | 
|  | } | 
|  | case ISD::STEP_VECTOR: | 
|  | if (SDValue V = FoldSTEP_VECTOR(DL, VT, N1, *this)) | 
|  | return V; | 
|  | break; | 
|  | case ISD::BITCAST: | 
|  | if (VT == MVT::f16 && C->getValueType(0) == MVT::i16) | 
|  | return getConstantFP(APFloat(APFloat::IEEEhalf(), Val), DL, VT); | 
|  | if (VT == MVT::f32 && C->getValueType(0) == MVT::i32) | 
|  | return getConstantFP(APFloat(APFloat::IEEEsingle(), Val), DL, VT); | 
|  | if (VT == MVT::f64 && C->getValueType(0) == MVT::i64) | 
|  | return getConstantFP(APFloat(APFloat::IEEEdouble(), Val), DL, VT); | 
|  | if (VT == MVT::f128 && C->getValueType(0) == MVT::i128) | 
|  | return getConstantFP(APFloat(APFloat::IEEEquad(), Val), DL, VT); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Constant fold unary operations with a floating point constant operand. | 
|  | if (auto *C = dyn_cast<ConstantFPSDNode>(N1)) { | 
|  | APFloat V = C->getValueAPF(); // make copy | 
|  | switch (Opcode) { | 
|  | case ISD::FNEG: | 
|  | V.changeSign(); | 
|  | return getConstantFP(V, DL, VT); | 
|  | case ISD::FABS: | 
|  | V.clearSign(); | 
|  | return getConstantFP(V, DL, VT); | 
|  | case ISD::FCEIL: { | 
|  | APFloat::opStatus fs = V.roundToIntegral(APFloat::rmTowardPositive); | 
|  | if (fs == APFloat::opOK || fs == APFloat::opInexact) | 
|  | return getConstantFP(V, DL, VT); | 
|  | return SDValue(); | 
|  | } | 
|  | case ISD::FTRUNC: { | 
|  | APFloat::opStatus fs = V.roundToIntegral(APFloat::rmTowardZero); | 
|  | if (fs == APFloat::opOK || fs == APFloat::opInexact) | 
|  | return getConstantFP(V, DL, VT); | 
|  | return SDValue(); | 
|  | } | 
|  | case ISD::FFLOOR: { | 
|  | APFloat::opStatus fs = V.roundToIntegral(APFloat::rmTowardNegative); | 
|  | if (fs == APFloat::opOK || fs == APFloat::opInexact) | 
|  | return getConstantFP(V, DL, VT); | 
|  | return SDValue(); | 
|  | } | 
|  | case ISD::FP_EXTEND: { | 
|  | bool ignored; | 
|  | // This can return overflow, underflow, or inexact; we don't care. | 
|  | // FIXME need to be more flexible about rounding mode. | 
|  | (void)V.convert(VT.getFltSemantics(), APFloat::rmNearestTiesToEven, | 
|  | &ignored); | 
|  | return getConstantFP(V, DL, VT); | 
|  | } | 
|  | case ISD::FP_TO_SINT: | 
|  | case ISD::FP_TO_UINT: { | 
|  | bool ignored; | 
|  | APSInt IntVal(VT.getSizeInBits(), Opcode == ISD::FP_TO_UINT); | 
|  | // FIXME need to be more flexible about rounding mode. | 
|  | APFloat::opStatus s = | 
|  | V.convertToInteger(IntVal, APFloat::rmTowardZero, &ignored); | 
|  | if (s == APFloat::opInvalidOp) // inexact is OK, in fact usual | 
|  | break; | 
|  | return getConstant(IntVal, DL, VT); | 
|  | } | 
|  | case ISD::FP_TO_FP16: | 
|  | case ISD::FP_TO_BF16: { | 
|  | bool Ignored; | 
|  | // This can return overflow, underflow, or inexact; we don't care. | 
|  | // FIXME need to be more flexible about rounding mode. | 
|  | (void)V.convert(Opcode == ISD::FP_TO_FP16 ? APFloat::IEEEhalf() | 
|  | : APFloat::BFloat(), | 
|  | APFloat::rmNearestTiesToEven, &Ignored); | 
|  | return getConstant(V.bitcastToAPInt().getZExtValue(), DL, VT); | 
|  | } | 
|  | case ISD::BITCAST: | 
|  | if (VT == MVT::i16 && C->getValueType(0) == MVT::f16) | 
|  | return getConstant((uint16_t)V.bitcastToAPInt().getZExtValue(), DL, | 
|  | VT); | 
|  | if (VT == MVT::i16 && C->getValueType(0) == MVT::bf16) | 
|  | return getConstant((uint16_t)V.bitcastToAPInt().getZExtValue(), DL, | 
|  | VT); | 
|  | if (VT == MVT::i32 && C->getValueType(0) == MVT::f32) | 
|  | return getConstant((uint32_t)V.bitcastToAPInt().getZExtValue(), DL, | 
|  | VT); | 
|  | if (VT == MVT::i64 && C->getValueType(0) == MVT::f64) | 
|  | return getConstant(V.bitcastToAPInt().getZExtValue(), DL, VT); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Early-out if we failed to constant fold a bitcast. | 
|  | if (Opcode == ISD::BITCAST) | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | // Handle binops special cases. | 
|  | if (NumOps == 2) { | 
|  | if (SDValue CFP = foldConstantFPMath(Opcode, DL, VT, Ops)) | 
|  | return CFP; | 
|  |  | 
|  | if (auto *C1 = dyn_cast<ConstantSDNode>(Ops[0])) { | 
|  | if (auto *C2 = dyn_cast<ConstantSDNode>(Ops[1])) { | 
|  | if (C1->isOpaque() || C2->isOpaque()) | 
|  | return SDValue(); | 
|  |  | 
|  | std::optional<APInt> FoldAttempt = | 
|  | FoldValue(Opcode, C1->getAPIntValue(), C2->getAPIntValue()); | 
|  | if (!FoldAttempt) | 
|  | return SDValue(); | 
|  |  | 
|  | SDValue Folded = getConstant(*FoldAttempt, DL, VT); | 
|  | assert((!Folded || !VT.isVector()) && | 
|  | "Can't fold vectors ops with scalar operands"); | 
|  | return Folded; | 
|  | } | 
|  | } | 
|  |  | 
|  | // fold (add Sym, c) -> Sym+c | 
|  | if (GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Ops[0])) | 
|  | return FoldSymbolOffset(Opcode, VT, GA, Ops[1].getNode()); | 
|  | if (TLI->isCommutativeBinOp(Opcode)) | 
|  | if (GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Ops[1])) | 
|  | return FoldSymbolOffset(Opcode, VT, GA, Ops[0].getNode()); | 
|  |  | 
|  | // fold (sext_in_reg c1) -> c2 | 
|  | if (Opcode == ISD::SIGN_EXTEND_INREG) { | 
|  | EVT EVT = cast<VTSDNode>(Ops[1])->getVT(); | 
|  |  | 
|  | auto SignExtendInReg = [&](APInt Val, llvm::EVT ConstantVT) { | 
|  | unsigned FromBits = EVT.getScalarSizeInBits(); | 
|  | Val <<= Val.getBitWidth() - FromBits; | 
|  | Val.ashrInPlace(Val.getBitWidth() - FromBits); | 
|  | return getConstant(Val, DL, ConstantVT); | 
|  | }; | 
|  |  | 
|  | if (auto *C1 = dyn_cast<ConstantSDNode>(Ops[0])) { | 
|  | const APInt &Val = C1->getAPIntValue(); | 
|  | return SignExtendInReg(Val, VT); | 
|  | } | 
|  |  | 
|  | if (ISD::isBuildVectorOfConstantSDNodes(Ops[0].getNode())) { | 
|  | SmallVector<SDValue, 8> ScalarOps; | 
|  | llvm::EVT OpVT = Ops[0].getOperand(0).getValueType(); | 
|  | for (int I = 0, E = VT.getVectorNumElements(); I != E; ++I) { | 
|  | SDValue Op = Ops[0].getOperand(I); | 
|  | if (Op.isUndef()) { | 
|  | ScalarOps.push_back(getUNDEF(OpVT)); | 
|  | continue; | 
|  | } | 
|  | const APInt &Val = cast<ConstantSDNode>(Op)->getAPIntValue(); | 
|  | ScalarOps.push_back(SignExtendInReg(Val, OpVT)); | 
|  | } | 
|  | return getBuildVector(VT, DL, ScalarOps); | 
|  | } | 
|  |  | 
|  | if (Ops[0].getOpcode() == ISD::SPLAT_VECTOR && | 
|  | isa<ConstantSDNode>(Ops[0].getOperand(0))) | 
|  | return getNode(ISD::SPLAT_VECTOR, DL, VT, | 
|  | SignExtendInReg(Ops[0].getConstantOperandAPInt(0), | 
|  | Ops[0].getOperand(0).getValueType())); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Handle fshl/fshr special cases. | 
|  | if (Opcode == ISD::FSHL || Opcode == ISD::FSHR) { | 
|  | auto *C1 = dyn_cast<ConstantSDNode>(Ops[0]); | 
|  | auto *C2 = dyn_cast<ConstantSDNode>(Ops[1]); | 
|  | auto *C3 = dyn_cast<ConstantSDNode>(Ops[2]); | 
|  |  | 
|  | if (C1 && C2 && C3) { | 
|  | if (C1->isOpaque() || C2->isOpaque() || C3->isOpaque()) | 
|  | return SDValue(); | 
|  | const APInt &V1 = C1->getAPIntValue(), &V2 = C2->getAPIntValue(), | 
|  | &V3 = C3->getAPIntValue(); | 
|  |  | 
|  | APInt FoldedVal = Opcode == ISD::FSHL ? APIntOps::fshl(V1, V2, V3) | 
|  | : APIntOps::fshr(V1, V2, V3); | 
|  | return getConstant(FoldedVal, DL, VT); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Handle fma/fmad special cases. | 
|  | if (Opcode == ISD::FMA || Opcode == ISD::FMAD) { | 
|  | assert(VT.isFloatingPoint() && "This operator only applies to FP types!"); | 
|  | assert(Ops[0].getValueType() == VT && Ops[1].getValueType() == VT && | 
|  | Ops[2].getValueType() == VT && "FMA types must match!"); | 
|  | ConstantFPSDNode *C1 = dyn_cast<ConstantFPSDNode>(Ops[0]); | 
|  | ConstantFPSDNode *C2 = dyn_cast<ConstantFPSDNode>(Ops[1]); | 
|  | ConstantFPSDNode *C3 = dyn_cast<ConstantFPSDNode>(Ops[2]); | 
|  | if (C1 && C2 && C3) { | 
|  | APFloat V1 = C1->getValueAPF(); | 
|  | const APFloat &V2 = C2->getValueAPF(); | 
|  | const APFloat &V3 = C3->getValueAPF(); | 
|  | if (Opcode == ISD::FMAD) { | 
|  | V1.multiply(V2, APFloat::rmNearestTiesToEven); | 
|  | V1.add(V3, APFloat::rmNearestTiesToEven); | 
|  | } else | 
|  | V1.fusedMultiplyAdd(V2, V3, APFloat::rmNearestTiesToEven); | 
|  | return getConstantFP(V1, DL, VT); | 
|  | } | 
|  | } | 
|  |  | 
|  | // This is for vector folding only from here on. | 
|  | if (!VT.isVector()) | 
|  | return SDValue(); | 
|  |  | 
|  | ElementCount NumElts = VT.getVectorElementCount(); | 
|  |  | 
|  | // See if we can fold through any bitcasted integer ops. | 
|  | if (NumOps == 2 && VT.isFixedLengthVector() && VT.isInteger() && | 
|  | Ops[0].getValueType() == VT && Ops[1].getValueType() == VT && | 
|  | (Ops[0].getOpcode() == ISD::BITCAST || | 
|  | Ops[1].getOpcode() == ISD::BITCAST)) { | 
|  | SDValue N1 = peekThroughBitcasts(Ops[0]); | 
|  | SDValue N2 = peekThroughBitcasts(Ops[1]); | 
|  | auto *BV1 = dyn_cast<BuildVectorSDNode>(N1); | 
|  | auto *BV2 = dyn_cast<BuildVectorSDNode>(N2); | 
|  | if (BV1 && BV2 && N1.getValueType().isInteger() && | 
|  | N2.getValueType().isInteger()) { | 
|  | bool IsLE = getDataLayout().isLittleEndian(); | 
|  | unsigned EltBits = VT.getScalarSizeInBits(); | 
|  | SmallVector<APInt> RawBits1, RawBits2; | 
|  | BitVector UndefElts1, UndefElts2; | 
|  | if (BV1->getConstantRawBits(IsLE, EltBits, RawBits1, UndefElts1) && | 
|  | BV2->getConstantRawBits(IsLE, EltBits, RawBits2, UndefElts2)) { | 
|  | SmallVector<APInt> RawBits; | 
|  | for (unsigned I = 0, E = NumElts.getFixedValue(); I != E; ++I) { | 
|  | std::optional<APInt> Fold = FoldValueWithUndef( | 
|  | Opcode, RawBits1[I], UndefElts1[I], RawBits2[I], UndefElts2[I]); | 
|  | if (!Fold) | 
|  | break; | 
|  | RawBits.push_back(*Fold); | 
|  | } | 
|  | if (RawBits.size() == NumElts.getFixedValue()) { | 
|  | // We have constant folded, but we might need to cast this again back | 
|  | // to the original (possibly legalized) type. | 
|  | EVT BVVT, BVEltVT; | 
|  | if (N1.getValueType() == VT) { | 
|  | BVVT = N1.getValueType(); | 
|  | BVEltVT = BV1->getOperand(0).getValueType(); | 
|  | } else { | 
|  | BVVT = N2.getValueType(); | 
|  | BVEltVT = BV2->getOperand(0).getValueType(); | 
|  | } | 
|  | unsigned BVEltBits = BVEltVT.getSizeInBits(); | 
|  | SmallVector<APInt> DstBits; | 
|  | BitVector DstUndefs; | 
|  | BuildVectorSDNode::recastRawBits(IsLE, BVVT.getScalarSizeInBits(), | 
|  | DstBits, RawBits, DstUndefs, | 
|  | BitVector(RawBits.size(), false)); | 
|  | SmallVector<SDValue> Ops(DstBits.size(), getUNDEF(BVEltVT)); | 
|  | for (unsigned I = 0, E = DstBits.size(); I != E; ++I) { | 
|  | if (DstUndefs[I]) | 
|  | continue; | 
|  | Ops[I] = getConstant(DstBits[I].sext(BVEltBits), DL, BVEltVT); | 
|  | } | 
|  | return getBitcast(VT, getBuildVector(BVVT, DL, Ops)); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Fold (mul step_vector(C0), C1) to (step_vector(C0 * C1)). | 
|  | //      (shl step_vector(C0), C1) -> (step_vector(C0 << C1)) | 
|  | if ((Opcode == ISD::MUL || Opcode == ISD::SHL) && | 
|  | Ops[0].getOpcode() == ISD::STEP_VECTOR) { | 
|  | APInt RHSVal; | 
|  | if (ISD::isConstantSplatVector(Ops[1].getNode(), RHSVal)) { | 
|  | APInt NewStep = Opcode == ISD::MUL | 
|  | ? Ops[0].getConstantOperandAPInt(0) * RHSVal | 
|  | : Ops[0].getConstantOperandAPInt(0) << RHSVal; | 
|  | return getStepVector(DL, VT, NewStep); | 
|  | } | 
|  | } | 
|  |  | 
|  | auto IsScalarOrSameVectorSize = [NumElts](const SDValue &Op) { | 
|  | return !Op.getValueType().isVector() || | 
|  | Op.getValueType().getVectorElementCount() == NumElts; | 
|  | }; | 
|  |  | 
|  | auto IsBuildVectorSplatVectorOrUndef = [](const SDValue &Op) { | 
|  | return Op.isUndef() || Op.getOpcode() == ISD::CONDCODE || | 
|  | Op.getOpcode() == ISD::BUILD_VECTOR || | 
|  | Op.getOpcode() == ISD::SPLAT_VECTOR; | 
|  | }; | 
|  |  | 
|  | // All operands must be vector types with the same number of elements as | 
|  | // the result type and must be either UNDEF or a build/splat vector | 
|  | // or UNDEF scalars. | 
|  | if (!llvm::all_of(Ops, IsBuildVectorSplatVectorOrUndef) || | 
|  | !llvm::all_of(Ops, IsScalarOrSameVectorSize)) | 
|  | return SDValue(); | 
|  |  | 
|  | // If we are comparing vectors, then the result needs to be a i1 boolean that | 
|  | // is then extended back to the legal result type depending on how booleans | 
|  | // are represented. | 
|  | EVT SVT = (Opcode == ISD::SETCC ? MVT::i1 : VT.getScalarType()); | 
|  | ISD::NodeType ExtendCode = | 
|  | (Opcode == ISD::SETCC && SVT != VT.getScalarType()) | 
|  | ? TargetLowering::getExtendForContent(TLI->getBooleanContents(VT)) | 
|  | : ISD::SIGN_EXTEND; | 
|  |  | 
|  | // Find legal integer scalar type for constant promotion and | 
|  | // ensure that its scalar size is at least as large as source. | 
|  | EVT LegalSVT = VT.getScalarType(); | 
|  | if (NewNodesMustHaveLegalTypes && LegalSVT.isInteger()) { | 
|  | LegalSVT = TLI->getTypeToTransformTo(*getContext(), LegalSVT); | 
|  | if (LegalSVT.bitsLT(VT.getScalarType())) | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | // For scalable vector types we know we're dealing with SPLAT_VECTORs. We | 
|  | // only have one operand to check. For fixed-length vector types we may have | 
|  | // a combination of BUILD_VECTOR and SPLAT_VECTOR. | 
|  | unsigned NumVectorElts = NumElts.isScalable() ? 1 : NumElts.getFixedValue(); | 
|  |  | 
|  | // Constant fold each scalar lane separately. | 
|  | SmallVector<SDValue, 4> ScalarResults; | 
|  | for (unsigned I = 0; I != NumVectorElts; I++) { | 
|  | SmallVector<SDValue, 4> ScalarOps; | 
|  | for (SDValue Op : Ops) { | 
|  | EVT InSVT = Op.getValueType().getScalarType(); | 
|  | if (Op.getOpcode() != ISD::BUILD_VECTOR && | 
|  | Op.getOpcode() != ISD::SPLAT_VECTOR) { | 
|  | if (Op.isUndef()) | 
|  | ScalarOps.push_back(getUNDEF(InSVT)); | 
|  | else | 
|  | ScalarOps.push_back(Op); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | SDValue ScalarOp = | 
|  | Op.getOperand(Op.getOpcode() == ISD::SPLAT_VECTOR ? 0 : I); | 
|  | EVT ScalarVT = ScalarOp.getValueType(); | 
|  |  | 
|  | // Build vector (integer) scalar operands may need implicit | 
|  | // truncation - do this before constant folding. | 
|  | if (ScalarVT.isInteger() && ScalarVT.bitsGT(InSVT)) { | 
|  | // Don't create illegally-typed nodes unless they're constants or undef | 
|  | // - if we fail to constant fold we can't guarantee the (dead) nodes | 
|  | // we're creating will be cleaned up before being visited for | 
|  | // legalization. | 
|  | if (NewNodesMustHaveLegalTypes && !ScalarOp.isUndef() && | 
|  | !isa<ConstantSDNode>(ScalarOp) && | 
|  | TLI->getTypeAction(*getContext(), InSVT) != | 
|  | TargetLowering::TypeLegal) | 
|  | return SDValue(); | 
|  | ScalarOp = getNode(ISD::TRUNCATE, DL, InSVT, ScalarOp); | 
|  | } | 
|  |  | 
|  | ScalarOps.push_back(ScalarOp); | 
|  | } | 
|  |  | 
|  | // Constant fold the scalar operands. | 
|  | SDValue ScalarResult = getNode(Opcode, DL, SVT, ScalarOps, Flags); | 
|  |  | 
|  | // Scalar folding only succeeded if the result is a constant or UNDEF. | 
|  | if (!ScalarResult.isUndef() && ScalarResult.getOpcode() != ISD::Constant && | 
|  | ScalarResult.getOpcode() != ISD::ConstantFP) | 
|  | return SDValue(); | 
|  |  | 
|  | // Legalize the (integer) scalar constant if necessary. We only do | 
|  | // this once we know the folding succeeded, since otherwise we would | 
|  | // get a node with illegal type which has a user. | 
|  | if (LegalSVT != SVT) | 
|  | ScalarResult = getNode(ExtendCode, DL, LegalSVT, ScalarResult); | 
|  |  | 
|  | ScalarResults.push_back(ScalarResult); | 
|  | } | 
|  |  | 
|  | SDValue V = NumElts.isScalable() ? getSplatVector(VT, DL, ScalarResults[0]) | 
|  | : getBuildVector(VT, DL, ScalarResults); | 
|  | NewSDValueDbgMsg(V, "New node fold constant vector: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::foldConstantFPMath(unsigned Opcode, const SDLoc &DL, | 
|  | EVT VT, ArrayRef<SDValue> Ops) { | 
|  | // TODO: Add support for unary/ternary fp opcodes. | 
|  | if (Ops.size() != 2) | 
|  | return SDValue(); | 
|  |  | 
|  | // TODO: We don't do any constant folding for strict FP opcodes here, but we | 
|  | //       should. That will require dealing with a potentially non-default | 
|  | //       rounding mode, checking the "opStatus" return value from the APFloat | 
|  | //       math calculations, and possibly other variations. | 
|  | SDValue N1 = Ops[0]; | 
|  | SDValue N2 = Ops[1]; | 
|  | ConstantFPSDNode *N1CFP = isConstOrConstSplatFP(N1, /*AllowUndefs*/ false); | 
|  | ConstantFPSDNode *N2CFP = isConstOrConstSplatFP(N2, /*AllowUndefs*/ false); | 
|  | if (N1CFP && N2CFP) { | 
|  | APFloat C1 = N1CFP->getValueAPF(); // make copy | 
|  | const APFloat &C2 = N2CFP->getValueAPF(); | 
|  | switch (Opcode) { | 
|  | case ISD::FADD: | 
|  | C1.add(C2, APFloat::rmNearestTiesToEven); | 
|  | return getConstantFP(C1, DL, VT); | 
|  | case ISD::FSUB: | 
|  | C1.subtract(C2, APFloat::rmNearestTiesToEven); | 
|  | return getConstantFP(C1, DL, VT); | 
|  | case ISD::FMUL: | 
|  | C1.multiply(C2, APFloat::rmNearestTiesToEven); | 
|  | return getConstantFP(C1, DL, VT); | 
|  | case ISD::FDIV: | 
|  | C1.divide(C2, APFloat::rmNearestTiesToEven); | 
|  | return getConstantFP(C1, DL, VT); | 
|  | case ISD::FREM: | 
|  | C1.mod(C2); | 
|  | return getConstantFP(C1, DL, VT); | 
|  | case ISD::FCOPYSIGN: | 
|  | C1.copySign(C2); | 
|  | return getConstantFP(C1, DL, VT); | 
|  | case ISD::FMINNUM: | 
|  | return getConstantFP(minnum(C1, C2), DL, VT); | 
|  | case ISD::FMAXNUM: | 
|  | return getConstantFP(maxnum(C1, C2), DL, VT); | 
|  | case ISD::FMINIMUM: | 
|  | return getConstantFP(minimum(C1, C2), DL, VT); | 
|  | case ISD::FMAXIMUM: | 
|  | return getConstantFP(maximum(C1, C2), DL, VT); | 
|  | case ISD::FMINIMUMNUM: | 
|  | return getConstantFP(minimumnum(C1, C2), DL, VT); | 
|  | case ISD::FMAXIMUMNUM: | 
|  | return getConstantFP(maximumnum(C1, C2), DL, VT); | 
|  | default: break; | 
|  | } | 
|  | } | 
|  | if (N1CFP && Opcode == ISD::FP_ROUND) { | 
|  | APFloat C1 = N1CFP->getValueAPF();    // make copy | 
|  | bool Unused; | 
|  | // This can return overflow, underflow, or inexact; we don't care. | 
|  | // FIXME need to be more flexible about rounding mode. | 
|  | (void)C1.convert(VT.getFltSemantics(), APFloat::rmNearestTiesToEven, | 
|  | &Unused); | 
|  | return getConstantFP(C1, DL, VT); | 
|  | } | 
|  |  | 
|  | switch (Opcode) { | 
|  | case ISD::FSUB: | 
|  | // -0.0 - undef --> undef (consistent with "fneg undef") | 
|  | if (ConstantFPSDNode *N1C = isConstOrConstSplatFP(N1, /*AllowUndefs*/ true)) | 
|  | if (N1C && N1C->getValueAPF().isNegZero() && N2.isUndef()) | 
|  | return getUNDEF(VT); | 
|  | [[fallthrough]]; | 
|  |  | 
|  | case ISD::FADD: | 
|  | case ISD::FMUL: | 
|  | case ISD::FDIV: | 
|  | case ISD::FREM: | 
|  | // If both operands are undef, the result is undef. If 1 operand is undef, | 
|  | // the result is NaN. This should match the behavior of the IR optimizer. | 
|  | if (N1.isUndef() && N2.isUndef()) | 
|  | return getUNDEF(VT); | 
|  | if (N1.isUndef() || N2.isUndef()) | 
|  | return getConstantFP(APFloat::getNaN(VT.getFltSemantics()), DL, VT); | 
|  | } | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::FoldConstantBuildVector(BuildVectorSDNode *BV, | 
|  | const SDLoc &DL, EVT DstEltVT) { | 
|  | EVT SrcEltVT = BV->getValueType(0).getVectorElementType(); | 
|  |  | 
|  | // If this is already the right type, we're done. | 
|  | if (SrcEltVT == DstEltVT) | 
|  | return SDValue(BV, 0); | 
|  |  | 
|  | unsigned SrcBitSize = SrcEltVT.getSizeInBits(); | 
|  | unsigned DstBitSize = DstEltVT.getSizeInBits(); | 
|  |  | 
|  | // If this is a conversion of N elements of one type to N elements of another | 
|  | // type, convert each element.  This handles FP<->INT cases. | 
|  | if (SrcBitSize == DstBitSize) { | 
|  | SmallVector<SDValue, 8> Ops; | 
|  | for (SDValue Op : BV->op_values()) { | 
|  | // If the vector element type is not legal, the BUILD_VECTOR operands | 
|  | // are promoted and implicitly truncated.  Make that explicit here. | 
|  | if (Op.getValueType() != SrcEltVT) | 
|  | Op = getNode(ISD::TRUNCATE, DL, SrcEltVT, Op); | 
|  | Ops.push_back(getBitcast(DstEltVT, Op)); | 
|  | } | 
|  | EVT VT = EVT::getVectorVT(*getContext(), DstEltVT, | 
|  | BV->getValueType(0).getVectorNumElements()); | 
|  | return getBuildVector(VT, DL, Ops); | 
|  | } | 
|  |  | 
|  | // Otherwise, we're growing or shrinking the elements.  To avoid having to | 
|  | // handle annoying details of growing/shrinking FP values, we convert them to | 
|  | // int first. | 
|  | if (SrcEltVT.isFloatingPoint()) { | 
|  | // Convert the input float vector to a int vector where the elements are the | 
|  | // same sizes. | 
|  | EVT IntEltVT = EVT::getIntegerVT(*getContext(), SrcEltVT.getSizeInBits()); | 
|  | if (SDValue Tmp = FoldConstantBuildVector(BV, DL, IntEltVT)) | 
|  | return FoldConstantBuildVector(cast<BuildVectorSDNode>(Tmp), DL, | 
|  | DstEltVT); | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | // Now we know the input is an integer vector.  If the output is a FP type, | 
|  | // convert to integer first, then to FP of the right size. | 
|  | if (DstEltVT.isFloatingPoint()) { | 
|  | EVT IntEltVT = EVT::getIntegerVT(*getContext(), DstEltVT.getSizeInBits()); | 
|  | if (SDValue Tmp = FoldConstantBuildVector(BV, DL, IntEltVT)) | 
|  | return FoldConstantBuildVector(cast<BuildVectorSDNode>(Tmp), DL, | 
|  | DstEltVT); | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | // Okay, we know the src/dst types are both integers of differing types. | 
|  | assert(SrcEltVT.isInteger() && DstEltVT.isInteger()); | 
|  |  | 
|  | // Extract the constant raw bit data. | 
|  | BitVector UndefElements; | 
|  | SmallVector<APInt> RawBits; | 
|  | bool IsLE = getDataLayout().isLittleEndian(); | 
|  | if (!BV->getConstantRawBits(IsLE, DstBitSize, RawBits, UndefElements)) | 
|  | return SDValue(); | 
|  |  | 
|  | SmallVector<SDValue, 8> Ops; | 
|  | for (unsigned I = 0, E = RawBits.size(); I != E; ++I) { | 
|  | if (UndefElements[I]) | 
|  | Ops.push_back(getUNDEF(DstEltVT)); | 
|  | else | 
|  | Ops.push_back(getConstant(RawBits[I], DL, DstEltVT)); | 
|  | } | 
|  |  | 
|  | EVT VT = EVT::getVectorVT(*getContext(), DstEltVT, Ops.size()); | 
|  | return getBuildVector(VT, DL, Ops); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getAssertAlign(const SDLoc &DL, SDValue Val, Align A) { | 
|  | assert(Val.getValueType().isInteger() && "Invalid AssertAlign!"); | 
|  |  | 
|  | // There's no need to assert on a byte-aligned pointer. All pointers are at | 
|  | // least byte aligned. | 
|  | if (A == Align(1)) | 
|  | return Val; | 
|  |  | 
|  | SDVTList VTs = getVTList(Val.getValueType()); | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, ISD::AssertAlign, VTs, {Val}); | 
|  | ID.AddInteger(A.value()); | 
|  |  | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, DL, IP)) | 
|  | return SDValue(E, 0); | 
|  |  | 
|  | auto *N = | 
|  | newSDNode<AssertAlignSDNode>(DL.getIROrder(), DL.getDebugLoc(), VTs, A); | 
|  | createOperands(N, {Val}); | 
|  |  | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  |  | 
|  | SDValue V(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT, | 
|  | SDValue N1, SDValue N2) { | 
|  | SDNodeFlags Flags; | 
|  | if (Inserter) | 
|  | Flags = Inserter->getFlags(); | 
|  | return getNode(Opcode, DL, VT, N1, N2, Flags); | 
|  | } | 
|  |  | 
|  | void SelectionDAG::canonicalizeCommutativeBinop(unsigned Opcode, SDValue &N1, | 
|  | SDValue &N2) const { | 
|  | if (!TLI->isCommutativeBinOp(Opcode)) | 
|  | return; | 
|  |  | 
|  | // Canonicalize: | 
|  | //   binop(const, nonconst) -> binop(nonconst, const) | 
|  | bool N1C = isConstantIntBuildVectorOrConstantInt(N1); | 
|  | bool N2C = isConstantIntBuildVectorOrConstantInt(N2); | 
|  | bool N1CFP = isConstantFPBuildVectorOrConstantFP(N1); | 
|  | bool N2CFP = isConstantFPBuildVectorOrConstantFP(N2); | 
|  | if ((N1C && !N2C) || (N1CFP && !N2CFP)) | 
|  | std::swap(N1, N2); | 
|  |  | 
|  | // Canonicalize: | 
|  | //  binop(splat(x), step_vector) -> binop(step_vector, splat(x)) | 
|  | else if (N1.getOpcode() == ISD::SPLAT_VECTOR && | 
|  | N2.getOpcode() == ISD::STEP_VECTOR) | 
|  | std::swap(N1, N2); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT, | 
|  | SDValue N1, SDValue N2, const SDNodeFlags Flags) { | 
|  | assert(N1.getOpcode() != ISD::DELETED_NODE && | 
|  | N2.getOpcode() != ISD::DELETED_NODE && | 
|  | "Operand is DELETED_NODE!"); | 
|  |  | 
|  | canonicalizeCommutativeBinop(Opcode, N1, N2); | 
|  |  | 
|  | auto *N1C = dyn_cast<ConstantSDNode>(N1); | 
|  | auto *N2C = dyn_cast<ConstantSDNode>(N2); | 
|  |  | 
|  | // Don't allow undefs in vector splats - we might be returning N2 when folding | 
|  | // to zero etc. | 
|  | ConstantSDNode *N2CV = | 
|  | isConstOrConstSplat(N2, /*AllowUndefs*/ false, /*AllowTruncation*/ true); | 
|  |  | 
|  | switch (Opcode) { | 
|  | default: break; | 
|  | case ISD::TokenFactor: | 
|  | assert(VT == MVT::Other && N1.getValueType() == MVT::Other && | 
|  | N2.getValueType() == MVT::Other && "Invalid token factor!"); | 
|  | // Fold trivial token factors. | 
|  | if (N1.getOpcode() == ISD::EntryToken) return N2; | 
|  | if (N2.getOpcode() == ISD::EntryToken) return N1; | 
|  | if (N1 == N2) return N1; | 
|  | break; | 
|  | case ISD::BUILD_VECTOR: { | 
|  | // Attempt to simplify BUILD_VECTOR. | 
|  | SDValue Ops[] = {N1, N2}; | 
|  | if (SDValue V = FoldBUILD_VECTOR(DL, VT, Ops, *this)) | 
|  | return V; | 
|  | break; | 
|  | } | 
|  | case ISD::CONCAT_VECTORS: { | 
|  | SDValue Ops[] = {N1, N2}; | 
|  | if (SDValue V = foldCONCAT_VECTORS(DL, VT, Ops, *this)) | 
|  | return V; | 
|  | break; | 
|  | } | 
|  | case ISD::AND: | 
|  | assert(VT.isInteger() && "This operator does not apply to FP types!"); | 
|  | assert(N1.getValueType() == N2.getValueType() && | 
|  | N1.getValueType() == VT && "Binary operator types must match!"); | 
|  | // (X & 0) -> 0.  This commonly occurs when legalizing i64 values, so it's | 
|  | // worth handling here. | 
|  | if (N2CV && N2CV->isZero()) | 
|  | return N2; | 
|  | if (N2CV && N2CV->isAllOnes()) // X & -1 -> X | 
|  | return N1; | 
|  | break; | 
|  | case ISD::OR: | 
|  | case ISD::XOR: | 
|  | case ISD::ADD: | 
|  | case ISD::PTRADD: | 
|  | case ISD::SUB: | 
|  | assert(VT.isInteger() && "This operator does not apply to FP types!"); | 
|  | assert(N1.getValueType() == N2.getValueType() && | 
|  | N1.getValueType() == VT && "Binary operator types must match!"); | 
|  | // The equal operand types requirement is unnecessarily strong for PTRADD. | 
|  | // However, the SelectionDAGBuilder does not generate PTRADDs with different | 
|  | // operand types, and we'd need to re-implement GEP's non-standard wrapping | 
|  | // logic everywhere where PTRADDs may be folded or combined to properly | 
|  | // support them. If/when we introduce pointer types to the SDAG, we will | 
|  | // need to relax this constraint. | 
|  |  | 
|  | // (X ^|+- 0) -> X.  This commonly occurs when legalizing i64 values, so | 
|  | // it's worth handling here. | 
|  | if (N2CV && N2CV->isZero()) | 
|  | return N1; | 
|  | if ((Opcode == ISD::ADD || Opcode == ISD::SUB) && | 
|  | VT.getScalarType() == MVT::i1) | 
|  | return getNode(ISD::XOR, DL, VT, N1, N2); | 
|  | // Fold (add (vscale * C0), (vscale * C1)) to (vscale * (C0 + C1)). | 
|  | if (Opcode == ISD::ADD && N1.getOpcode() == ISD::VSCALE && | 
|  | N2.getOpcode() == ISD::VSCALE) { | 
|  | const APInt &C1 = N1->getConstantOperandAPInt(0); | 
|  | const APInt &C2 = N2->getConstantOperandAPInt(0); | 
|  | return getVScale(DL, VT, C1 + C2); | 
|  | } | 
|  | break; | 
|  | case ISD::MUL: | 
|  | assert(VT.isInteger() && "This operator does not apply to FP types!"); | 
|  | assert(N1.getValueType() == N2.getValueType() && | 
|  | N1.getValueType() == VT && "Binary operator types must match!"); | 
|  | if (VT.getScalarType() == MVT::i1) | 
|  | return getNode(ISD::AND, DL, VT, N1, N2); | 
|  | if (N2C && (N1.getOpcode() == ISD::VSCALE) && Flags.hasNoSignedWrap()) { | 
|  | const APInt &MulImm = N1->getConstantOperandAPInt(0); | 
|  | const APInt &N2CImm = N2C->getAPIntValue(); | 
|  | return getVScale(DL, VT, MulImm * N2CImm); | 
|  | } | 
|  | break; | 
|  | case ISD::UDIV: | 
|  | case ISD::UREM: | 
|  | case ISD::MULHU: | 
|  | case ISD::MULHS: | 
|  | case ISD::SDIV: | 
|  | case ISD::SREM: | 
|  | case ISD::SADDSAT: | 
|  | case ISD::SSUBSAT: | 
|  | case ISD::UADDSAT: | 
|  | case ISD::USUBSAT: | 
|  | assert(VT.isInteger() && "This operator does not apply to FP types!"); | 
|  | assert(N1.getValueType() == N2.getValueType() && | 
|  | N1.getValueType() == VT && "Binary operator types must match!"); | 
|  | if (VT.getScalarType() == MVT::i1) { | 
|  | // fold (add_sat x, y) -> (or x, y) for bool types. | 
|  | if (Opcode == ISD::SADDSAT || Opcode == ISD::UADDSAT) | 
|  | return getNode(ISD::OR, DL, VT, N1, N2); | 
|  | // fold (sub_sat x, y) -> (and x, ~y) for bool types. | 
|  | if (Opcode == ISD::SSUBSAT || Opcode == ISD::USUBSAT) | 
|  | return getNode(ISD::AND, DL, VT, N1, getNOT(DL, N2, VT)); | 
|  | } | 
|  | break; | 
|  | case ISD::SCMP: | 
|  | case ISD::UCMP: | 
|  | assert(N1.getValueType() == N2.getValueType() && | 
|  | "Types of operands of UCMP/SCMP must match"); | 
|  | assert(N1.getValueType().isVector() == VT.isVector() && | 
|  | "Operands and return type of must both be scalars or vectors"); | 
|  | if (VT.isVector()) | 
|  | assert(VT.getVectorElementCount() == | 
|  | N1.getValueType().getVectorElementCount() && | 
|  | "Result and operands must have the same number of elements"); | 
|  | break; | 
|  | case ISD::AVGFLOORS: | 
|  | case ISD::AVGFLOORU: | 
|  | case ISD::AVGCEILS: | 
|  | case ISD::AVGCEILU: | 
|  | assert(VT.isInteger() && "This operator does not apply to FP types!"); | 
|  | assert(N1.getValueType() == N2.getValueType() && | 
|  | N1.getValueType() == VT && "Binary operator types must match!"); | 
|  | break; | 
|  | case ISD::ABDS: | 
|  | case ISD::ABDU: | 
|  | assert(VT.isInteger() && "This operator does not apply to FP types!"); | 
|  | assert(N1.getValueType() == N2.getValueType() && | 
|  | N1.getValueType() == VT && "Binary operator types must match!"); | 
|  | if (VT.getScalarType() == MVT::i1) | 
|  | return getNode(ISD::XOR, DL, VT, N1, N2); | 
|  | break; | 
|  | case ISD::SMIN: | 
|  | case ISD::UMAX: | 
|  | assert(VT.isInteger() && "This operator does not apply to FP types!"); | 
|  | assert(N1.getValueType() == N2.getValueType() && | 
|  | N1.getValueType() == VT && "Binary operator types must match!"); | 
|  | if (VT.getScalarType() == MVT::i1) | 
|  | return getNode(ISD::OR, DL, VT, N1, N2); | 
|  | break; | 
|  | case ISD::SMAX: | 
|  | case ISD::UMIN: | 
|  | assert(VT.isInteger() && "This operator does not apply to FP types!"); | 
|  | assert(N1.getValueType() == N2.getValueType() && | 
|  | N1.getValueType() == VT && "Binary operator types must match!"); | 
|  | if (VT.getScalarType() == MVT::i1) | 
|  | return getNode(ISD::AND, DL, VT, N1, N2); | 
|  | break; | 
|  | case ISD::FADD: | 
|  | case ISD::FSUB: | 
|  | case ISD::FMUL: | 
|  | case ISD::FDIV: | 
|  | case ISD::FREM: | 
|  | assert(VT.isFloatingPoint() && "This operator only applies to FP types!"); | 
|  | assert(N1.getValueType() == N2.getValueType() && | 
|  | N1.getValueType() == VT && "Binary operator types must match!"); | 
|  | if (SDValue V = simplifyFPBinop(Opcode, N1, N2, Flags)) | 
|  | return V; | 
|  | break; | 
|  | case ISD::FCOPYSIGN:   // N1 and result must match.  N1/N2 need not match. | 
|  | assert(N1.getValueType() == VT && | 
|  | N1.getValueType().isFloatingPoint() && | 
|  | N2.getValueType().isFloatingPoint() && | 
|  | "Invalid FCOPYSIGN!"); | 
|  | break; | 
|  | case ISD::SHL: | 
|  | if (N2C && (N1.getOpcode() == ISD::VSCALE) && Flags.hasNoSignedWrap()) { | 
|  | const APInt &MulImm = N1->getConstantOperandAPInt(0); | 
|  | const APInt &ShiftImm = N2C->getAPIntValue(); | 
|  | return getVScale(DL, VT, MulImm << ShiftImm); | 
|  | } | 
|  | [[fallthrough]]; | 
|  | case ISD::SRA: | 
|  | case ISD::SRL: | 
|  | if (SDValue V = simplifyShift(N1, N2)) | 
|  | return V; | 
|  | [[fallthrough]]; | 
|  | case ISD::ROTL: | 
|  | case ISD::ROTR: | 
|  | assert(VT == N1.getValueType() && | 
|  | "Shift operators return type must be the same as their first arg"); | 
|  | assert(VT.isInteger() && N2.getValueType().isInteger() && | 
|  | "Shifts only work on integers"); | 
|  | assert((!VT.isVector() || VT == N2.getValueType()) && | 
|  | "Vector shift amounts must be in the same as their first arg"); | 
|  | // Verify that the shift amount VT is big enough to hold valid shift | 
|  | // amounts.  This catches things like trying to shift an i1024 value by an | 
|  | // i8, which is easy to fall into in generic code that uses | 
|  | // TLI.getShiftAmount(). | 
|  | assert(N2.getValueType().getScalarSizeInBits() >= | 
|  | Log2_32_Ceil(VT.getScalarSizeInBits()) && | 
|  | "Invalid use of small shift amount with oversized value!"); | 
|  |  | 
|  | // Always fold shifts of i1 values so the code generator doesn't need to | 
|  | // handle them.  Since we know the size of the shift has to be less than the | 
|  | // size of the value, the shift/rotate count is guaranteed to be zero. | 
|  | if (VT == MVT::i1) | 
|  | return N1; | 
|  | if (N2CV && N2CV->isZero()) | 
|  | return N1; | 
|  | break; | 
|  | case ISD::FP_ROUND: | 
|  | assert(VT.isFloatingPoint() && N1.getValueType().isFloatingPoint() && | 
|  | VT.bitsLE(N1.getValueType()) && N2C && | 
|  | (N2C->getZExtValue() == 0 || N2C->getZExtValue() == 1) && | 
|  | N2.getOpcode() == ISD::TargetConstant && "Invalid FP_ROUND!"); | 
|  | if (N1.getValueType() == VT) return N1;  // noop conversion. | 
|  | break; | 
|  | case ISD::AssertNoFPClass: { | 
|  | assert(N1.getValueType().isFloatingPoint() && | 
|  | "AssertNoFPClass is used for a non-floating type"); | 
|  | assert(isa<ConstantSDNode>(N2) && "NoFPClass is not Constant"); | 
|  | FPClassTest NoFPClass = static_cast<FPClassTest>(N2->getAsZExtVal()); | 
|  | assert(llvm::to_underlying(NoFPClass) <= | 
|  | BitmaskEnumDetail::Mask<FPClassTest>() && | 
|  | "FPClassTest value too large"); | 
|  | (void)NoFPClass; | 
|  | break; | 
|  | } | 
|  | case ISD::AssertSext: | 
|  | case ISD::AssertZext: { | 
|  | EVT EVT = cast<VTSDNode>(N2)->getVT(); | 
|  | assert(VT == N1.getValueType() && "Not an inreg extend!"); | 
|  | assert(VT.isInteger() && EVT.isInteger() && | 
|  | "Cannot *_EXTEND_INREG FP types"); | 
|  | assert(!EVT.isVector() && | 
|  | "AssertSExt/AssertZExt type should be the vector element type " | 
|  | "rather than the vector type!"); | 
|  | assert(EVT.bitsLE(VT.getScalarType()) && "Not extending!"); | 
|  | if (VT.getScalarType() == EVT) return N1; // noop assertion. | 
|  | break; | 
|  | } | 
|  | case ISD::SIGN_EXTEND_INREG: { | 
|  | EVT EVT = cast<VTSDNode>(N2)->getVT(); | 
|  | assert(VT == N1.getValueType() && "Not an inreg extend!"); | 
|  | assert(VT.isInteger() && EVT.isInteger() && | 
|  | "Cannot *_EXTEND_INREG FP types"); | 
|  | assert(EVT.isVector() == VT.isVector() && | 
|  | "SIGN_EXTEND_INREG type should be vector iff the operand " | 
|  | "type is vector!"); | 
|  | assert((!EVT.isVector() || | 
|  | EVT.getVectorElementCount() == VT.getVectorElementCount()) && | 
|  | "Vector element counts must match in SIGN_EXTEND_INREG"); | 
|  | assert(EVT.bitsLE(VT) && "Not extending!"); | 
|  | if (EVT == VT) return N1;  // Not actually extending | 
|  | break; | 
|  | } | 
|  | case ISD::FP_TO_SINT_SAT: | 
|  | case ISD::FP_TO_UINT_SAT: { | 
|  | assert(VT.isInteger() && cast<VTSDNode>(N2)->getVT().isInteger() && | 
|  | N1.getValueType().isFloatingPoint() && "Invalid FP_TO_*INT_SAT"); | 
|  | assert(N1.getValueType().isVector() == VT.isVector() && | 
|  | "FP_TO_*INT_SAT type should be vector iff the operand type is " | 
|  | "vector!"); | 
|  | assert((!VT.isVector() || VT.getVectorElementCount() == | 
|  | N1.getValueType().getVectorElementCount()) && | 
|  | "Vector element counts must match in FP_TO_*INT_SAT"); | 
|  | assert(!cast<VTSDNode>(N2)->getVT().isVector() && | 
|  | "Type to saturate to must be a scalar."); | 
|  | assert(cast<VTSDNode>(N2)->getVT().bitsLE(VT.getScalarType()) && | 
|  | "Not extending!"); | 
|  | break; | 
|  | } | 
|  | case ISD::EXTRACT_VECTOR_ELT: | 
|  | assert(VT.getSizeInBits() >= N1.getValueType().getScalarSizeInBits() && | 
|  | "The result of EXTRACT_VECTOR_ELT must be at least as wide as the \ | 
|  | element type of the vector."); | 
|  |  | 
|  | // Extract from an undefined value or using an undefined index is undefined. | 
|  | if (N1.isUndef() || N2.isUndef()) | 
|  | return getUNDEF(VT); | 
|  |  | 
|  | // EXTRACT_VECTOR_ELT of out-of-bounds element is an UNDEF for fixed length | 
|  | // vectors. For scalable vectors we will provide appropriate support for | 
|  | // dealing with arbitrary indices. | 
|  | if (N2C && N1.getValueType().isFixedLengthVector() && | 
|  | N2C->getAPIntValue().uge(N1.getValueType().getVectorNumElements())) | 
|  | return getUNDEF(VT); | 
|  |  | 
|  | // EXTRACT_VECTOR_ELT of CONCAT_VECTORS is often formed while lowering is | 
|  | // expanding copies of large vectors from registers. This only works for | 
|  | // fixed length vectors, since we need to know the exact number of | 
|  | // elements. | 
|  | if (N2C && N1.getOpcode() == ISD::CONCAT_VECTORS && | 
|  | N1.getOperand(0).getValueType().isFixedLengthVector()) { | 
|  | unsigned Factor = N1.getOperand(0).getValueType().getVectorNumElements(); | 
|  | return getExtractVectorElt(DL, VT, | 
|  | N1.getOperand(N2C->getZExtValue() / Factor), | 
|  | N2C->getZExtValue() % Factor); | 
|  | } | 
|  |  | 
|  | // EXTRACT_VECTOR_ELT of BUILD_VECTOR or SPLAT_VECTOR is often formed while | 
|  | // lowering is expanding large vector constants. | 
|  | if (N2C && (N1.getOpcode() == ISD::BUILD_VECTOR || | 
|  | N1.getOpcode() == ISD::SPLAT_VECTOR)) { | 
|  | assert((N1.getOpcode() != ISD::BUILD_VECTOR || | 
|  | N1.getValueType().isFixedLengthVector()) && | 
|  | "BUILD_VECTOR used for scalable vectors"); | 
|  | unsigned Index = | 
|  | N1.getOpcode() == ISD::BUILD_VECTOR ? N2C->getZExtValue() : 0; | 
|  | SDValue Elt = N1.getOperand(Index); | 
|  |  | 
|  | if (VT != Elt.getValueType()) | 
|  | // If the vector element type is not legal, the BUILD_VECTOR operands | 
|  | // are promoted and implicitly truncated, and the result implicitly | 
|  | // extended. Make that explicit here. | 
|  | Elt = getAnyExtOrTrunc(Elt, DL, VT); | 
|  |  | 
|  | return Elt; | 
|  | } | 
|  |  | 
|  | // EXTRACT_VECTOR_ELT of INSERT_VECTOR_ELT is often formed when vector | 
|  | // operations are lowered to scalars. | 
|  | if (N1.getOpcode() == ISD::INSERT_VECTOR_ELT) { | 
|  | // If the indices are the same, return the inserted element else | 
|  | // if the indices are known different, extract the element from | 
|  | // the original vector. | 
|  | SDValue N1Op2 = N1.getOperand(2); | 
|  | ConstantSDNode *N1Op2C = dyn_cast<ConstantSDNode>(N1Op2); | 
|  |  | 
|  | if (N1Op2C && N2C) { | 
|  | if (N1Op2C->getZExtValue() == N2C->getZExtValue()) { | 
|  | if (VT == N1.getOperand(1).getValueType()) | 
|  | return N1.getOperand(1); | 
|  | if (VT.isFloatingPoint()) { | 
|  | assert(VT.getSizeInBits() > N1.getOperand(1).getValueType().getSizeInBits()); | 
|  | return getFPExtendOrRound(N1.getOperand(1), DL, VT); | 
|  | } | 
|  | return getSExtOrTrunc(N1.getOperand(1), DL, VT); | 
|  | } | 
|  | return getNode(ISD::EXTRACT_VECTOR_ELT, DL, VT, N1.getOperand(0), N2); | 
|  | } | 
|  | } | 
|  |  | 
|  | // EXTRACT_VECTOR_ELT of v1iX EXTRACT_SUBVECTOR could be formed | 
|  | // when vector types are scalarized and v1iX is legal. | 
|  | // vextract (v1iX extract_subvector(vNiX, Idx)) -> vextract(vNiX,Idx). | 
|  | // Here we are completely ignoring the extract element index (N2), | 
|  | // which is fine for fixed width vectors, since any index other than 0 | 
|  | // is undefined anyway. However, this cannot be ignored for scalable | 
|  | // vectors - in theory we could support this, but we don't want to do this | 
|  | // without a profitability check. | 
|  | if (N1.getOpcode() == ISD::EXTRACT_SUBVECTOR && | 
|  | N1.getValueType().isFixedLengthVector() && | 
|  | N1.getValueType().getVectorNumElements() == 1) { | 
|  | return getNode(ISD::EXTRACT_VECTOR_ELT, DL, VT, N1.getOperand(0), | 
|  | N1.getOperand(1)); | 
|  | } | 
|  | break; | 
|  | case ISD::EXTRACT_ELEMENT: | 
|  | assert(N2C && (unsigned)N2C->getZExtValue() < 2 && "Bad EXTRACT_ELEMENT!"); | 
|  | assert(!N1.getValueType().isVector() && !VT.isVector() && | 
|  | (N1.getValueType().isInteger() == VT.isInteger()) && | 
|  | N1.getValueType() != VT && | 
|  | "Wrong types for EXTRACT_ELEMENT!"); | 
|  |  | 
|  | // EXTRACT_ELEMENT of BUILD_PAIR is often formed while legalize is expanding | 
|  | // 64-bit integers into 32-bit parts.  Instead of building the extract of | 
|  | // the BUILD_PAIR, only to have legalize rip it apart, just do it now. | 
|  | if (N1.getOpcode() == ISD::BUILD_PAIR) | 
|  | return N1.getOperand(N2C->getZExtValue()); | 
|  |  | 
|  | // EXTRACT_ELEMENT of a constant int is also very common. | 
|  | if (N1C) { | 
|  | unsigned ElementSize = VT.getSizeInBits(); | 
|  | unsigned Shift = ElementSize * N2C->getZExtValue(); | 
|  | const APInt &Val = N1C->getAPIntValue(); | 
|  | return getConstant(Val.extractBits(ElementSize, Shift), DL, VT); | 
|  | } | 
|  | break; | 
|  | case ISD::EXTRACT_SUBVECTOR: { | 
|  | EVT N1VT = N1.getValueType(); | 
|  | assert(VT.isVector() && N1VT.isVector() && | 
|  | "Extract subvector VTs must be vectors!"); | 
|  | assert(VT.getVectorElementType() == N1VT.getVectorElementType() && | 
|  | "Extract subvector VTs must have the same element type!"); | 
|  | assert((VT.isFixedLengthVector() || N1VT.isScalableVector()) && | 
|  | "Cannot extract a scalable vector from a fixed length vector!"); | 
|  | assert((VT.isScalableVector() != N1VT.isScalableVector() || | 
|  | VT.getVectorMinNumElements() <= N1VT.getVectorMinNumElements()) && | 
|  | "Extract subvector must be from larger vector to smaller vector!"); | 
|  | assert(N2C && "Extract subvector index must be a constant"); | 
|  | assert((VT.isScalableVector() != N1VT.isScalableVector() || | 
|  | (VT.getVectorMinNumElements() + N2C->getZExtValue()) <= | 
|  | N1VT.getVectorMinNumElements()) && | 
|  | "Extract subvector overflow!"); | 
|  | assert(N2C->getAPIntValue().getBitWidth() == | 
|  | TLI->getVectorIdxWidth(getDataLayout()) && | 
|  | "Constant index for EXTRACT_SUBVECTOR has an invalid size"); | 
|  | assert(N2C->getZExtValue() % VT.getVectorMinNumElements() == 0 && | 
|  | "Extract index is not a multiple of the output vector length"); | 
|  |  | 
|  | // Trivial extraction. | 
|  | if (VT == N1VT) | 
|  | return N1; | 
|  |  | 
|  | // EXTRACT_SUBVECTOR of an UNDEF is an UNDEF. | 
|  | if (N1.isUndef()) | 
|  | return getUNDEF(VT); | 
|  |  | 
|  | // EXTRACT_SUBVECTOR of CONCAT_VECTOR can be simplified if the pieces of | 
|  | // the concat have the same type as the extract. | 
|  | if (N1.getOpcode() == ISD::CONCAT_VECTORS && | 
|  | VT == N1.getOperand(0).getValueType()) { | 
|  | unsigned Factor = VT.getVectorMinNumElements(); | 
|  | return N1.getOperand(N2C->getZExtValue() / Factor); | 
|  | } | 
|  |  | 
|  | // EXTRACT_SUBVECTOR of INSERT_SUBVECTOR is often created | 
|  | // during shuffle legalization. | 
|  | if (N1.getOpcode() == ISD::INSERT_SUBVECTOR && N2 == N1.getOperand(2) && | 
|  | VT == N1.getOperand(1).getValueType()) | 
|  | return N1.getOperand(1); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (N1.getOpcode() == ISD::POISON || N2.getOpcode() == ISD::POISON) { | 
|  | switch (Opcode) { | 
|  | case ISD::XOR: | 
|  | case ISD::ADD: | 
|  | case ISD::PTRADD: | 
|  | case ISD::SUB: | 
|  | case ISD::SIGN_EXTEND_INREG: | 
|  | case ISD::UDIV: | 
|  | case ISD::SDIV: | 
|  | case ISD::UREM: | 
|  | case ISD::SREM: | 
|  | case ISD::MUL: | 
|  | case ISD::AND: | 
|  | case ISD::SSUBSAT: | 
|  | case ISD::USUBSAT: | 
|  | case ISD::UMIN: | 
|  | case ISD::OR: | 
|  | case ISD::SADDSAT: | 
|  | case ISD::UADDSAT: | 
|  | case ISD::UMAX: | 
|  | case ISD::SMAX: | 
|  | case ISD::SMIN: | 
|  | // fold op(arg1, poison) -> poison, fold op(poison, arg2) -> poison. | 
|  | return N2.getOpcode() == ISD::POISON ? N2 : N1; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Canonicalize an UNDEF to the RHS, even over a constant. | 
|  | if (N1.getOpcode() == ISD::UNDEF && N2.getOpcode() != ISD::UNDEF) { | 
|  | if (TLI->isCommutativeBinOp(Opcode)) { | 
|  | std::swap(N1, N2); | 
|  | } else { | 
|  | switch (Opcode) { | 
|  | case ISD::PTRADD: | 
|  | case ISD::SUB: | 
|  | // fold op(undef, non_undef_arg2) -> undef. | 
|  | return N1; | 
|  | case ISD::SIGN_EXTEND_INREG: | 
|  | case ISD::UDIV: | 
|  | case ISD::SDIV: | 
|  | case ISD::UREM: | 
|  | case ISD::SREM: | 
|  | case ISD::SSUBSAT: | 
|  | case ISD::USUBSAT: | 
|  | // fold op(undef, non_undef_arg2) -> 0. | 
|  | return getConstant(0, DL, VT); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Fold a bunch of operators when the RHS is undef. | 
|  | if (N2.getOpcode() == ISD::UNDEF) { | 
|  | switch (Opcode) { | 
|  | case ISD::XOR: | 
|  | if (N1.getOpcode() == ISD::UNDEF) | 
|  | // Handle undef ^ undef -> 0 special case. This is a common | 
|  | // idiom (misuse). | 
|  | return getConstant(0, DL, VT); | 
|  | [[fallthrough]]; | 
|  | case ISD::ADD: | 
|  | case ISD::PTRADD: | 
|  | case ISD::SUB: | 
|  | // fold op(arg1, undef) -> undef. | 
|  | return N2; | 
|  | case ISD::UDIV: | 
|  | case ISD::SDIV: | 
|  | case ISD::UREM: | 
|  | case ISD::SREM: | 
|  | // fold op(arg1, undef) -> poison. | 
|  | return getPOISON(VT); | 
|  | case ISD::MUL: | 
|  | case ISD::AND: | 
|  | case ISD::SSUBSAT: | 
|  | case ISD::USUBSAT: | 
|  | case ISD::UMIN: | 
|  | // fold op(undef, undef) -> undef, fold op(arg1, undef) -> 0. | 
|  | return N1.getOpcode() == ISD::UNDEF ? N2 : getConstant(0, DL, VT); | 
|  | case ISD::OR: | 
|  | case ISD::SADDSAT: | 
|  | case ISD::UADDSAT: | 
|  | case ISD::UMAX: | 
|  | // fold op(undef, undef) -> undef, fold op(arg1, undef) -> -1. | 
|  | return N1.getOpcode() == ISD::UNDEF ? N2 : getAllOnesConstant(DL, VT); | 
|  | case ISD::SMAX: | 
|  | // fold op(undef, undef) -> undef, fold op(arg1, undef) -> MAX_INT. | 
|  | return N1.getOpcode() == ISD::UNDEF | 
|  | ? N2 | 
|  | : getConstant( | 
|  | APInt::getSignedMaxValue(VT.getScalarSizeInBits()), DL, | 
|  | VT); | 
|  | case ISD::SMIN: | 
|  | // fold op(undef, undef) -> undef, fold op(arg1, undef) -> MIN_INT. | 
|  | return N1.getOpcode() == ISD::UNDEF | 
|  | ? N2 | 
|  | : getConstant( | 
|  | APInt::getSignedMinValue(VT.getScalarSizeInBits()), DL, | 
|  | VT); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Perform trivial constant folding. | 
|  | if (SDValue SV = FoldConstantArithmetic(Opcode, DL, VT, {N1, N2}, Flags)) | 
|  | return SV; | 
|  |  | 
|  | // Memoize this node if possible. | 
|  | SDNode *N; | 
|  | SDVTList VTs = getVTList(VT); | 
|  | SDValue Ops[] = {N1, N2}; | 
|  | if (VT != MVT::Glue) { | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, Opcode, VTs, Ops); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, DL, IP)) { | 
|  | E->intersectFlagsWith(Flags); | 
|  | return SDValue(E, 0); | 
|  | } | 
|  |  | 
|  | N = newSDNode<SDNode>(Opcode, DL.getIROrder(), DL.getDebugLoc(), VTs); | 
|  | N->setFlags(Flags); | 
|  | createOperands(N, Ops); | 
|  | CSEMap.InsertNode(N, IP); | 
|  | } else { | 
|  | N = newSDNode<SDNode>(Opcode, DL.getIROrder(), DL.getDebugLoc(), VTs); | 
|  | createOperands(N, Ops); | 
|  | } | 
|  |  | 
|  | InsertNode(N); | 
|  | SDValue V = SDValue(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT, | 
|  | SDValue N1, SDValue N2, SDValue N3) { | 
|  | SDNodeFlags Flags; | 
|  | if (Inserter) | 
|  | Flags = Inserter->getFlags(); | 
|  | return getNode(Opcode, DL, VT, N1, N2, N3, Flags); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT, | 
|  | SDValue N1, SDValue N2, SDValue N3, | 
|  | const SDNodeFlags Flags) { | 
|  | assert(N1.getOpcode() != ISD::DELETED_NODE && | 
|  | N2.getOpcode() != ISD::DELETED_NODE && | 
|  | N3.getOpcode() != ISD::DELETED_NODE && | 
|  | "Operand is DELETED_NODE!"); | 
|  | // Perform various simplifications. | 
|  | switch (Opcode) { | 
|  | case ISD::BUILD_VECTOR: { | 
|  | // Attempt to simplify BUILD_VECTOR. | 
|  | SDValue Ops[] = {N1, N2, N3}; | 
|  | if (SDValue V = FoldBUILD_VECTOR(DL, VT, Ops, *this)) | 
|  | return V; | 
|  | break; | 
|  | } | 
|  | case ISD::CONCAT_VECTORS: { | 
|  | SDValue Ops[] = {N1, N2, N3}; | 
|  | if (SDValue V = foldCONCAT_VECTORS(DL, VT, Ops, *this)) | 
|  | return V; | 
|  | break; | 
|  | } | 
|  | case ISD::SETCC: { | 
|  | assert(VT.isInteger() && "SETCC result type must be an integer!"); | 
|  | assert(N1.getValueType() == N2.getValueType() && | 
|  | "SETCC operands must have the same type!"); | 
|  | assert(VT.isVector() == N1.getValueType().isVector() && | 
|  | "SETCC type should be vector iff the operand type is vector!"); | 
|  | assert((!VT.isVector() || VT.getVectorElementCount() == | 
|  | N1.getValueType().getVectorElementCount()) && | 
|  | "SETCC vector element counts must match!"); | 
|  | // Use FoldSetCC to simplify SETCC's. | 
|  | if (SDValue V = FoldSetCC(VT, N1, N2, cast<CondCodeSDNode>(N3)->get(), DL)) | 
|  | return V; | 
|  | break; | 
|  | } | 
|  | case ISD::SELECT: | 
|  | case ISD::VSELECT: | 
|  | if (SDValue V = simplifySelect(N1, N2, N3)) | 
|  | return V; | 
|  | break; | 
|  | case ISD::VECTOR_SHUFFLE: | 
|  | llvm_unreachable("should use getVectorShuffle constructor!"); | 
|  | case ISD::VECTOR_SPLICE: { | 
|  | if (cast<ConstantSDNode>(N3)->isZero()) | 
|  | return N1; | 
|  | break; | 
|  | } | 
|  | case ISD::INSERT_VECTOR_ELT: { | 
|  | assert(VT.isVector() && VT == N1.getValueType() && | 
|  | "INSERT_VECTOR_ELT vector type mismatch"); | 
|  | assert(VT.isFloatingPoint() == N2.getValueType().isFloatingPoint() && | 
|  | "INSERT_VECTOR_ELT scalar fp/int mismatch"); | 
|  | assert((!VT.isFloatingPoint() || | 
|  | VT.getVectorElementType() == N2.getValueType()) && | 
|  | "INSERT_VECTOR_ELT fp scalar type mismatch"); | 
|  | assert((!VT.isInteger() || | 
|  | VT.getScalarSizeInBits() <= N2.getScalarValueSizeInBits()) && | 
|  | "INSERT_VECTOR_ELT int scalar size mismatch"); | 
|  |  | 
|  | auto *N3C = dyn_cast<ConstantSDNode>(N3); | 
|  | // INSERT_VECTOR_ELT into out-of-bounds element is an UNDEF, except | 
|  | // for scalable vectors where we will generate appropriate code to | 
|  | // deal with out-of-bounds cases correctly. | 
|  | if (N3C && N1.getValueType().isFixedLengthVector() && | 
|  | N3C->getZExtValue() >= N1.getValueType().getVectorNumElements()) | 
|  | return getUNDEF(VT); | 
|  |  | 
|  | // Undefined index can be assumed out-of-bounds, so that's UNDEF too. | 
|  | if (N3.isUndef()) | 
|  | return getUNDEF(VT); | 
|  |  | 
|  | // If the inserted element is an UNDEF, just use the input vector. | 
|  | if (N2.isUndef()) | 
|  | return N1; | 
|  |  | 
|  | break; | 
|  | } | 
|  | case ISD::INSERT_SUBVECTOR: { | 
|  | // Inserting undef into undef is still undef. | 
|  | if (N1.isUndef() && N2.isUndef()) | 
|  | return getUNDEF(VT); | 
|  |  | 
|  | EVT N2VT = N2.getValueType(); | 
|  | assert(VT == N1.getValueType() && | 
|  | "Dest and insert subvector source types must match!"); | 
|  | assert(VT.isVector() && N2VT.isVector() && | 
|  | "Insert subvector VTs must be vectors!"); | 
|  | assert(VT.getVectorElementType() == N2VT.getVectorElementType() && | 
|  | "Insert subvector VTs must have the same element type!"); | 
|  | assert((VT.isScalableVector() || N2VT.isFixedLengthVector()) && | 
|  | "Cannot insert a scalable vector into a fixed length vector!"); | 
|  | assert((VT.isScalableVector() != N2VT.isScalableVector() || | 
|  | VT.getVectorMinNumElements() >= N2VT.getVectorMinNumElements()) && | 
|  | "Insert subvector must be from smaller vector to larger vector!"); | 
|  | assert(isa<ConstantSDNode>(N3) && | 
|  | "Insert subvector index must be constant"); | 
|  | assert((VT.isScalableVector() != N2VT.isScalableVector() || | 
|  | (N2VT.getVectorMinNumElements() + N3->getAsZExtVal()) <= | 
|  | VT.getVectorMinNumElements()) && | 
|  | "Insert subvector overflow!"); | 
|  | assert(N3->getAsAPIntVal().getBitWidth() == | 
|  | TLI->getVectorIdxWidth(getDataLayout()) && | 
|  | "Constant index for INSERT_SUBVECTOR has an invalid size"); | 
|  |  | 
|  | // Trivial insertion. | 
|  | if (VT == N2VT) | 
|  | return N2; | 
|  |  | 
|  | // If this is an insert of an extracted vector into an undef vector, we | 
|  | // can just use the input to the extract. | 
|  | if (N1.isUndef() && N2.getOpcode() == ISD::EXTRACT_SUBVECTOR && | 
|  | N2.getOperand(1) == N3 && N2.getOperand(0).getValueType() == VT) | 
|  | return N2.getOperand(0); | 
|  | break; | 
|  | } | 
|  | case ISD::BITCAST: | 
|  | // Fold bit_convert nodes from a type to themselves. | 
|  | if (N1.getValueType() == VT) | 
|  | return N1; | 
|  | break; | 
|  | case ISD::VP_TRUNCATE: | 
|  | case ISD::VP_SIGN_EXTEND: | 
|  | case ISD::VP_ZERO_EXTEND: | 
|  | // Don't create noop casts. | 
|  | if (N1.getValueType() == VT) | 
|  | return N1; | 
|  | break; | 
|  | case ISD::VECTOR_COMPRESS: { | 
|  | [[maybe_unused]] EVT VecVT = N1.getValueType(); | 
|  | [[maybe_unused]] EVT MaskVT = N2.getValueType(); | 
|  | [[maybe_unused]] EVT PassthruVT = N3.getValueType(); | 
|  | assert(VT == VecVT && "Vector and result type don't match."); | 
|  | assert(VecVT.isVector() && MaskVT.isVector() && PassthruVT.isVector() && | 
|  | "All inputs must be vectors."); | 
|  | assert(VecVT == PassthruVT && "Vector and passthru types don't match."); | 
|  | assert(VecVT.getVectorElementCount() == MaskVT.getVectorElementCount() && | 
|  | "Vector and mask must have same number of elements."); | 
|  |  | 
|  | if (N1.isUndef() || N2.isUndef()) | 
|  | return N3; | 
|  |  | 
|  | break; | 
|  | } | 
|  | case ISD::PARTIAL_REDUCE_UMLA: | 
|  | case ISD::PARTIAL_REDUCE_SMLA: | 
|  | case ISD::PARTIAL_REDUCE_SUMLA: { | 
|  | [[maybe_unused]] EVT AccVT = N1.getValueType(); | 
|  | [[maybe_unused]] EVT Input1VT = N2.getValueType(); | 
|  | [[maybe_unused]] EVT Input2VT = N3.getValueType(); | 
|  | assert(Input1VT.isVector() && Input1VT == Input2VT && | 
|  | "Expected the second and third operands of the PARTIAL_REDUCE_MLA " | 
|  | "node to have the same type!"); | 
|  | assert(VT.isVector() && VT == AccVT && | 
|  | "Expected the first operand of the PARTIAL_REDUCE_MLA node to have " | 
|  | "the same type as its result!"); | 
|  | assert(Input1VT.getVectorElementCount().hasKnownScalarFactor( | 
|  | AccVT.getVectorElementCount()) && | 
|  | "Expected the element count of the second and third operands of the " | 
|  | "PARTIAL_REDUCE_MLA node to be a positive integer multiple of the " | 
|  | "element count of the first operand and the result!"); | 
|  | assert(N2.getScalarValueSizeInBits() <= N1.getScalarValueSizeInBits() && | 
|  | "Expected the second and third operands of the PARTIAL_REDUCE_MLA " | 
|  | "node to have an element type which is the same as or smaller than " | 
|  | "the element type of the first operand and result!"); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Perform trivial constant folding for arithmetic operators. | 
|  | switch (Opcode) { | 
|  | case ISD::FMA: | 
|  | case ISD::FMAD: | 
|  | case ISD::SETCC: | 
|  | case ISD::FSHL: | 
|  | case ISD::FSHR: | 
|  | if (SDValue SV = | 
|  | FoldConstantArithmetic(Opcode, DL, VT, {N1, N2, N3}, Flags)) | 
|  | return SV; | 
|  | break; | 
|  | } | 
|  |  | 
|  | // Memoize node if it doesn't produce a glue result. | 
|  | SDNode *N; | 
|  | SDVTList VTs = getVTList(VT); | 
|  | SDValue Ops[] = {N1, N2, N3}; | 
|  | if (VT != MVT::Glue) { | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, Opcode, VTs, Ops); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, DL, IP)) { | 
|  | E->intersectFlagsWith(Flags); | 
|  | return SDValue(E, 0); | 
|  | } | 
|  |  | 
|  | N = newSDNode<SDNode>(Opcode, DL.getIROrder(), DL.getDebugLoc(), VTs); | 
|  | N->setFlags(Flags); | 
|  | createOperands(N, Ops); | 
|  | CSEMap.InsertNode(N, IP); | 
|  | } else { | 
|  | N = newSDNode<SDNode>(Opcode, DL.getIROrder(), DL.getDebugLoc(), VTs); | 
|  | createOperands(N, Ops); | 
|  | } | 
|  |  | 
|  | InsertNode(N); | 
|  | SDValue V = SDValue(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT, | 
|  | SDValue N1, SDValue N2, SDValue N3, SDValue N4, | 
|  | const SDNodeFlags Flags) { | 
|  | SDValue Ops[] = { N1, N2, N3, N4 }; | 
|  | return getNode(Opcode, DL, VT, Ops, Flags); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT, | 
|  | SDValue N1, SDValue N2, SDValue N3, SDValue N4) { | 
|  | SDNodeFlags Flags; | 
|  | if (Inserter) | 
|  | Flags = Inserter->getFlags(); | 
|  | return getNode(Opcode, DL, VT, N1, N2, N3, N4, Flags); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT, | 
|  | SDValue N1, SDValue N2, SDValue N3, SDValue N4, | 
|  | SDValue N5, const SDNodeFlags Flags) { | 
|  | SDValue Ops[] = { N1, N2, N3, N4, N5 }; | 
|  | return getNode(Opcode, DL, VT, Ops, Flags); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT, | 
|  | SDValue N1, SDValue N2, SDValue N3, SDValue N4, | 
|  | SDValue N5) { | 
|  | SDNodeFlags Flags; | 
|  | if (Inserter) | 
|  | Flags = Inserter->getFlags(); | 
|  | return getNode(Opcode, DL, VT, N1, N2, N3, N4, N5, Flags); | 
|  | } | 
|  |  | 
|  | /// getStackArgumentTokenFactor - Compute a TokenFactor to force all | 
|  | /// the incoming stack arguments to be loaded from the stack. | 
|  | SDValue SelectionDAG::getStackArgumentTokenFactor(SDValue Chain) { | 
|  | SmallVector<SDValue, 8> ArgChains; | 
|  |  | 
|  | // Include the original chain at the beginning of the list. When this is | 
|  | // used by target LowerCall hooks, this helps legalize find the | 
|  | // CALLSEQ_BEGIN node. | 
|  | ArgChains.push_back(Chain); | 
|  |  | 
|  | // Add a chain value for each stack argument. | 
|  | for (SDNode *U : getEntryNode().getNode()->users()) | 
|  | if (LoadSDNode *L = dyn_cast<LoadSDNode>(U)) | 
|  | if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(L->getBasePtr())) | 
|  | if (FI->getIndex() < 0) | 
|  | ArgChains.push_back(SDValue(L, 1)); | 
|  |  | 
|  | // Build a tokenfactor for all the chains. | 
|  | return getNode(ISD::TokenFactor, SDLoc(Chain), MVT::Other, ArgChains); | 
|  | } | 
|  |  | 
|  | /// getMemsetValue - Vectorized representation of the memset value | 
|  | /// operand. | 
|  | static SDValue getMemsetValue(SDValue Value, EVT VT, SelectionDAG &DAG, | 
|  | const SDLoc &dl) { | 
|  | assert(!Value.isUndef()); | 
|  |  | 
|  | unsigned NumBits = VT.getScalarSizeInBits(); | 
|  | if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Value)) { | 
|  | assert(C->getAPIntValue().getBitWidth() == 8); | 
|  | APInt Val = APInt::getSplat(NumBits, C->getAPIntValue()); | 
|  | if (VT.isInteger()) { | 
|  | bool IsOpaque = VT.getSizeInBits() > 64 || | 
|  | !DAG.getTargetLoweringInfo().isLegalStoreImmediate(C->getSExtValue()); | 
|  | return DAG.getConstant(Val, dl, VT, false, IsOpaque); | 
|  | } | 
|  | return DAG.getConstantFP(APFloat(VT.getFltSemantics(), Val), dl, VT); | 
|  | } | 
|  |  | 
|  | assert(Value.getValueType() == MVT::i8 && "memset with non-byte fill value?"); | 
|  | EVT IntVT = VT.getScalarType(); | 
|  | if (!IntVT.isInteger()) | 
|  | IntVT = EVT::getIntegerVT(*DAG.getContext(), IntVT.getSizeInBits()); | 
|  |  | 
|  | Value = DAG.getNode(ISD::ZERO_EXTEND, dl, IntVT, Value); | 
|  | if (NumBits > 8) { | 
|  | // Use a multiplication with 0x010101... to extend the input to the | 
|  | // required length. | 
|  | APInt Magic = APInt::getSplat(NumBits, APInt(8, 0x01)); | 
|  | Value = DAG.getNode(ISD::MUL, dl, IntVT, Value, | 
|  | DAG.getConstant(Magic, dl, IntVT)); | 
|  | } | 
|  |  | 
|  | if (VT != Value.getValueType() && !VT.isInteger()) | 
|  | Value = DAG.getBitcast(VT.getScalarType(), Value); | 
|  | if (VT != Value.getValueType()) | 
|  | Value = DAG.getSplatBuildVector(VT, dl, Value); | 
|  |  | 
|  | return Value; | 
|  | } | 
|  |  | 
|  | /// getMemsetStringVal - Similar to getMemsetValue. Except this is only | 
|  | /// used when a memcpy is turned into a memset when the source is a constant | 
|  | /// string ptr. | 
|  | static SDValue getMemsetStringVal(EVT VT, const SDLoc &dl, SelectionDAG &DAG, | 
|  | const TargetLowering &TLI, | 
|  | const ConstantDataArraySlice &Slice) { | 
|  | // Handle vector with all elements zero. | 
|  | if (Slice.Array == nullptr) { | 
|  | if (VT.isInteger()) | 
|  | return DAG.getConstant(0, dl, VT); | 
|  | return DAG.getNode(ISD::BITCAST, dl, VT, | 
|  | DAG.getConstant(0, dl, VT.changeTypeToInteger())); | 
|  | } | 
|  |  | 
|  | assert(!VT.isVector() && "Can't handle vector type here!"); | 
|  | unsigned NumVTBits = VT.getSizeInBits(); | 
|  | unsigned NumVTBytes = NumVTBits / 8; | 
|  | unsigned NumBytes = std::min(NumVTBytes, unsigned(Slice.Length)); | 
|  |  | 
|  | APInt Val(NumVTBits, 0); | 
|  | if (DAG.getDataLayout().isLittleEndian()) { | 
|  | for (unsigned i = 0; i != NumBytes; ++i) | 
|  | Val |= (uint64_t)(unsigned char)Slice[i] << i*8; | 
|  | } else { | 
|  | for (unsigned i = 0; i != NumBytes; ++i) | 
|  | Val |= (uint64_t)(unsigned char)Slice[i] << (NumVTBytes-i-1)*8; | 
|  | } | 
|  |  | 
|  | // If the "cost" of materializing the integer immediate is less than the cost | 
|  | // of a load, then it is cost effective to turn the load into the immediate. | 
|  | Type *Ty = VT.getTypeForEVT(*DAG.getContext()); | 
|  | if (TLI.shouldConvertConstantLoadToIntImm(Val, Ty)) | 
|  | return DAG.getConstant(Val, dl, VT); | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getMemBasePlusOffset(SDValue Base, TypeSize Offset, | 
|  | const SDLoc &DL, | 
|  | const SDNodeFlags Flags) { | 
|  | EVT VT = Base.getValueType(); | 
|  | SDValue Index; | 
|  |  | 
|  | if (Offset.isScalable()) | 
|  | Index = getVScale(DL, Base.getValueType(), | 
|  | APInt(Base.getValueSizeInBits().getFixedValue(), | 
|  | Offset.getKnownMinValue())); | 
|  | else | 
|  | Index = getConstant(Offset.getFixedValue(), DL, VT); | 
|  |  | 
|  | return getMemBasePlusOffset(Base, Index, DL, Flags); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getMemBasePlusOffset(SDValue Ptr, SDValue Offset, | 
|  | const SDLoc &DL, | 
|  | const SDNodeFlags Flags) { | 
|  | assert(Offset.getValueType().isInteger()); | 
|  | EVT BasePtrVT = Ptr.getValueType(); | 
|  | if (TLI->shouldPreservePtrArith(this->getMachineFunction().getFunction(), | 
|  | BasePtrVT)) | 
|  | return getNode(ISD::PTRADD, DL, BasePtrVT, Ptr, Offset, Flags); | 
|  | return getNode(ISD::ADD, DL, BasePtrVT, Ptr, Offset, Flags); | 
|  | } | 
|  |  | 
|  | /// Returns true if memcpy source is constant data. | 
|  | static bool isMemSrcFromConstant(SDValue Src, ConstantDataArraySlice &Slice) { | 
|  | uint64_t SrcDelta = 0; | 
|  | GlobalAddressSDNode *G = nullptr; | 
|  | if (Src.getOpcode() == ISD::GlobalAddress) | 
|  | G = cast<GlobalAddressSDNode>(Src); | 
|  | else if (Src.getOpcode() == ISD::ADD && | 
|  | Src.getOperand(0).getOpcode() == ISD::GlobalAddress && | 
|  | Src.getOperand(1).getOpcode() == ISD::Constant) { | 
|  | G = cast<GlobalAddressSDNode>(Src.getOperand(0)); | 
|  | SrcDelta = Src.getConstantOperandVal(1); | 
|  | } | 
|  | if (!G) | 
|  | return false; | 
|  |  | 
|  | return getConstantDataArrayInfo(G->getGlobal(), Slice, 8, | 
|  | SrcDelta + G->getOffset()); | 
|  | } | 
|  |  | 
|  | static bool shouldLowerMemFuncForSize(const MachineFunction &MF, | 
|  | SelectionDAG &DAG) { | 
|  | // On Darwin, -Os means optimize for size without hurting performance, so | 
|  | // only really optimize for size when -Oz (MinSize) is used. | 
|  | if (MF.getTarget().getTargetTriple().isOSDarwin()) | 
|  | return MF.getFunction().hasMinSize(); | 
|  | return DAG.shouldOptForSize(); | 
|  | } | 
|  |  | 
|  | static void chainLoadsAndStoresForMemcpy(SelectionDAG &DAG, const SDLoc &dl, | 
|  | SmallVector<SDValue, 32> &OutChains, unsigned From, | 
|  | unsigned To, SmallVector<SDValue, 16> &OutLoadChains, | 
|  | SmallVector<SDValue, 16> &OutStoreChains) { | 
|  | assert(OutLoadChains.size() && "Missing loads in memcpy inlining"); | 
|  | assert(OutStoreChains.size() && "Missing stores in memcpy inlining"); | 
|  | SmallVector<SDValue, 16> GluedLoadChains; | 
|  | for (unsigned i = From; i < To; ++i) { | 
|  | OutChains.push_back(OutLoadChains[i]); | 
|  | GluedLoadChains.push_back(OutLoadChains[i]); | 
|  | } | 
|  |  | 
|  | // Chain for all loads. | 
|  | SDValue LoadToken = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, | 
|  | GluedLoadChains); | 
|  |  | 
|  | for (unsigned i = From; i < To; ++i) { | 
|  | StoreSDNode *ST = dyn_cast<StoreSDNode>(OutStoreChains[i]); | 
|  | SDValue NewStore = DAG.getTruncStore(LoadToken, dl, ST->getValue(), | 
|  | ST->getBasePtr(), ST->getMemoryVT(), | 
|  | ST->getMemOperand()); | 
|  | OutChains.push_back(NewStore); | 
|  | } | 
|  | } | 
|  |  | 
|  | static SDValue getMemcpyLoadsAndStores( | 
|  | SelectionDAG &DAG, const SDLoc &dl, SDValue Chain, SDValue Dst, SDValue Src, | 
|  | uint64_t Size, Align Alignment, bool isVol, bool AlwaysInline, | 
|  | MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo, | 
|  | const AAMDNodes &AAInfo, BatchAAResults *BatchAA) { | 
|  | // Turn a memcpy of undef to nop. | 
|  | // FIXME: We need to honor volatile even is Src is undef. | 
|  | if (Src.isUndef()) | 
|  | return Chain; | 
|  |  | 
|  | // Expand memcpy to a series of load and store ops if the size operand falls | 
|  | // below a certain threshold. | 
|  | // TODO: In the AlwaysInline case, if the size is big then generate a loop | 
|  | // rather than maybe a humongous number of loads and stores. | 
|  | const TargetLowering &TLI = DAG.getTargetLoweringInfo(); | 
|  | const DataLayout &DL = DAG.getDataLayout(); | 
|  | LLVMContext &C = *DAG.getContext(); | 
|  | std::vector<EVT> MemOps; | 
|  | bool DstAlignCanChange = false; | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  | MachineFrameInfo &MFI = MF.getFrameInfo(); | 
|  | bool OptSize = shouldLowerMemFuncForSize(MF, DAG); | 
|  | FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(Dst); | 
|  | if (FI && !MFI.isFixedObjectIndex(FI->getIndex())) | 
|  | DstAlignCanChange = true; | 
|  | MaybeAlign SrcAlign = DAG.InferPtrAlign(Src); | 
|  | if (!SrcAlign || Alignment > *SrcAlign) | 
|  | SrcAlign = Alignment; | 
|  | assert(SrcAlign && "SrcAlign must be set"); | 
|  | ConstantDataArraySlice Slice; | 
|  | // If marked as volatile, perform a copy even when marked as constant. | 
|  | bool CopyFromConstant = !isVol && isMemSrcFromConstant(Src, Slice); | 
|  | bool isZeroConstant = CopyFromConstant && Slice.Array == nullptr; | 
|  | unsigned Limit = AlwaysInline ? ~0U : TLI.getMaxStoresPerMemcpy(OptSize); | 
|  | const MemOp Op = isZeroConstant | 
|  | ? MemOp::Set(Size, DstAlignCanChange, Alignment, | 
|  | /*IsZeroMemset*/ true, isVol) | 
|  | : MemOp::Copy(Size, DstAlignCanChange, Alignment, | 
|  | *SrcAlign, isVol, CopyFromConstant); | 
|  | if (!TLI.findOptimalMemOpLowering( | 
|  | C, MemOps, Limit, Op, DstPtrInfo.getAddrSpace(), | 
|  | SrcPtrInfo.getAddrSpace(), MF.getFunction().getAttributes())) | 
|  | return SDValue(); | 
|  |  | 
|  | if (DstAlignCanChange) { | 
|  | Type *Ty = MemOps[0].getTypeForEVT(C); | 
|  | Align NewAlign = DL.getABITypeAlign(Ty); | 
|  |  | 
|  | // Don't promote to an alignment that would require dynamic stack | 
|  | // realignment which may conflict with optimizations such as tail call | 
|  | // optimization. | 
|  | const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); | 
|  | if (!TRI->hasStackRealignment(MF)) | 
|  | if (MaybeAlign StackAlign = DL.getStackAlignment()) | 
|  | NewAlign = std::min(NewAlign, *StackAlign); | 
|  |  | 
|  | if (NewAlign > Alignment) { | 
|  | // Give the stack frame object a larger alignment if needed. | 
|  | if (MFI.getObjectAlign(FI->getIndex()) < NewAlign) | 
|  | MFI.setObjectAlignment(FI->getIndex(), NewAlign); | 
|  | Alignment = NewAlign; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Prepare AAInfo for loads/stores after lowering this memcpy. | 
|  | AAMDNodes NewAAInfo = AAInfo; | 
|  | NewAAInfo.TBAA = NewAAInfo.TBAAStruct = nullptr; | 
|  |  | 
|  | const Value *SrcVal = dyn_cast_if_present<const Value *>(SrcPtrInfo.V); | 
|  | bool isConstant = | 
|  | BatchAA && SrcVal && | 
|  | BatchAA->pointsToConstantMemory(MemoryLocation(SrcVal, Size, AAInfo)); | 
|  |  | 
|  | MachineMemOperand::Flags MMOFlags = | 
|  | isVol ? MachineMemOperand::MOVolatile : MachineMemOperand::MONone; | 
|  | SmallVector<SDValue, 16> OutLoadChains; | 
|  | SmallVector<SDValue, 16> OutStoreChains; | 
|  | SmallVector<SDValue, 32> OutChains; | 
|  | unsigned NumMemOps = MemOps.size(); | 
|  | uint64_t SrcOff = 0, DstOff = 0; | 
|  | for (unsigned i = 0; i != NumMemOps; ++i) { | 
|  | EVT VT = MemOps[i]; | 
|  | unsigned VTSize = VT.getSizeInBits() / 8; | 
|  | SDValue Value, Store; | 
|  |  | 
|  | if (VTSize > Size) { | 
|  | // Issuing an unaligned load / store pair  that overlaps with the previous | 
|  | // pair. Adjust the offset accordingly. | 
|  | assert(i == NumMemOps-1 && i != 0); | 
|  | SrcOff -= VTSize - Size; | 
|  | DstOff -= VTSize - Size; | 
|  | } | 
|  |  | 
|  | if (CopyFromConstant && | 
|  | (isZeroConstant || (VT.isInteger() && !VT.isVector()))) { | 
|  | // It's unlikely a store of a vector immediate can be done in a single | 
|  | // instruction. It would require a load from a constantpool first. | 
|  | // We only handle zero vectors here. | 
|  | // FIXME: Handle other cases where store of vector immediate is done in | 
|  | // a single instruction. | 
|  | ConstantDataArraySlice SubSlice; | 
|  | if (SrcOff < Slice.Length) { | 
|  | SubSlice = Slice; | 
|  | SubSlice.move(SrcOff); | 
|  | } else { | 
|  | // This is an out-of-bounds access and hence UB. Pretend we read zero. | 
|  | SubSlice.Array = nullptr; | 
|  | SubSlice.Offset = 0; | 
|  | SubSlice.Length = VTSize; | 
|  | } | 
|  | Value = getMemsetStringVal(VT, dl, DAG, TLI, SubSlice); | 
|  | if (Value.getNode()) { | 
|  | Store = DAG.getStore( | 
|  | Chain, dl, Value, | 
|  | DAG.getMemBasePlusOffset(Dst, TypeSize::getFixed(DstOff), dl), | 
|  | DstPtrInfo.getWithOffset(DstOff), Alignment, MMOFlags, NewAAInfo); | 
|  | OutChains.push_back(Store); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!Store.getNode()) { | 
|  | // The type might not be legal for the target.  This should only happen | 
|  | // if the type is smaller than a legal type, as on PPC, so the right | 
|  | // thing to do is generate a LoadExt/StoreTrunc pair.  These simplify | 
|  | // to Load/Store if NVT==VT. | 
|  | // FIXME does the case above also need this? | 
|  | EVT NVT = TLI.getTypeToTransformTo(C, VT); | 
|  | assert(NVT.bitsGE(VT)); | 
|  |  | 
|  | bool isDereferenceable = | 
|  | SrcPtrInfo.getWithOffset(SrcOff).isDereferenceable(VTSize, C, DL); | 
|  | MachineMemOperand::Flags SrcMMOFlags = MMOFlags; | 
|  | if (isDereferenceable) | 
|  | SrcMMOFlags |= MachineMemOperand::MODereferenceable; | 
|  | if (isConstant) | 
|  | SrcMMOFlags |= MachineMemOperand::MOInvariant; | 
|  |  | 
|  | Value = DAG.getExtLoad( | 
|  | ISD::EXTLOAD, dl, NVT, Chain, | 
|  | DAG.getMemBasePlusOffset(Src, TypeSize::getFixed(SrcOff), dl), | 
|  | SrcPtrInfo.getWithOffset(SrcOff), VT, | 
|  | commonAlignment(*SrcAlign, SrcOff), SrcMMOFlags, NewAAInfo); | 
|  | OutLoadChains.push_back(Value.getValue(1)); | 
|  |  | 
|  | Store = DAG.getTruncStore( | 
|  | Chain, dl, Value, | 
|  | DAG.getMemBasePlusOffset(Dst, TypeSize::getFixed(DstOff), dl), | 
|  | DstPtrInfo.getWithOffset(DstOff), VT, Alignment, MMOFlags, NewAAInfo); | 
|  | OutStoreChains.push_back(Store); | 
|  | } | 
|  | SrcOff += VTSize; | 
|  | DstOff += VTSize; | 
|  | Size -= VTSize; | 
|  | } | 
|  |  | 
|  | unsigned GluedLdStLimit = MaxLdStGlue == 0 ? | 
|  | TLI.getMaxGluedStoresPerMemcpy() : MaxLdStGlue; | 
|  | unsigned NumLdStInMemcpy = OutStoreChains.size(); | 
|  |  | 
|  | if (NumLdStInMemcpy) { | 
|  | // It may be that memcpy might be converted to memset if it's memcpy | 
|  | // of constants. In such a case, we won't have loads and stores, but | 
|  | // just stores. In the absence of loads, there is nothing to gang up. | 
|  | if ((GluedLdStLimit <= 1) || !EnableMemCpyDAGOpt) { | 
|  | // If target does not care, just leave as it. | 
|  | for (unsigned i = 0; i < NumLdStInMemcpy; ++i) { | 
|  | OutChains.push_back(OutLoadChains[i]); | 
|  | OutChains.push_back(OutStoreChains[i]); | 
|  | } | 
|  | } else { | 
|  | // Ld/St less than/equal limit set by target. | 
|  | if (NumLdStInMemcpy <= GluedLdStLimit) { | 
|  | chainLoadsAndStoresForMemcpy(DAG, dl, OutChains, 0, | 
|  | NumLdStInMemcpy, OutLoadChains, | 
|  | OutStoreChains); | 
|  | } else { | 
|  | unsigned NumberLdChain =  NumLdStInMemcpy / GluedLdStLimit; | 
|  | unsigned RemainingLdStInMemcpy = NumLdStInMemcpy % GluedLdStLimit; | 
|  | unsigned GlueIter = 0; | 
|  |  | 
|  | for (unsigned cnt = 0; cnt < NumberLdChain; ++cnt) { | 
|  | unsigned IndexFrom = NumLdStInMemcpy - GlueIter - GluedLdStLimit; | 
|  | unsigned IndexTo   = NumLdStInMemcpy - GlueIter; | 
|  |  | 
|  | chainLoadsAndStoresForMemcpy(DAG, dl, OutChains, IndexFrom, IndexTo, | 
|  | OutLoadChains, OutStoreChains); | 
|  | GlueIter += GluedLdStLimit; | 
|  | } | 
|  |  | 
|  | // Residual ld/st. | 
|  | if (RemainingLdStInMemcpy) { | 
|  | chainLoadsAndStoresForMemcpy(DAG, dl, OutChains, 0, | 
|  | RemainingLdStInMemcpy, OutLoadChains, | 
|  | OutStoreChains); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, OutChains); | 
|  | } | 
|  |  | 
|  | static SDValue getMemmoveLoadsAndStores(SelectionDAG &DAG, const SDLoc &dl, | 
|  | SDValue Chain, SDValue Dst, SDValue Src, | 
|  | uint64_t Size, Align Alignment, | 
|  | bool isVol, bool AlwaysInline, | 
|  | MachinePointerInfo DstPtrInfo, | 
|  | MachinePointerInfo SrcPtrInfo, | 
|  | const AAMDNodes &AAInfo) { | 
|  | // Turn a memmove of undef to nop. | 
|  | // FIXME: We need to honor volatile even is Src is undef. | 
|  | if (Src.isUndef()) | 
|  | return Chain; | 
|  |  | 
|  | // Expand memmove to a series of load and store ops if the size operand falls | 
|  | // below a certain threshold. | 
|  | const TargetLowering &TLI = DAG.getTargetLoweringInfo(); | 
|  | const DataLayout &DL = DAG.getDataLayout(); | 
|  | LLVMContext &C = *DAG.getContext(); | 
|  | std::vector<EVT> MemOps; | 
|  | bool DstAlignCanChange = false; | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  | MachineFrameInfo &MFI = MF.getFrameInfo(); | 
|  | bool OptSize = shouldLowerMemFuncForSize(MF, DAG); | 
|  | FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(Dst); | 
|  | if (FI && !MFI.isFixedObjectIndex(FI->getIndex())) | 
|  | DstAlignCanChange = true; | 
|  | MaybeAlign SrcAlign = DAG.InferPtrAlign(Src); | 
|  | if (!SrcAlign || Alignment > *SrcAlign) | 
|  | SrcAlign = Alignment; | 
|  | assert(SrcAlign && "SrcAlign must be set"); | 
|  | unsigned Limit = AlwaysInline ? ~0U : TLI.getMaxStoresPerMemmove(OptSize); | 
|  | if (!TLI.findOptimalMemOpLowering( | 
|  | C, MemOps, Limit, | 
|  | MemOp::Copy(Size, DstAlignCanChange, Alignment, *SrcAlign, | 
|  | /*IsVolatile*/ true), | 
|  | DstPtrInfo.getAddrSpace(), SrcPtrInfo.getAddrSpace(), | 
|  | MF.getFunction().getAttributes())) | 
|  | return SDValue(); | 
|  |  | 
|  | if (DstAlignCanChange) { | 
|  | Type *Ty = MemOps[0].getTypeForEVT(C); | 
|  | Align NewAlign = DL.getABITypeAlign(Ty); | 
|  |  | 
|  | // Don't promote to an alignment that would require dynamic stack | 
|  | // realignment which may conflict with optimizations such as tail call | 
|  | // optimization. | 
|  | const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); | 
|  | if (!TRI->hasStackRealignment(MF)) | 
|  | if (MaybeAlign StackAlign = DL.getStackAlignment()) | 
|  | NewAlign = std::min(NewAlign, *StackAlign); | 
|  |  | 
|  | if (NewAlign > Alignment) { | 
|  | // Give the stack frame object a larger alignment if needed. | 
|  | if (MFI.getObjectAlign(FI->getIndex()) < NewAlign) | 
|  | MFI.setObjectAlignment(FI->getIndex(), NewAlign); | 
|  | Alignment = NewAlign; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Prepare AAInfo for loads/stores after lowering this memmove. | 
|  | AAMDNodes NewAAInfo = AAInfo; | 
|  | NewAAInfo.TBAA = NewAAInfo.TBAAStruct = nullptr; | 
|  |  | 
|  | MachineMemOperand::Flags MMOFlags = | 
|  | isVol ? MachineMemOperand::MOVolatile : MachineMemOperand::MONone; | 
|  | uint64_t SrcOff = 0, DstOff = 0; | 
|  | SmallVector<SDValue, 8> LoadValues; | 
|  | SmallVector<SDValue, 8> LoadChains; | 
|  | SmallVector<SDValue, 8> OutChains; | 
|  | unsigned NumMemOps = MemOps.size(); | 
|  | for (unsigned i = 0; i < NumMemOps; i++) { | 
|  | EVT VT = MemOps[i]; | 
|  | unsigned VTSize = VT.getSizeInBits() / 8; | 
|  | SDValue Value; | 
|  |  | 
|  | bool isDereferenceable = | 
|  | SrcPtrInfo.getWithOffset(SrcOff).isDereferenceable(VTSize, C, DL); | 
|  | MachineMemOperand::Flags SrcMMOFlags = MMOFlags; | 
|  | if (isDereferenceable) | 
|  | SrcMMOFlags |= MachineMemOperand::MODereferenceable; | 
|  |  | 
|  | Value = DAG.getLoad( | 
|  | VT, dl, Chain, | 
|  | DAG.getMemBasePlusOffset(Src, TypeSize::getFixed(SrcOff), dl), | 
|  | SrcPtrInfo.getWithOffset(SrcOff), *SrcAlign, SrcMMOFlags, NewAAInfo); | 
|  | LoadValues.push_back(Value); | 
|  | LoadChains.push_back(Value.getValue(1)); | 
|  | SrcOff += VTSize; | 
|  | } | 
|  | Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, LoadChains); | 
|  | OutChains.clear(); | 
|  | for (unsigned i = 0; i < NumMemOps; i++) { | 
|  | EVT VT = MemOps[i]; | 
|  | unsigned VTSize = VT.getSizeInBits() / 8; | 
|  | SDValue Store; | 
|  |  | 
|  | Store = DAG.getStore( | 
|  | Chain, dl, LoadValues[i], | 
|  | DAG.getMemBasePlusOffset(Dst, TypeSize::getFixed(DstOff), dl), | 
|  | DstPtrInfo.getWithOffset(DstOff), Alignment, MMOFlags, NewAAInfo); | 
|  | OutChains.push_back(Store); | 
|  | DstOff += VTSize; | 
|  | } | 
|  |  | 
|  | return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, OutChains); | 
|  | } | 
|  |  | 
|  | /// Lower the call to 'memset' intrinsic function into a series of store | 
|  | /// operations. | 
|  | /// | 
|  | /// \param DAG Selection DAG where lowered code is placed. | 
|  | /// \param dl Link to corresponding IR location. | 
|  | /// \param Chain Control flow dependency. | 
|  | /// \param Dst Pointer to destination memory location. | 
|  | /// \param Src Value of byte to write into the memory. | 
|  | /// \param Size Number of bytes to write. | 
|  | /// \param Alignment Alignment of the destination in bytes. | 
|  | /// \param isVol True if destination is volatile. | 
|  | /// \param AlwaysInline Makes sure no function call is generated. | 
|  | /// \param DstPtrInfo IR information on the memory pointer. | 
|  | /// \returns New head in the control flow, if lowering was successful, empty | 
|  | /// SDValue otherwise. | 
|  | /// | 
|  | /// The function tries to replace 'llvm.memset' intrinsic with several store | 
|  | /// operations and value calculation code. This is usually profitable for small | 
|  | /// memory size or when the semantic requires inlining. | 
|  | static SDValue getMemsetStores(SelectionDAG &DAG, const SDLoc &dl, | 
|  | SDValue Chain, SDValue Dst, SDValue Src, | 
|  | uint64_t Size, Align Alignment, bool isVol, | 
|  | bool AlwaysInline, MachinePointerInfo DstPtrInfo, | 
|  | const AAMDNodes &AAInfo) { | 
|  | // Turn a memset of undef to nop. | 
|  | // FIXME: We need to honor volatile even is Src is undef. | 
|  | if (Src.isUndef()) | 
|  | return Chain; | 
|  |  | 
|  | // Expand memset to a series of load/store ops if the size operand | 
|  | // falls below a certain threshold. | 
|  | const TargetLowering &TLI = DAG.getTargetLoweringInfo(); | 
|  | std::vector<EVT> MemOps; | 
|  | bool DstAlignCanChange = false; | 
|  | LLVMContext &C = *DAG.getContext(); | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  | MachineFrameInfo &MFI = MF.getFrameInfo(); | 
|  | bool OptSize = shouldLowerMemFuncForSize(MF, DAG); | 
|  | FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(Dst); | 
|  | if (FI && !MFI.isFixedObjectIndex(FI->getIndex())) | 
|  | DstAlignCanChange = true; | 
|  | bool IsZeroVal = isNullConstant(Src); | 
|  | unsigned Limit = AlwaysInline ? ~0 : TLI.getMaxStoresPerMemset(OptSize); | 
|  |  | 
|  | if (!TLI.findOptimalMemOpLowering( | 
|  | C, MemOps, Limit, | 
|  | MemOp::Set(Size, DstAlignCanChange, Alignment, IsZeroVal, isVol), | 
|  | DstPtrInfo.getAddrSpace(), ~0u, MF.getFunction().getAttributes())) | 
|  | return SDValue(); | 
|  |  | 
|  | if (DstAlignCanChange) { | 
|  | Type *Ty = MemOps[0].getTypeForEVT(*DAG.getContext()); | 
|  | const DataLayout &DL = DAG.getDataLayout(); | 
|  | Align NewAlign = DL.getABITypeAlign(Ty); | 
|  |  | 
|  | // Don't promote to an alignment that would require dynamic stack | 
|  | // realignment which may conflict with optimizations such as tail call | 
|  | // optimization. | 
|  | const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); | 
|  | if (!TRI->hasStackRealignment(MF)) | 
|  | if (MaybeAlign StackAlign = DL.getStackAlignment()) | 
|  | NewAlign = std::min(NewAlign, *StackAlign); | 
|  |  | 
|  | if (NewAlign > Alignment) { | 
|  | // Give the stack frame object a larger alignment if needed. | 
|  | if (MFI.getObjectAlign(FI->getIndex()) < NewAlign) | 
|  | MFI.setObjectAlignment(FI->getIndex(), NewAlign); | 
|  | Alignment = NewAlign; | 
|  | } | 
|  | } | 
|  |  | 
|  | SmallVector<SDValue, 8> OutChains; | 
|  | uint64_t DstOff = 0; | 
|  | unsigned NumMemOps = MemOps.size(); | 
|  |  | 
|  | // Find the largest store and generate the bit pattern for it. | 
|  | EVT LargestVT = MemOps[0]; | 
|  | for (unsigned i = 1; i < NumMemOps; i++) | 
|  | if (MemOps[i].bitsGT(LargestVT)) | 
|  | LargestVT = MemOps[i]; | 
|  | SDValue MemSetValue = getMemsetValue(Src, LargestVT, DAG, dl); | 
|  |  | 
|  | // Prepare AAInfo for loads/stores after lowering this memset. | 
|  | AAMDNodes NewAAInfo = AAInfo; | 
|  | NewAAInfo.TBAA = NewAAInfo.TBAAStruct = nullptr; | 
|  |  | 
|  | for (unsigned i = 0; i < NumMemOps; i++) { | 
|  | EVT VT = MemOps[i]; | 
|  | unsigned VTSize = VT.getSizeInBits() / 8; | 
|  | if (VTSize > Size) { | 
|  | // Issuing an unaligned load / store pair  that overlaps with the previous | 
|  | // pair. Adjust the offset accordingly. | 
|  | assert(i == NumMemOps-1 && i != 0); | 
|  | DstOff -= VTSize - Size; | 
|  | } | 
|  |  | 
|  | // If this store is smaller than the largest store see whether we can get | 
|  | // the smaller value for free with a truncate or extract vector element and | 
|  | // then store. | 
|  | SDValue Value = MemSetValue; | 
|  | if (VT.bitsLT(LargestVT)) { | 
|  | unsigned Index; | 
|  | unsigned NElts = LargestVT.getSizeInBits() / VT.getSizeInBits(); | 
|  | EVT SVT = EVT::getVectorVT(*DAG.getContext(), VT.getScalarType(), NElts); | 
|  | if (!LargestVT.isVector() && !VT.isVector() && | 
|  | TLI.isTruncateFree(LargestVT, VT)) | 
|  | Value = DAG.getNode(ISD::TRUNCATE, dl, VT, MemSetValue); | 
|  | else if (LargestVT.isVector() && !VT.isVector() && | 
|  | TLI.shallExtractConstSplatVectorElementToStore( | 
|  | LargestVT.getTypeForEVT(*DAG.getContext()), | 
|  | VT.getSizeInBits(), Index) && | 
|  | TLI.isTypeLegal(SVT) && | 
|  | LargestVT.getSizeInBits() == SVT.getSizeInBits()) { | 
|  | // Target which can combine store(extractelement VectorTy, Idx) can get | 
|  | // the smaller value for free. | 
|  | SDValue TailValue = DAG.getNode(ISD::BITCAST, dl, SVT, MemSetValue); | 
|  | Value = DAG.getExtractVectorElt(dl, VT, TailValue, Index); | 
|  | } else | 
|  | Value = getMemsetValue(Src, VT, DAG, dl); | 
|  | } | 
|  | assert(Value.getValueType() == VT && "Value with wrong type."); | 
|  | SDValue Store = DAG.getStore( | 
|  | Chain, dl, Value, | 
|  | DAG.getMemBasePlusOffset(Dst, TypeSize::getFixed(DstOff), dl), | 
|  | DstPtrInfo.getWithOffset(DstOff), Alignment, | 
|  | isVol ? MachineMemOperand::MOVolatile : MachineMemOperand::MONone, | 
|  | NewAAInfo); | 
|  | OutChains.push_back(Store); | 
|  | DstOff += VT.getSizeInBits() / 8; | 
|  | Size -= VTSize; | 
|  | } | 
|  |  | 
|  | return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, OutChains); | 
|  | } | 
|  |  | 
|  | static void checkAddrSpaceIsValidForLibcall(const TargetLowering *TLI, | 
|  | unsigned AS) { | 
|  | // Lowering memcpy / memset / memmove intrinsics to calls is only valid if all | 
|  | // pointer operands can be losslessly bitcasted to pointers of address space 0 | 
|  | if (AS != 0 && !TLI->getTargetMachine().isNoopAddrSpaceCast(AS, 0)) { | 
|  | report_fatal_error("cannot lower memory intrinsic in address space " + | 
|  | Twine(AS)); | 
|  | } | 
|  | } | 
|  |  | 
|  | std::pair<SDValue, SDValue> | 
|  | SelectionDAG::getMemcmp(SDValue Chain, const SDLoc &dl, SDValue Mem0, | 
|  | SDValue Mem1, SDValue Size, const CallInst *CI) { | 
|  | const char *LibCallName = TLI->getLibcallName(RTLIB::MEMCMP); | 
|  | if (!LibCallName) | 
|  | return {}; | 
|  |  | 
|  | PointerType *PT = PointerType::getUnqual(*getContext()); | 
|  | TargetLowering::ArgListTy Args = { | 
|  | {Mem0, PT}, | 
|  | {Mem1, PT}, | 
|  | {Size, getDataLayout().getIntPtrType(*getContext())}}; | 
|  |  | 
|  | TargetLowering::CallLoweringInfo CLI(*this); | 
|  | bool IsTailCall = false; | 
|  | bool ReturnsFirstArg = CI && funcReturnsFirstArgOfCall(*CI); | 
|  | IsTailCall = CI && CI->isTailCall() && | 
|  | isInTailCallPosition(*CI, getTarget(), ReturnsFirstArg); | 
|  |  | 
|  | CLI.setDebugLoc(dl) | 
|  | .setChain(Chain) | 
|  | .setLibCallee( | 
|  | TLI->getLibcallCallingConv(RTLIB::MEMCMP), | 
|  | Type::getInt32Ty(*getContext()), | 
|  | getExternalSymbol(LibCallName, TLI->getPointerTy(getDataLayout())), | 
|  | std::move(Args)) | 
|  | .setTailCall(IsTailCall); | 
|  |  | 
|  | return TLI->LowerCallTo(CLI); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getMemcpy( | 
|  | SDValue Chain, const SDLoc &dl, SDValue Dst, SDValue Src, SDValue Size, | 
|  | Align Alignment, bool isVol, bool AlwaysInline, const CallInst *CI, | 
|  | std::optional<bool> OverrideTailCall, MachinePointerInfo DstPtrInfo, | 
|  | MachinePointerInfo SrcPtrInfo, const AAMDNodes &AAInfo, | 
|  | BatchAAResults *BatchAA) { | 
|  | // Check to see if we should lower the memcpy to loads and stores first. | 
|  | // For cases within the target-specified limits, this is the best choice. | 
|  | ConstantSDNode *ConstantSize = dyn_cast<ConstantSDNode>(Size); | 
|  | if (ConstantSize) { | 
|  | // Memcpy with size zero? Just return the original chain. | 
|  | if (ConstantSize->isZero()) | 
|  | return Chain; | 
|  |  | 
|  | SDValue Result = getMemcpyLoadsAndStores( | 
|  | *this, dl, Chain, Dst, Src, ConstantSize->getZExtValue(), Alignment, | 
|  | isVol, false, DstPtrInfo, SrcPtrInfo, AAInfo, BatchAA); | 
|  | if (Result.getNode()) | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | // Then check to see if we should lower the memcpy with target-specific | 
|  | // code. If the target chooses to do this, this is the next best. | 
|  | if (TSI) { | 
|  | SDValue Result = TSI->EmitTargetCodeForMemcpy( | 
|  | *this, dl, Chain, Dst, Src, Size, Alignment, isVol, AlwaysInline, | 
|  | DstPtrInfo, SrcPtrInfo); | 
|  | if (Result.getNode()) | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | // If we really need inline code and the target declined to provide it, | 
|  | // use a (potentially long) sequence of loads and stores. | 
|  | if (AlwaysInline) { | 
|  | assert(ConstantSize && "AlwaysInline requires a constant size!"); | 
|  | return getMemcpyLoadsAndStores( | 
|  | *this, dl, Chain, Dst, Src, ConstantSize->getZExtValue(), Alignment, | 
|  | isVol, true, DstPtrInfo, SrcPtrInfo, AAInfo, BatchAA); | 
|  | } | 
|  |  | 
|  | checkAddrSpaceIsValidForLibcall(TLI, DstPtrInfo.getAddrSpace()); | 
|  | checkAddrSpaceIsValidForLibcall(TLI, SrcPtrInfo.getAddrSpace()); | 
|  |  | 
|  | // FIXME: If the memcpy is volatile (isVol), lowering it to a plain libc | 
|  | // memcpy is not guaranteed to be safe. libc memcpys aren't required to | 
|  | // respect volatile, so they may do things like read or write memory | 
|  | // beyond the given memory regions. But fixing this isn't easy, and most | 
|  | // people don't care. | 
|  |  | 
|  | // Emit a library call. | 
|  | TargetLowering::ArgListTy Args; | 
|  | Type *PtrTy = PointerType::getUnqual(*getContext()); | 
|  | Args.emplace_back(Dst, PtrTy); | 
|  | Args.emplace_back(Src, PtrTy); | 
|  | Args.emplace_back(Size, getDataLayout().getIntPtrType(*getContext())); | 
|  | // FIXME: pass in SDLoc | 
|  | TargetLowering::CallLoweringInfo CLI(*this); | 
|  | bool IsTailCall = false; | 
|  | const char *MemCpyName = TLI->getMemcpyName(); | 
|  |  | 
|  | if (OverrideTailCall.has_value()) { | 
|  | IsTailCall = *OverrideTailCall; | 
|  | } else { | 
|  | bool LowersToMemcpy = StringRef(MemCpyName) == StringRef("memcpy"); | 
|  | bool ReturnsFirstArg = CI && funcReturnsFirstArgOfCall(*CI); | 
|  | IsTailCall = CI && CI->isTailCall() && | 
|  | isInTailCallPosition(*CI, getTarget(), | 
|  | ReturnsFirstArg && LowersToMemcpy); | 
|  | } | 
|  |  | 
|  | CLI.setDebugLoc(dl) | 
|  | .setChain(Chain) | 
|  | .setLibCallee( | 
|  | TLI->getLibcallCallingConv(RTLIB::MEMCPY), | 
|  | Dst.getValueType().getTypeForEVT(*getContext()), | 
|  | getExternalSymbol(MemCpyName, TLI->getPointerTy(getDataLayout())), | 
|  | std::move(Args)) | 
|  | .setDiscardResult() | 
|  | .setTailCall(IsTailCall); | 
|  |  | 
|  | std::pair<SDValue,SDValue> CallResult = TLI->LowerCallTo(CLI); | 
|  | return CallResult.second; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getAtomicMemcpy(SDValue Chain, const SDLoc &dl, | 
|  | SDValue Dst, SDValue Src, SDValue Size, | 
|  | Type *SizeTy, unsigned ElemSz, | 
|  | bool isTailCall, | 
|  | MachinePointerInfo DstPtrInfo, | 
|  | MachinePointerInfo SrcPtrInfo) { | 
|  | // Emit a library call. | 
|  | TargetLowering::ArgListTy Args; | 
|  | Type *ArgTy = getDataLayout().getIntPtrType(*getContext()); | 
|  | Args.emplace_back(Dst, ArgTy); | 
|  | Args.emplace_back(Src, ArgTy); | 
|  | Args.emplace_back(Size, SizeTy); | 
|  |  | 
|  | RTLIB::Libcall LibraryCall = | 
|  | RTLIB::getMEMCPY_ELEMENT_UNORDERED_ATOMIC(ElemSz); | 
|  | if (LibraryCall == RTLIB::UNKNOWN_LIBCALL) | 
|  | report_fatal_error("Unsupported element size"); | 
|  |  | 
|  | TargetLowering::CallLoweringInfo CLI(*this); | 
|  | CLI.setDebugLoc(dl) | 
|  | .setChain(Chain) | 
|  | .setLibCallee(TLI->getLibcallCallingConv(LibraryCall), | 
|  | Type::getVoidTy(*getContext()), | 
|  | getExternalSymbol(TLI->getLibcallName(LibraryCall), | 
|  | TLI->getPointerTy(getDataLayout())), | 
|  | std::move(Args)) | 
|  | .setDiscardResult() | 
|  | .setTailCall(isTailCall); | 
|  |  | 
|  | std::pair<SDValue, SDValue> CallResult = TLI->LowerCallTo(CLI); | 
|  | return CallResult.second; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getMemmove(SDValue Chain, const SDLoc &dl, SDValue Dst, | 
|  | SDValue Src, SDValue Size, Align Alignment, | 
|  | bool isVol, const CallInst *CI, | 
|  | std::optional<bool> OverrideTailCall, | 
|  | MachinePointerInfo DstPtrInfo, | 
|  | MachinePointerInfo SrcPtrInfo, | 
|  | const AAMDNodes &AAInfo, | 
|  | BatchAAResults *BatchAA) { | 
|  | // Check to see if we should lower the memmove to loads and stores first. | 
|  | // For cases within the target-specified limits, this is the best choice. | 
|  | ConstantSDNode *ConstantSize = dyn_cast<ConstantSDNode>(Size); | 
|  | if (ConstantSize) { | 
|  | // Memmove with size zero? Just return the original chain. | 
|  | if (ConstantSize->isZero()) | 
|  | return Chain; | 
|  |  | 
|  | SDValue Result = getMemmoveLoadsAndStores( | 
|  | *this, dl, Chain, Dst, Src, ConstantSize->getZExtValue(), Alignment, | 
|  | isVol, false, DstPtrInfo, SrcPtrInfo, AAInfo); | 
|  | if (Result.getNode()) | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | // Then check to see if we should lower the memmove with target-specific | 
|  | // code. If the target chooses to do this, this is the next best. | 
|  | if (TSI) { | 
|  | SDValue Result = | 
|  | TSI->EmitTargetCodeForMemmove(*this, dl, Chain, Dst, Src, Size, | 
|  | Alignment, isVol, DstPtrInfo, SrcPtrInfo); | 
|  | if (Result.getNode()) | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | checkAddrSpaceIsValidForLibcall(TLI, DstPtrInfo.getAddrSpace()); | 
|  | checkAddrSpaceIsValidForLibcall(TLI, SrcPtrInfo.getAddrSpace()); | 
|  |  | 
|  | // FIXME: If the memmove is volatile, lowering it to plain libc memmove may | 
|  | // not be safe.  See memcpy above for more details. | 
|  |  | 
|  | // Emit a library call. | 
|  | TargetLowering::ArgListTy Args; | 
|  | Type *PtrTy = PointerType::getUnqual(*getContext()); | 
|  | Args.emplace_back(Dst, PtrTy); | 
|  | Args.emplace_back(Src, PtrTy); | 
|  | Args.emplace_back(Size, getDataLayout().getIntPtrType(*getContext())); | 
|  | // FIXME:  pass in SDLoc | 
|  | TargetLowering::CallLoweringInfo CLI(*this); | 
|  |  | 
|  | bool IsTailCall = false; | 
|  | if (OverrideTailCall.has_value()) { | 
|  | IsTailCall = *OverrideTailCall; | 
|  | } else { | 
|  | bool LowersToMemmove = | 
|  | TLI->getLibcallName(RTLIB::MEMMOVE) == StringRef("memmove"); | 
|  | bool ReturnsFirstArg = CI && funcReturnsFirstArgOfCall(*CI); | 
|  | IsTailCall = CI && CI->isTailCall() && | 
|  | isInTailCallPosition(*CI, getTarget(), | 
|  | ReturnsFirstArg && LowersToMemmove); | 
|  | } | 
|  |  | 
|  | CLI.setDebugLoc(dl) | 
|  | .setChain(Chain) | 
|  | .setLibCallee(TLI->getLibcallCallingConv(RTLIB::MEMMOVE), | 
|  | Dst.getValueType().getTypeForEVT(*getContext()), | 
|  | getExternalSymbol(TLI->getLibcallName(RTLIB::MEMMOVE), | 
|  | TLI->getPointerTy(getDataLayout())), | 
|  | std::move(Args)) | 
|  | .setDiscardResult() | 
|  | .setTailCall(IsTailCall); | 
|  |  | 
|  | std::pair<SDValue,SDValue> CallResult = TLI->LowerCallTo(CLI); | 
|  | return CallResult.second; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getAtomicMemmove(SDValue Chain, const SDLoc &dl, | 
|  | SDValue Dst, SDValue Src, SDValue Size, | 
|  | Type *SizeTy, unsigned ElemSz, | 
|  | bool isTailCall, | 
|  | MachinePointerInfo DstPtrInfo, | 
|  | MachinePointerInfo SrcPtrInfo) { | 
|  | // Emit a library call. | 
|  | TargetLowering::ArgListTy Args; | 
|  | Type *IntPtrTy = getDataLayout().getIntPtrType(*getContext()); | 
|  | Args.emplace_back(Dst, IntPtrTy); | 
|  | Args.emplace_back(Src, IntPtrTy); | 
|  | Args.emplace_back(Size, SizeTy); | 
|  |  | 
|  | RTLIB::Libcall LibraryCall = | 
|  | RTLIB::getMEMMOVE_ELEMENT_UNORDERED_ATOMIC(ElemSz); | 
|  | if (LibraryCall == RTLIB::UNKNOWN_LIBCALL) | 
|  | report_fatal_error("Unsupported element size"); | 
|  |  | 
|  | TargetLowering::CallLoweringInfo CLI(*this); | 
|  | CLI.setDebugLoc(dl) | 
|  | .setChain(Chain) | 
|  | .setLibCallee(TLI->getLibcallCallingConv(LibraryCall), | 
|  | Type::getVoidTy(*getContext()), | 
|  | getExternalSymbol(TLI->getLibcallName(LibraryCall), | 
|  | TLI->getPointerTy(getDataLayout())), | 
|  | std::move(Args)) | 
|  | .setDiscardResult() | 
|  | .setTailCall(isTailCall); | 
|  |  | 
|  | std::pair<SDValue, SDValue> CallResult = TLI->LowerCallTo(CLI); | 
|  | return CallResult.second; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getMemset(SDValue Chain, const SDLoc &dl, SDValue Dst, | 
|  | SDValue Src, SDValue Size, Align Alignment, | 
|  | bool isVol, bool AlwaysInline, | 
|  | const CallInst *CI, | 
|  | MachinePointerInfo DstPtrInfo, | 
|  | const AAMDNodes &AAInfo) { | 
|  | // Check to see if we should lower the memset to stores first. | 
|  | // For cases within the target-specified limits, this is the best choice. | 
|  | ConstantSDNode *ConstantSize = dyn_cast<ConstantSDNode>(Size); | 
|  | if (ConstantSize) { | 
|  | // Memset with size zero? Just return the original chain. | 
|  | if (ConstantSize->isZero()) | 
|  | return Chain; | 
|  |  | 
|  | SDValue Result = getMemsetStores(*this, dl, Chain, Dst, Src, | 
|  | ConstantSize->getZExtValue(), Alignment, | 
|  | isVol, false, DstPtrInfo, AAInfo); | 
|  |  | 
|  | if (Result.getNode()) | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | // Then check to see if we should lower the memset with target-specific | 
|  | // code. If the target chooses to do this, this is the next best. | 
|  | if (TSI) { | 
|  | SDValue Result = TSI->EmitTargetCodeForMemset( | 
|  | *this, dl, Chain, Dst, Src, Size, Alignment, isVol, AlwaysInline, DstPtrInfo); | 
|  | if (Result.getNode()) | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | // If we really need inline code and the target declined to provide it, | 
|  | // use a (potentially long) sequence of loads and stores. | 
|  | if (AlwaysInline) { | 
|  | assert(ConstantSize && "AlwaysInline requires a constant size!"); | 
|  | SDValue Result = getMemsetStores(*this, dl, Chain, Dst, Src, | 
|  | ConstantSize->getZExtValue(), Alignment, | 
|  | isVol, true, DstPtrInfo, AAInfo); | 
|  | assert(Result && | 
|  | "getMemsetStores must return a valid sequence when AlwaysInline"); | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | checkAddrSpaceIsValidForLibcall(TLI, DstPtrInfo.getAddrSpace()); | 
|  |  | 
|  | // Emit a library call. | 
|  | auto &Ctx = *getContext(); | 
|  | const auto& DL = getDataLayout(); | 
|  |  | 
|  | TargetLowering::CallLoweringInfo CLI(*this); | 
|  | // FIXME: pass in SDLoc | 
|  | CLI.setDebugLoc(dl).setChain(Chain); | 
|  |  | 
|  | const char *BzeroName = getTargetLoweringInfo().getLibcallName(RTLIB::BZERO); | 
|  |  | 
|  | bool UseBZero = isNullConstant(Src) && BzeroName; | 
|  | // If zeroing out and bzero is present, use it. | 
|  | if (UseBZero) { | 
|  | TargetLowering::ArgListTy Args; | 
|  | Args.emplace_back(Dst, PointerType::getUnqual(Ctx)); | 
|  | Args.emplace_back(Size, DL.getIntPtrType(Ctx)); | 
|  | CLI.setLibCallee( | 
|  | TLI->getLibcallCallingConv(RTLIB::BZERO), Type::getVoidTy(Ctx), | 
|  | getExternalSymbol(BzeroName, TLI->getPointerTy(DL)), std::move(Args)); | 
|  | } else { | 
|  | TargetLowering::ArgListTy Args; | 
|  | Args.emplace_back(Dst, PointerType::getUnqual(Ctx)); | 
|  | Args.emplace_back(Src, Src.getValueType().getTypeForEVT(Ctx)); | 
|  | Args.emplace_back(Size, DL.getIntPtrType(Ctx)); | 
|  | CLI.setLibCallee(TLI->getLibcallCallingConv(RTLIB::MEMSET), | 
|  | Dst.getValueType().getTypeForEVT(Ctx), | 
|  | getExternalSymbol(TLI->getLibcallName(RTLIB::MEMSET), | 
|  | TLI->getPointerTy(DL)), | 
|  | std::move(Args)); | 
|  | } | 
|  | bool LowersToMemset = | 
|  | TLI->getLibcallName(RTLIB::MEMSET) == StringRef("memset"); | 
|  | // If we're going to use bzero, make sure not to tail call unless the | 
|  | // subsequent return doesn't need a value, as bzero doesn't return the first | 
|  | // arg unlike memset. | 
|  | bool ReturnsFirstArg = CI && funcReturnsFirstArgOfCall(*CI) && !UseBZero; | 
|  | bool IsTailCall = | 
|  | CI && CI->isTailCall() && | 
|  | isInTailCallPosition(*CI, getTarget(), ReturnsFirstArg && LowersToMemset); | 
|  | CLI.setDiscardResult().setTailCall(IsTailCall); | 
|  |  | 
|  | std::pair<SDValue, SDValue> CallResult = TLI->LowerCallTo(CLI); | 
|  | return CallResult.second; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getAtomicMemset(SDValue Chain, const SDLoc &dl, | 
|  | SDValue Dst, SDValue Value, SDValue Size, | 
|  | Type *SizeTy, unsigned ElemSz, | 
|  | bool isTailCall, | 
|  | MachinePointerInfo DstPtrInfo) { | 
|  | // Emit a library call. | 
|  | TargetLowering::ArgListTy Args; | 
|  | Args.emplace_back(Dst, getDataLayout().getIntPtrType(*getContext())); | 
|  | Args.emplace_back(Value, Type::getInt8Ty(*getContext())); | 
|  | Args.emplace_back(Size, SizeTy); | 
|  |  | 
|  | RTLIB::Libcall LibraryCall = | 
|  | RTLIB::getMEMSET_ELEMENT_UNORDERED_ATOMIC(ElemSz); | 
|  | if (LibraryCall == RTLIB::UNKNOWN_LIBCALL) | 
|  | report_fatal_error("Unsupported element size"); | 
|  |  | 
|  | TargetLowering::CallLoweringInfo CLI(*this); | 
|  | CLI.setDebugLoc(dl) | 
|  | .setChain(Chain) | 
|  | .setLibCallee(TLI->getLibcallCallingConv(LibraryCall), | 
|  | Type::getVoidTy(*getContext()), | 
|  | getExternalSymbol(TLI->getLibcallName(LibraryCall), | 
|  | TLI->getPointerTy(getDataLayout())), | 
|  | std::move(Args)) | 
|  | .setDiscardResult() | 
|  | .setTailCall(isTailCall); | 
|  |  | 
|  | std::pair<SDValue, SDValue> CallResult = TLI->LowerCallTo(CLI); | 
|  | return CallResult.second; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getAtomic(unsigned Opcode, const SDLoc &dl, EVT MemVT, | 
|  | SDVTList VTList, ArrayRef<SDValue> Ops, | 
|  | MachineMemOperand *MMO, | 
|  | ISD::LoadExtType ExtType) { | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, Opcode, VTList, Ops); | 
|  | ID.AddInteger(MemVT.getRawBits()); | 
|  | ID.AddInteger(getSyntheticNodeSubclassData<AtomicSDNode>( | 
|  | dl.getIROrder(), Opcode, VTList, MemVT, MMO, ExtType)); | 
|  | ID.AddInteger(MMO->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(MMO->getFlags()); | 
|  | void* IP = nullptr; | 
|  | if (auto *E = cast_or_null<AtomicSDNode>(FindNodeOrInsertPos(ID, dl, IP))) { | 
|  | E->refineAlignment(MMO); | 
|  | E->refineRanges(MMO); | 
|  | return SDValue(E, 0); | 
|  | } | 
|  |  | 
|  | auto *N = newSDNode<AtomicSDNode>(dl.getIROrder(), dl.getDebugLoc(), Opcode, | 
|  | VTList, MemVT, MMO, ExtType); | 
|  | createOperands(N, Ops); | 
|  |  | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | SDValue V(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getAtomicCmpSwap(unsigned Opcode, const SDLoc &dl, | 
|  | EVT MemVT, SDVTList VTs, SDValue Chain, | 
|  | SDValue Ptr, SDValue Cmp, SDValue Swp, | 
|  | MachineMemOperand *MMO) { | 
|  | assert(Opcode == ISD::ATOMIC_CMP_SWAP || | 
|  | Opcode == ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS); | 
|  | assert(Cmp.getValueType() == Swp.getValueType() && "Invalid Atomic Op Types"); | 
|  |  | 
|  | SDValue Ops[] = {Chain, Ptr, Cmp, Swp}; | 
|  | return getAtomic(Opcode, dl, MemVT, VTs, Ops, MMO); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getAtomic(unsigned Opcode, const SDLoc &dl, EVT MemVT, | 
|  | SDValue Chain, SDValue Ptr, SDValue Val, | 
|  | MachineMemOperand *MMO) { | 
|  | assert((Opcode == ISD::ATOMIC_LOAD_ADD || Opcode == ISD::ATOMIC_LOAD_SUB || | 
|  | Opcode == ISD::ATOMIC_LOAD_AND || Opcode == ISD::ATOMIC_LOAD_CLR || | 
|  | Opcode == ISD::ATOMIC_LOAD_OR || Opcode == ISD::ATOMIC_LOAD_XOR || | 
|  | Opcode == ISD::ATOMIC_LOAD_NAND || Opcode == ISD::ATOMIC_LOAD_MIN || | 
|  | Opcode == ISD::ATOMIC_LOAD_MAX || Opcode == ISD::ATOMIC_LOAD_UMIN || | 
|  | Opcode == ISD::ATOMIC_LOAD_UMAX || Opcode == ISD::ATOMIC_LOAD_FADD || | 
|  | Opcode == ISD::ATOMIC_LOAD_FSUB || Opcode == ISD::ATOMIC_LOAD_FMAX || | 
|  | Opcode == ISD::ATOMIC_LOAD_FMIN || | 
|  | Opcode == ISD::ATOMIC_LOAD_FMINIMUM || | 
|  | Opcode == ISD::ATOMIC_LOAD_FMAXIMUM || | 
|  | Opcode == ISD::ATOMIC_LOAD_UINC_WRAP || | 
|  | Opcode == ISD::ATOMIC_LOAD_UDEC_WRAP || | 
|  | Opcode == ISD::ATOMIC_LOAD_USUB_COND || | 
|  | Opcode == ISD::ATOMIC_LOAD_USUB_SAT || Opcode == ISD::ATOMIC_SWAP || | 
|  | Opcode == ISD::ATOMIC_STORE) && | 
|  | "Invalid Atomic Op"); | 
|  |  | 
|  | EVT VT = Val.getValueType(); | 
|  |  | 
|  | SDVTList VTs = Opcode == ISD::ATOMIC_STORE ? getVTList(MVT::Other) : | 
|  | getVTList(VT, MVT::Other); | 
|  | SDValue Ops[] = {Chain, Ptr, Val}; | 
|  | return getAtomic(Opcode, dl, MemVT, VTs, Ops, MMO); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getAtomicLoad(ISD::LoadExtType ExtType, const SDLoc &dl, | 
|  | EVT MemVT, EVT VT, SDValue Chain, | 
|  | SDValue Ptr, MachineMemOperand *MMO) { | 
|  | SDVTList VTs = getVTList(VT, MVT::Other); | 
|  | SDValue Ops[] = {Chain, Ptr}; | 
|  | return getAtomic(ISD::ATOMIC_LOAD, dl, MemVT, VTs, Ops, MMO, ExtType); | 
|  | } | 
|  |  | 
|  | /// getMergeValues - Create a MERGE_VALUES node from the given operands. | 
|  | SDValue SelectionDAG::getMergeValues(ArrayRef<SDValue> Ops, const SDLoc &dl) { | 
|  | if (Ops.size() == 1) | 
|  | return Ops[0]; | 
|  |  | 
|  | SmallVector<EVT, 4> VTs; | 
|  | VTs.reserve(Ops.size()); | 
|  | for (const SDValue &Op : Ops) | 
|  | VTs.push_back(Op.getValueType()); | 
|  | return getNode(ISD::MERGE_VALUES, dl, getVTList(VTs), Ops); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getMemIntrinsicNode( | 
|  | unsigned Opcode, const SDLoc &dl, SDVTList VTList, ArrayRef<SDValue> Ops, | 
|  | EVT MemVT, MachinePointerInfo PtrInfo, Align Alignment, | 
|  | MachineMemOperand::Flags Flags, LocationSize Size, | 
|  | const AAMDNodes &AAInfo) { | 
|  | if (Size.hasValue() && !Size.getValue()) | 
|  | Size = LocationSize::precise(MemVT.getStoreSize()); | 
|  |  | 
|  | MachineFunction &MF = getMachineFunction(); | 
|  | MachineMemOperand *MMO = | 
|  | MF.getMachineMemOperand(PtrInfo, Flags, Size, Alignment, AAInfo); | 
|  |  | 
|  | return getMemIntrinsicNode(Opcode, dl, VTList, Ops, MemVT, MMO); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getMemIntrinsicNode(unsigned Opcode, const SDLoc &dl, | 
|  | SDVTList VTList, | 
|  | ArrayRef<SDValue> Ops, EVT MemVT, | 
|  | MachineMemOperand *MMO) { | 
|  | assert( | 
|  | (Opcode == ISD::INTRINSIC_VOID || Opcode == ISD::INTRINSIC_W_CHAIN || | 
|  | Opcode == ISD::PREFETCH || | 
|  | (Opcode <= (unsigned)std::numeric_limits<int>::max() && | 
|  | Opcode >= ISD::BUILTIN_OP_END && TSI->isTargetMemoryOpcode(Opcode))) && | 
|  | "Opcode is not a memory-accessing opcode!"); | 
|  |  | 
|  | // Memoize the node unless it returns a glue result. | 
|  | MemIntrinsicSDNode *N; | 
|  | if (VTList.VTs[VTList.NumVTs-1] != MVT::Glue) { | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, Opcode, VTList, Ops); | 
|  | ID.AddInteger(getSyntheticNodeSubclassData<MemIntrinsicSDNode>( | 
|  | Opcode, dl.getIROrder(), VTList, MemVT, MMO)); | 
|  | ID.AddInteger(MMO->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(MMO->getFlags()); | 
|  | ID.AddInteger(MemVT.getRawBits()); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, dl, IP)) { | 
|  | cast<MemIntrinsicSDNode>(E)->refineAlignment(MMO); | 
|  | return SDValue(E, 0); | 
|  | } | 
|  |  | 
|  | N = newSDNode<MemIntrinsicSDNode>(Opcode, dl.getIROrder(), dl.getDebugLoc(), | 
|  | VTList, MemVT, MMO); | 
|  | createOperands(N, Ops); | 
|  |  | 
|  | CSEMap.InsertNode(N, IP); | 
|  | } else { | 
|  | N = newSDNode<MemIntrinsicSDNode>(Opcode, dl.getIROrder(), dl.getDebugLoc(), | 
|  | VTList, MemVT, MMO); | 
|  | createOperands(N, Ops); | 
|  | } | 
|  | InsertNode(N); | 
|  | SDValue V(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getLifetimeNode(bool IsStart, const SDLoc &dl, | 
|  | SDValue Chain, int FrameIndex) { | 
|  | const unsigned Opcode = IsStart ? ISD::LIFETIME_START : ISD::LIFETIME_END; | 
|  | const auto VTs = getVTList(MVT::Other); | 
|  | SDValue Ops[2] = { | 
|  | Chain, | 
|  | getFrameIndex(FrameIndex, | 
|  | getTargetLoweringInfo().getFrameIndexTy(getDataLayout()), | 
|  | true)}; | 
|  |  | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, Opcode, VTs, Ops); | 
|  | ID.AddInteger(FrameIndex); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, dl, IP)) | 
|  | return SDValue(E, 0); | 
|  |  | 
|  | LifetimeSDNode *N = | 
|  | newSDNode<LifetimeSDNode>(Opcode, dl.getIROrder(), dl.getDebugLoc(), VTs); | 
|  | createOperands(N, Ops); | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | SDValue V(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getPseudoProbeNode(const SDLoc &Dl, SDValue Chain, | 
|  | uint64_t Guid, uint64_t Index, | 
|  | uint32_t Attr) { | 
|  | const unsigned Opcode = ISD::PSEUDO_PROBE; | 
|  | const auto VTs = getVTList(MVT::Other); | 
|  | SDValue Ops[] = {Chain}; | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, Opcode, VTs, Ops); | 
|  | ID.AddInteger(Guid); | 
|  | ID.AddInteger(Index); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, Dl, IP)) | 
|  | return SDValue(E, 0); | 
|  |  | 
|  | auto *N = newSDNode<PseudoProbeSDNode>( | 
|  | Opcode, Dl.getIROrder(), Dl.getDebugLoc(), VTs, Guid, Index, Attr); | 
|  | createOperands(N, Ops); | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | SDValue V(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | /// InferPointerInfo - If the specified ptr/offset is a frame index, infer a | 
|  | /// MachinePointerInfo record from it.  This is particularly useful because the | 
|  | /// code generator has many cases where it doesn't bother passing in a | 
|  | /// MachinePointerInfo to getLoad or getStore when it has "FI+Cst". | 
|  | static MachinePointerInfo InferPointerInfo(const MachinePointerInfo &Info, | 
|  | SelectionDAG &DAG, SDValue Ptr, | 
|  | int64_t Offset = 0) { | 
|  | // If this is FI+Offset, we can model it. | 
|  | if (const FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(Ptr)) | 
|  | return MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), | 
|  | FI->getIndex(), Offset); | 
|  |  | 
|  | // If this is (FI+Offset1)+Offset2, we can model it. | 
|  | if (Ptr.getOpcode() != ISD::ADD || | 
|  | !isa<ConstantSDNode>(Ptr.getOperand(1)) || | 
|  | !isa<FrameIndexSDNode>(Ptr.getOperand(0))) | 
|  | return Info; | 
|  |  | 
|  | int FI = cast<FrameIndexSDNode>(Ptr.getOperand(0))->getIndex(); | 
|  | return MachinePointerInfo::getFixedStack( | 
|  | DAG.getMachineFunction(), FI, | 
|  | Offset + cast<ConstantSDNode>(Ptr.getOperand(1))->getSExtValue()); | 
|  | } | 
|  |  | 
|  | /// InferPointerInfo - If the specified ptr/offset is a frame index, infer a | 
|  | /// MachinePointerInfo record from it.  This is particularly useful because the | 
|  | /// code generator has many cases where it doesn't bother passing in a | 
|  | /// MachinePointerInfo to getLoad or getStore when it has "FI+Cst". | 
|  | static MachinePointerInfo InferPointerInfo(const MachinePointerInfo &Info, | 
|  | SelectionDAG &DAG, SDValue Ptr, | 
|  | SDValue OffsetOp) { | 
|  | // If the 'Offset' value isn't a constant, we can't handle this. | 
|  | if (ConstantSDNode *OffsetNode = dyn_cast<ConstantSDNode>(OffsetOp)) | 
|  | return InferPointerInfo(Info, DAG, Ptr, OffsetNode->getSExtValue()); | 
|  | if (OffsetOp.isUndef()) | 
|  | return InferPointerInfo(Info, DAG, Ptr); | 
|  | return Info; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getLoad(ISD::MemIndexedMode AM, ISD::LoadExtType ExtType, | 
|  | EVT VT, const SDLoc &dl, SDValue Chain, | 
|  | SDValue Ptr, SDValue Offset, | 
|  | MachinePointerInfo PtrInfo, EVT MemVT, | 
|  | Align Alignment, | 
|  | MachineMemOperand::Flags MMOFlags, | 
|  | const AAMDNodes &AAInfo, const MDNode *Ranges) { | 
|  | assert(Chain.getValueType() == MVT::Other && | 
|  | "Invalid chain type"); | 
|  |  | 
|  | MMOFlags |= MachineMemOperand::MOLoad; | 
|  | assert((MMOFlags & MachineMemOperand::MOStore) == 0); | 
|  | // If we don't have a PtrInfo, infer the trivial frame index case to simplify | 
|  | // clients. | 
|  | if (PtrInfo.V.isNull()) | 
|  | PtrInfo = InferPointerInfo(PtrInfo, *this, Ptr, Offset); | 
|  |  | 
|  | TypeSize Size = MemVT.getStoreSize(); | 
|  | MachineFunction &MF = getMachineFunction(); | 
|  | MachineMemOperand *MMO = MF.getMachineMemOperand(PtrInfo, MMOFlags, Size, | 
|  | Alignment, AAInfo, Ranges); | 
|  | return getLoad(AM, ExtType, VT, dl, Chain, Ptr, Offset, MemVT, MMO); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getLoad(ISD::MemIndexedMode AM, ISD::LoadExtType ExtType, | 
|  | EVT VT, const SDLoc &dl, SDValue Chain, | 
|  | SDValue Ptr, SDValue Offset, EVT MemVT, | 
|  | MachineMemOperand *MMO) { | 
|  | if (VT == MemVT) { | 
|  | ExtType = ISD::NON_EXTLOAD; | 
|  | } else if (ExtType == ISD::NON_EXTLOAD) { | 
|  | assert(VT == MemVT && "Non-extending load from different memory type!"); | 
|  | } else { | 
|  | // Extending load. | 
|  | assert(MemVT.getScalarType().bitsLT(VT.getScalarType()) && | 
|  | "Should only be an extending load, not truncating!"); | 
|  | assert(VT.isInteger() == MemVT.isInteger() && | 
|  | "Cannot convert from FP to Int or Int -> FP!"); | 
|  | assert(VT.isVector() == MemVT.isVector() && | 
|  | "Cannot use an ext load to convert to or from a vector!"); | 
|  | assert((!VT.isVector() || | 
|  | VT.getVectorElementCount() == MemVT.getVectorElementCount()) && | 
|  | "Cannot use an ext load to change the number of vector elements!"); | 
|  | } | 
|  |  | 
|  | assert((!MMO->getRanges() || | 
|  | (mdconst::extract<ConstantInt>(MMO->getRanges()->getOperand(0)) | 
|  | ->getBitWidth() == MemVT.getScalarSizeInBits() && | 
|  | MemVT.isInteger())) && | 
|  | "Range metadata and load type must match!"); | 
|  |  | 
|  | bool Indexed = AM != ISD::UNINDEXED; | 
|  | assert((Indexed || Offset.isUndef()) && "Unindexed load with an offset!"); | 
|  |  | 
|  | SDVTList VTs = Indexed ? | 
|  | getVTList(VT, Ptr.getValueType(), MVT::Other) : getVTList(VT, MVT::Other); | 
|  | SDValue Ops[] = { Chain, Ptr, Offset }; | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, ISD::LOAD, VTs, Ops); | 
|  | ID.AddInteger(MemVT.getRawBits()); | 
|  | ID.AddInteger(getSyntheticNodeSubclassData<LoadSDNode>( | 
|  | dl.getIROrder(), VTs, AM, ExtType, MemVT, MMO)); | 
|  | ID.AddInteger(MMO->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(MMO->getFlags()); | 
|  | void *IP = nullptr; | 
|  | if (auto *E = cast_or_null<LoadSDNode>(FindNodeOrInsertPos(ID, dl, IP))) { | 
|  | E->refineAlignment(MMO); | 
|  | E->refineRanges(MMO); | 
|  | return SDValue(E, 0); | 
|  | } | 
|  | auto *N = newSDNode<LoadSDNode>(dl.getIROrder(), dl.getDebugLoc(), VTs, AM, | 
|  | ExtType, MemVT, MMO); | 
|  | createOperands(N, Ops); | 
|  |  | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | SDValue V(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getLoad(EVT VT, const SDLoc &dl, SDValue Chain, | 
|  | SDValue Ptr, MachinePointerInfo PtrInfo, | 
|  | MaybeAlign Alignment, | 
|  | MachineMemOperand::Flags MMOFlags, | 
|  | const AAMDNodes &AAInfo, const MDNode *Ranges) { | 
|  | SDValue Undef = getUNDEF(Ptr.getValueType()); | 
|  | return getLoad(ISD::UNINDEXED, ISD::NON_EXTLOAD, VT, dl, Chain, Ptr, Undef, | 
|  | PtrInfo, VT, Alignment, MMOFlags, AAInfo, Ranges); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getLoad(EVT VT, const SDLoc &dl, SDValue Chain, | 
|  | SDValue Ptr, MachineMemOperand *MMO) { | 
|  | SDValue Undef = getUNDEF(Ptr.getValueType()); | 
|  | return getLoad(ISD::UNINDEXED, ISD::NON_EXTLOAD, VT, dl, Chain, Ptr, Undef, | 
|  | VT, MMO); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getExtLoad(ISD::LoadExtType ExtType, const SDLoc &dl, | 
|  | EVT VT, SDValue Chain, SDValue Ptr, | 
|  | MachinePointerInfo PtrInfo, EVT MemVT, | 
|  | MaybeAlign Alignment, | 
|  | MachineMemOperand::Flags MMOFlags, | 
|  | const AAMDNodes &AAInfo) { | 
|  | SDValue Undef = getUNDEF(Ptr.getValueType()); | 
|  | return getLoad(ISD::UNINDEXED, ExtType, VT, dl, Chain, Ptr, Undef, PtrInfo, | 
|  | MemVT, Alignment, MMOFlags, AAInfo); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getExtLoad(ISD::LoadExtType ExtType, const SDLoc &dl, | 
|  | EVT VT, SDValue Chain, SDValue Ptr, EVT MemVT, | 
|  | MachineMemOperand *MMO) { | 
|  | SDValue Undef = getUNDEF(Ptr.getValueType()); | 
|  | return getLoad(ISD::UNINDEXED, ExtType, VT, dl, Chain, Ptr, Undef, | 
|  | MemVT, MMO); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getIndexedLoad(SDValue OrigLoad, const SDLoc &dl, | 
|  | SDValue Base, SDValue Offset, | 
|  | ISD::MemIndexedMode AM) { | 
|  | LoadSDNode *LD = cast<LoadSDNode>(OrigLoad); | 
|  | assert(LD->getOffset().isUndef() && "Load is already a indexed load!"); | 
|  | // Don't propagate the invariant or dereferenceable flags. | 
|  | auto MMOFlags = | 
|  | LD->getMemOperand()->getFlags() & | 
|  | ~(MachineMemOperand::MOInvariant | MachineMemOperand::MODereferenceable); | 
|  | return getLoad(AM, LD->getExtensionType(), OrigLoad.getValueType(), dl, | 
|  | LD->getChain(), Base, Offset, LD->getPointerInfo(), | 
|  | LD->getMemoryVT(), LD->getAlign(), MMOFlags, LD->getAAInfo()); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getStore(SDValue Chain, const SDLoc &dl, SDValue Val, | 
|  | SDValue Ptr, MachinePointerInfo PtrInfo, | 
|  | Align Alignment, | 
|  | MachineMemOperand::Flags MMOFlags, | 
|  | const AAMDNodes &AAInfo) { | 
|  | assert(Chain.getValueType() == MVT::Other && "Invalid chain type"); | 
|  |  | 
|  | MMOFlags |= MachineMemOperand::MOStore; | 
|  | assert((MMOFlags & MachineMemOperand::MOLoad) == 0); | 
|  |  | 
|  | if (PtrInfo.V.isNull()) | 
|  | PtrInfo = InferPointerInfo(PtrInfo, *this, Ptr); | 
|  |  | 
|  | MachineFunction &MF = getMachineFunction(); | 
|  | TypeSize Size = Val.getValueType().getStoreSize(); | 
|  | MachineMemOperand *MMO = | 
|  | MF.getMachineMemOperand(PtrInfo, MMOFlags, Size, Alignment, AAInfo); | 
|  | return getStore(Chain, dl, Val, Ptr, MMO); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getStore(SDValue Chain, const SDLoc &dl, SDValue Val, | 
|  | SDValue Ptr, MachineMemOperand *MMO) { | 
|  | SDValue Undef = getUNDEF(Ptr.getValueType()); | 
|  | return getStore(Chain, dl, Val, Ptr, Undef, Val.getValueType(), MMO, | 
|  | ISD::UNINDEXED); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getStore(SDValue Chain, const SDLoc &dl, SDValue Val, | 
|  | SDValue Ptr, SDValue Offset, EVT SVT, | 
|  | MachineMemOperand *MMO, ISD::MemIndexedMode AM, | 
|  | bool IsTruncating) { | 
|  | assert(Chain.getValueType() == MVT::Other && "Invalid chain type"); | 
|  | EVT VT = Val.getValueType(); | 
|  | if (VT == SVT) { | 
|  | IsTruncating = false; | 
|  | } else if (!IsTruncating) { | 
|  | assert(VT == SVT && "No-truncating store from different memory type!"); | 
|  | } else { | 
|  | assert(SVT.getScalarType().bitsLT(VT.getScalarType()) && | 
|  | "Should only be a truncating store, not extending!"); | 
|  | assert(VT.isInteger() == SVT.isInteger() && "Can't do FP-INT conversion!"); | 
|  | assert(VT.isVector() == SVT.isVector() && | 
|  | "Cannot use trunc store to convert to or from a vector!"); | 
|  | assert((!VT.isVector() || | 
|  | VT.getVectorElementCount() == SVT.getVectorElementCount()) && | 
|  | "Cannot use trunc store to change the number of vector elements!"); | 
|  | } | 
|  |  | 
|  | bool Indexed = AM != ISD::UNINDEXED; | 
|  | assert((Indexed || Offset.isUndef()) && "Unindexed store with an offset!"); | 
|  | SDVTList VTs = Indexed ? getVTList(Ptr.getValueType(), MVT::Other) | 
|  | : getVTList(MVT::Other); | 
|  | SDValue Ops[] = {Chain, Val, Ptr, Offset}; | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, ISD::STORE, VTs, Ops); | 
|  | ID.AddInteger(SVT.getRawBits()); | 
|  | ID.AddInteger(getSyntheticNodeSubclassData<StoreSDNode>( | 
|  | dl.getIROrder(), VTs, AM, IsTruncating, SVT, MMO)); | 
|  | ID.AddInteger(MMO->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(MMO->getFlags()); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, dl, IP)) { | 
|  | cast<StoreSDNode>(E)->refineAlignment(MMO); | 
|  | return SDValue(E, 0); | 
|  | } | 
|  | auto *N = newSDNode<StoreSDNode>(dl.getIROrder(), dl.getDebugLoc(), VTs, AM, | 
|  | IsTruncating, SVT, MMO); | 
|  | createOperands(N, Ops); | 
|  |  | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | SDValue V(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getTruncStore(SDValue Chain, const SDLoc &dl, SDValue Val, | 
|  | SDValue Ptr, MachinePointerInfo PtrInfo, | 
|  | EVT SVT, Align Alignment, | 
|  | MachineMemOperand::Flags MMOFlags, | 
|  | const AAMDNodes &AAInfo) { | 
|  | assert(Chain.getValueType() == MVT::Other && | 
|  | "Invalid chain type"); | 
|  |  | 
|  | MMOFlags |= MachineMemOperand::MOStore; | 
|  | assert((MMOFlags & MachineMemOperand::MOLoad) == 0); | 
|  |  | 
|  | if (PtrInfo.V.isNull()) | 
|  | PtrInfo = InferPointerInfo(PtrInfo, *this, Ptr); | 
|  |  | 
|  | MachineFunction &MF = getMachineFunction(); | 
|  | MachineMemOperand *MMO = MF.getMachineMemOperand( | 
|  | PtrInfo, MMOFlags, SVT.getStoreSize(), Alignment, AAInfo); | 
|  | return getTruncStore(Chain, dl, Val, Ptr, SVT, MMO); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getTruncStore(SDValue Chain, const SDLoc &dl, SDValue Val, | 
|  | SDValue Ptr, EVT SVT, | 
|  | MachineMemOperand *MMO) { | 
|  | SDValue Undef = getUNDEF(Ptr.getValueType()); | 
|  | return getStore(Chain, dl, Val, Ptr, Undef, SVT, MMO, ISD::UNINDEXED, true); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getIndexedStore(SDValue OrigStore, const SDLoc &dl, | 
|  | SDValue Base, SDValue Offset, | 
|  | ISD::MemIndexedMode AM) { | 
|  | StoreSDNode *ST = cast<StoreSDNode>(OrigStore); | 
|  | assert(ST->getOffset().isUndef() && "Store is already a indexed store!"); | 
|  | return getStore(ST->getChain(), dl, ST->getValue(), Base, Offset, | 
|  | ST->getMemoryVT(), ST->getMemOperand(), AM, | 
|  | ST->isTruncatingStore()); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getLoadVP( | 
|  | ISD::MemIndexedMode AM, ISD::LoadExtType ExtType, EVT VT, const SDLoc &dl, | 
|  | SDValue Chain, SDValue Ptr, SDValue Offset, SDValue Mask, SDValue EVL, | 
|  | MachinePointerInfo PtrInfo, EVT MemVT, Align Alignment, | 
|  | MachineMemOperand::Flags MMOFlags, const AAMDNodes &AAInfo, | 
|  | const MDNode *Ranges, bool IsExpanding) { | 
|  | assert(Chain.getValueType() == MVT::Other && "Invalid chain type"); | 
|  |  | 
|  | MMOFlags |= MachineMemOperand::MOLoad; | 
|  | assert((MMOFlags & MachineMemOperand::MOStore) == 0); | 
|  | // If we don't have a PtrInfo, infer the trivial frame index case to simplify | 
|  | // clients. | 
|  | if (PtrInfo.V.isNull()) | 
|  | PtrInfo = InferPointerInfo(PtrInfo, *this, Ptr, Offset); | 
|  |  | 
|  | TypeSize Size = MemVT.getStoreSize(); | 
|  | MachineFunction &MF = getMachineFunction(); | 
|  | MachineMemOperand *MMO = MF.getMachineMemOperand(PtrInfo, MMOFlags, Size, | 
|  | Alignment, AAInfo, Ranges); | 
|  | return getLoadVP(AM, ExtType, VT, dl, Chain, Ptr, Offset, Mask, EVL, MemVT, | 
|  | MMO, IsExpanding); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getLoadVP(ISD::MemIndexedMode AM, | 
|  | ISD::LoadExtType ExtType, EVT VT, | 
|  | const SDLoc &dl, SDValue Chain, SDValue Ptr, | 
|  | SDValue Offset, SDValue Mask, SDValue EVL, | 
|  | EVT MemVT, MachineMemOperand *MMO, | 
|  | bool IsExpanding) { | 
|  | bool Indexed = AM != ISD::UNINDEXED; | 
|  | assert((Indexed || Offset.isUndef()) && "Unindexed load with an offset!"); | 
|  |  | 
|  | SDVTList VTs = Indexed ? getVTList(VT, Ptr.getValueType(), MVT::Other) | 
|  | : getVTList(VT, MVT::Other); | 
|  | SDValue Ops[] = {Chain, Ptr, Offset, Mask, EVL}; | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, ISD::VP_LOAD, VTs, Ops); | 
|  | ID.AddInteger(MemVT.getRawBits()); | 
|  | ID.AddInteger(getSyntheticNodeSubclassData<VPLoadSDNode>( | 
|  | dl.getIROrder(), VTs, AM, ExtType, IsExpanding, MemVT, MMO)); | 
|  | ID.AddInteger(MMO->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(MMO->getFlags()); | 
|  | void *IP = nullptr; | 
|  | if (auto *E = cast_or_null<VPLoadSDNode>(FindNodeOrInsertPos(ID, dl, IP))) { | 
|  | E->refineAlignment(MMO); | 
|  | E->refineRanges(MMO); | 
|  | return SDValue(E, 0); | 
|  | } | 
|  | auto *N = newSDNode<VPLoadSDNode>(dl.getIROrder(), dl.getDebugLoc(), VTs, AM, | 
|  | ExtType, IsExpanding, MemVT, MMO); | 
|  | createOperands(N, Ops); | 
|  |  | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | SDValue V(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getLoadVP(EVT VT, const SDLoc &dl, SDValue Chain, | 
|  | SDValue Ptr, SDValue Mask, SDValue EVL, | 
|  | MachinePointerInfo PtrInfo, | 
|  | MaybeAlign Alignment, | 
|  | MachineMemOperand::Flags MMOFlags, | 
|  | const AAMDNodes &AAInfo, const MDNode *Ranges, | 
|  | bool IsExpanding) { | 
|  | SDValue Undef = getUNDEF(Ptr.getValueType()); | 
|  | return getLoadVP(ISD::UNINDEXED, ISD::NON_EXTLOAD, VT, dl, Chain, Ptr, Undef, | 
|  | Mask, EVL, PtrInfo, VT, Alignment, MMOFlags, AAInfo, Ranges, | 
|  | IsExpanding); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getLoadVP(EVT VT, const SDLoc &dl, SDValue Chain, | 
|  | SDValue Ptr, SDValue Mask, SDValue EVL, | 
|  | MachineMemOperand *MMO, bool IsExpanding) { | 
|  | SDValue Undef = getUNDEF(Ptr.getValueType()); | 
|  | return getLoadVP(ISD::UNINDEXED, ISD::NON_EXTLOAD, VT, dl, Chain, Ptr, Undef, | 
|  | Mask, EVL, VT, MMO, IsExpanding); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getExtLoadVP(ISD::LoadExtType ExtType, const SDLoc &dl, | 
|  | EVT VT, SDValue Chain, SDValue Ptr, | 
|  | SDValue Mask, SDValue EVL, | 
|  | MachinePointerInfo PtrInfo, EVT MemVT, | 
|  | MaybeAlign Alignment, | 
|  | MachineMemOperand::Flags MMOFlags, | 
|  | const AAMDNodes &AAInfo, bool IsExpanding) { | 
|  | SDValue Undef = getUNDEF(Ptr.getValueType()); | 
|  | return getLoadVP(ISD::UNINDEXED, ExtType, VT, dl, Chain, Ptr, Undef, Mask, | 
|  | EVL, PtrInfo, MemVT, Alignment, MMOFlags, AAInfo, nullptr, | 
|  | IsExpanding); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getExtLoadVP(ISD::LoadExtType ExtType, const SDLoc &dl, | 
|  | EVT VT, SDValue Chain, SDValue Ptr, | 
|  | SDValue Mask, SDValue EVL, EVT MemVT, | 
|  | MachineMemOperand *MMO, bool IsExpanding) { | 
|  | SDValue Undef = getUNDEF(Ptr.getValueType()); | 
|  | return getLoadVP(ISD::UNINDEXED, ExtType, VT, dl, Chain, Ptr, Undef, Mask, | 
|  | EVL, MemVT, MMO, IsExpanding); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getIndexedLoadVP(SDValue OrigLoad, const SDLoc &dl, | 
|  | SDValue Base, SDValue Offset, | 
|  | ISD::MemIndexedMode AM) { | 
|  | auto *LD = cast<VPLoadSDNode>(OrigLoad); | 
|  | assert(LD->getOffset().isUndef() && "Load is already a indexed load!"); | 
|  | // Don't propagate the invariant or dereferenceable flags. | 
|  | auto MMOFlags = | 
|  | LD->getMemOperand()->getFlags() & | 
|  | ~(MachineMemOperand::MOInvariant | MachineMemOperand::MODereferenceable); | 
|  | return getLoadVP(AM, LD->getExtensionType(), OrigLoad.getValueType(), dl, | 
|  | LD->getChain(), Base, Offset, LD->getMask(), | 
|  | LD->getVectorLength(), LD->getPointerInfo(), | 
|  | LD->getMemoryVT(), LD->getAlign(), MMOFlags, LD->getAAInfo(), | 
|  | nullptr, LD->isExpandingLoad()); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getStoreVP(SDValue Chain, const SDLoc &dl, SDValue Val, | 
|  | SDValue Ptr, SDValue Offset, SDValue Mask, | 
|  | SDValue EVL, EVT MemVT, MachineMemOperand *MMO, | 
|  | ISD::MemIndexedMode AM, bool IsTruncating, | 
|  | bool IsCompressing) { | 
|  | assert(Chain.getValueType() == MVT::Other && "Invalid chain type"); | 
|  | bool Indexed = AM != ISD::UNINDEXED; | 
|  | assert((Indexed || Offset.isUndef()) && "Unindexed vp_store with an offset!"); | 
|  | SDVTList VTs = Indexed ? getVTList(Ptr.getValueType(), MVT::Other) | 
|  | : getVTList(MVT::Other); | 
|  | SDValue Ops[] = {Chain, Val, Ptr, Offset, Mask, EVL}; | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, ISD::VP_STORE, VTs, Ops); | 
|  | ID.AddInteger(MemVT.getRawBits()); | 
|  | ID.AddInteger(getSyntheticNodeSubclassData<VPStoreSDNode>( | 
|  | dl.getIROrder(), VTs, AM, IsTruncating, IsCompressing, MemVT, MMO)); | 
|  | ID.AddInteger(MMO->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(MMO->getFlags()); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, dl, IP)) { | 
|  | cast<VPStoreSDNode>(E)->refineAlignment(MMO); | 
|  | return SDValue(E, 0); | 
|  | } | 
|  | auto *N = newSDNode<VPStoreSDNode>(dl.getIROrder(), dl.getDebugLoc(), VTs, AM, | 
|  | IsTruncating, IsCompressing, MemVT, MMO); | 
|  | createOperands(N, Ops); | 
|  |  | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | SDValue V(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getTruncStoreVP(SDValue Chain, const SDLoc &dl, | 
|  | SDValue Val, SDValue Ptr, SDValue Mask, | 
|  | SDValue EVL, MachinePointerInfo PtrInfo, | 
|  | EVT SVT, Align Alignment, | 
|  | MachineMemOperand::Flags MMOFlags, | 
|  | const AAMDNodes &AAInfo, | 
|  | bool IsCompressing) { | 
|  | assert(Chain.getValueType() == MVT::Other && "Invalid chain type"); | 
|  |  | 
|  | MMOFlags |= MachineMemOperand::MOStore; | 
|  | assert((MMOFlags & MachineMemOperand::MOLoad) == 0); | 
|  |  | 
|  | if (PtrInfo.V.isNull()) | 
|  | PtrInfo = InferPointerInfo(PtrInfo, *this, Ptr); | 
|  |  | 
|  | MachineFunction &MF = getMachineFunction(); | 
|  | MachineMemOperand *MMO = MF.getMachineMemOperand( | 
|  | PtrInfo, MMOFlags, SVT.getStoreSize(), Alignment, AAInfo); | 
|  | return getTruncStoreVP(Chain, dl, Val, Ptr, Mask, EVL, SVT, MMO, | 
|  | IsCompressing); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getTruncStoreVP(SDValue Chain, const SDLoc &dl, | 
|  | SDValue Val, SDValue Ptr, SDValue Mask, | 
|  | SDValue EVL, EVT SVT, | 
|  | MachineMemOperand *MMO, | 
|  | bool IsCompressing) { | 
|  | EVT VT = Val.getValueType(); | 
|  |  | 
|  | assert(Chain.getValueType() == MVT::Other && "Invalid chain type"); | 
|  | if (VT == SVT) | 
|  | return getStoreVP(Chain, dl, Val, Ptr, getUNDEF(Ptr.getValueType()), Mask, | 
|  | EVL, VT, MMO, ISD::UNINDEXED, | 
|  | /*IsTruncating*/ false, IsCompressing); | 
|  |  | 
|  | assert(SVT.getScalarType().bitsLT(VT.getScalarType()) && | 
|  | "Should only be a truncating store, not extending!"); | 
|  | assert(VT.isInteger() == SVT.isInteger() && "Can't do FP-INT conversion!"); | 
|  | assert(VT.isVector() == SVT.isVector() && | 
|  | "Cannot use trunc store to convert to or from a vector!"); | 
|  | assert((!VT.isVector() || | 
|  | VT.getVectorElementCount() == SVT.getVectorElementCount()) && | 
|  | "Cannot use trunc store to change the number of vector elements!"); | 
|  |  | 
|  | SDVTList VTs = getVTList(MVT::Other); | 
|  | SDValue Undef = getUNDEF(Ptr.getValueType()); | 
|  | SDValue Ops[] = {Chain, Val, Ptr, Undef, Mask, EVL}; | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, ISD::VP_STORE, VTs, Ops); | 
|  | ID.AddInteger(SVT.getRawBits()); | 
|  | ID.AddInteger(getSyntheticNodeSubclassData<VPStoreSDNode>( | 
|  | dl.getIROrder(), VTs, ISD::UNINDEXED, true, IsCompressing, SVT, MMO)); | 
|  | ID.AddInteger(MMO->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(MMO->getFlags()); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, dl, IP)) { | 
|  | cast<VPStoreSDNode>(E)->refineAlignment(MMO); | 
|  | return SDValue(E, 0); | 
|  | } | 
|  | auto *N = | 
|  | newSDNode<VPStoreSDNode>(dl.getIROrder(), dl.getDebugLoc(), VTs, | 
|  | ISD::UNINDEXED, true, IsCompressing, SVT, MMO); | 
|  | createOperands(N, Ops); | 
|  |  | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | SDValue V(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getIndexedStoreVP(SDValue OrigStore, const SDLoc &dl, | 
|  | SDValue Base, SDValue Offset, | 
|  | ISD::MemIndexedMode AM) { | 
|  | auto *ST = cast<VPStoreSDNode>(OrigStore); | 
|  | assert(ST->getOffset().isUndef() && "Store is already an indexed store!"); | 
|  | SDVTList VTs = getVTList(Base.getValueType(), MVT::Other); | 
|  | SDValue Ops[] = {ST->getChain(), ST->getValue(), Base, | 
|  | Offset,         ST->getMask(),  ST->getVectorLength()}; | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, ISD::VP_STORE, VTs, Ops); | 
|  | ID.AddInteger(ST->getMemoryVT().getRawBits()); | 
|  | ID.AddInteger(ST->getRawSubclassData()); | 
|  | ID.AddInteger(ST->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(ST->getMemOperand()->getFlags()); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, dl, IP)) | 
|  | return SDValue(E, 0); | 
|  |  | 
|  | auto *N = newSDNode<VPStoreSDNode>( | 
|  | dl.getIROrder(), dl.getDebugLoc(), VTs, AM, ST->isTruncatingStore(), | 
|  | ST->isCompressingStore(), ST->getMemoryVT(), ST->getMemOperand()); | 
|  | createOperands(N, Ops); | 
|  |  | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | SDValue V(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getStridedLoadVP( | 
|  | ISD::MemIndexedMode AM, ISD::LoadExtType ExtType, EVT VT, const SDLoc &DL, | 
|  | SDValue Chain, SDValue Ptr, SDValue Offset, SDValue Stride, SDValue Mask, | 
|  | SDValue EVL, EVT MemVT, MachineMemOperand *MMO, bool IsExpanding) { | 
|  | bool Indexed = AM != ISD::UNINDEXED; | 
|  | assert((Indexed || Offset.isUndef()) && "Unindexed load with an offset!"); | 
|  |  | 
|  | SDValue Ops[] = {Chain, Ptr, Offset, Stride, Mask, EVL}; | 
|  | SDVTList VTs = Indexed ? getVTList(VT, Ptr.getValueType(), MVT::Other) | 
|  | : getVTList(VT, MVT::Other); | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, ISD::EXPERIMENTAL_VP_STRIDED_LOAD, VTs, Ops); | 
|  | ID.AddInteger(VT.getRawBits()); | 
|  | ID.AddInteger(getSyntheticNodeSubclassData<VPStridedLoadSDNode>( | 
|  | DL.getIROrder(), VTs, AM, ExtType, IsExpanding, MemVT, MMO)); | 
|  | ID.AddInteger(MMO->getPointerInfo().getAddrSpace()); | 
|  |  | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, DL, IP)) { | 
|  | cast<VPStridedLoadSDNode>(E)->refineAlignment(MMO); | 
|  | return SDValue(E, 0); | 
|  | } | 
|  |  | 
|  | auto *N = | 
|  | newSDNode<VPStridedLoadSDNode>(DL.getIROrder(), DL.getDebugLoc(), VTs, AM, | 
|  | ExtType, IsExpanding, MemVT, MMO); | 
|  | createOperands(N, Ops); | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | SDValue V(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getStridedLoadVP(EVT VT, const SDLoc &DL, SDValue Chain, | 
|  | SDValue Ptr, SDValue Stride, | 
|  | SDValue Mask, SDValue EVL, | 
|  | MachineMemOperand *MMO, | 
|  | bool IsExpanding) { | 
|  | SDValue Undef = getUNDEF(Ptr.getValueType()); | 
|  | return getStridedLoadVP(ISD::UNINDEXED, ISD::NON_EXTLOAD, VT, DL, Chain, Ptr, | 
|  | Undef, Stride, Mask, EVL, VT, MMO, IsExpanding); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getExtStridedLoadVP( | 
|  | ISD::LoadExtType ExtType, const SDLoc &DL, EVT VT, SDValue Chain, | 
|  | SDValue Ptr, SDValue Stride, SDValue Mask, SDValue EVL, EVT MemVT, | 
|  | MachineMemOperand *MMO, bool IsExpanding) { | 
|  | SDValue Undef = getUNDEF(Ptr.getValueType()); | 
|  | return getStridedLoadVP(ISD::UNINDEXED, ExtType, VT, DL, Chain, Ptr, Undef, | 
|  | Stride, Mask, EVL, MemVT, MMO, IsExpanding); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getStridedStoreVP(SDValue Chain, const SDLoc &DL, | 
|  | SDValue Val, SDValue Ptr, | 
|  | SDValue Offset, SDValue Stride, | 
|  | SDValue Mask, SDValue EVL, EVT MemVT, | 
|  | MachineMemOperand *MMO, | 
|  | ISD::MemIndexedMode AM, | 
|  | bool IsTruncating, bool IsCompressing) { | 
|  | assert(Chain.getValueType() == MVT::Other && "Invalid chain type"); | 
|  | bool Indexed = AM != ISD::UNINDEXED; | 
|  | assert((Indexed || Offset.isUndef()) && "Unindexed vp_store with an offset!"); | 
|  | SDVTList VTs = Indexed ? getVTList(Ptr.getValueType(), MVT::Other) | 
|  | : getVTList(MVT::Other); | 
|  | SDValue Ops[] = {Chain, Val, Ptr, Offset, Stride, Mask, EVL}; | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, ISD::EXPERIMENTAL_VP_STRIDED_STORE, VTs, Ops); | 
|  | ID.AddInteger(MemVT.getRawBits()); | 
|  | ID.AddInteger(getSyntheticNodeSubclassData<VPStridedStoreSDNode>( | 
|  | DL.getIROrder(), VTs, AM, IsTruncating, IsCompressing, MemVT, MMO)); | 
|  | ID.AddInteger(MMO->getPointerInfo().getAddrSpace()); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, DL, IP)) { | 
|  | cast<VPStridedStoreSDNode>(E)->refineAlignment(MMO); | 
|  | return SDValue(E, 0); | 
|  | } | 
|  | auto *N = newSDNode<VPStridedStoreSDNode>(DL.getIROrder(), DL.getDebugLoc(), | 
|  | VTs, AM, IsTruncating, | 
|  | IsCompressing, MemVT, MMO); | 
|  | createOperands(N, Ops); | 
|  |  | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | SDValue V(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getTruncStridedStoreVP(SDValue Chain, const SDLoc &DL, | 
|  | SDValue Val, SDValue Ptr, | 
|  | SDValue Stride, SDValue Mask, | 
|  | SDValue EVL, EVT SVT, | 
|  | MachineMemOperand *MMO, | 
|  | bool IsCompressing) { | 
|  | EVT VT = Val.getValueType(); | 
|  |  | 
|  | assert(Chain.getValueType() == MVT::Other && "Invalid chain type"); | 
|  | if (VT == SVT) | 
|  | return getStridedStoreVP(Chain, DL, Val, Ptr, getUNDEF(Ptr.getValueType()), | 
|  | Stride, Mask, EVL, VT, MMO, ISD::UNINDEXED, | 
|  | /*IsTruncating*/ false, IsCompressing); | 
|  |  | 
|  | assert(SVT.getScalarType().bitsLT(VT.getScalarType()) && | 
|  | "Should only be a truncating store, not extending!"); | 
|  | assert(VT.isInteger() == SVT.isInteger() && "Can't do FP-INT conversion!"); | 
|  | assert(VT.isVector() == SVT.isVector() && | 
|  | "Cannot use trunc store to convert to or from a vector!"); | 
|  | assert((!VT.isVector() || | 
|  | VT.getVectorElementCount() == SVT.getVectorElementCount()) && | 
|  | "Cannot use trunc store to change the number of vector elements!"); | 
|  |  | 
|  | SDVTList VTs = getVTList(MVT::Other); | 
|  | SDValue Undef = getUNDEF(Ptr.getValueType()); | 
|  | SDValue Ops[] = {Chain, Val, Ptr, Undef, Stride, Mask, EVL}; | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, ISD::EXPERIMENTAL_VP_STRIDED_STORE, VTs, Ops); | 
|  | ID.AddInteger(SVT.getRawBits()); | 
|  | ID.AddInteger(getSyntheticNodeSubclassData<VPStridedStoreSDNode>( | 
|  | DL.getIROrder(), VTs, ISD::UNINDEXED, true, IsCompressing, SVT, MMO)); | 
|  | ID.AddInteger(MMO->getPointerInfo().getAddrSpace()); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, DL, IP)) { | 
|  | cast<VPStridedStoreSDNode>(E)->refineAlignment(MMO); | 
|  | return SDValue(E, 0); | 
|  | } | 
|  | auto *N = newSDNode<VPStridedStoreSDNode>(DL.getIROrder(), DL.getDebugLoc(), | 
|  | VTs, ISD::UNINDEXED, true, | 
|  | IsCompressing, SVT, MMO); | 
|  | createOperands(N, Ops); | 
|  |  | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | SDValue V(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getGatherVP(SDVTList VTs, EVT VT, const SDLoc &dl, | 
|  | ArrayRef<SDValue> Ops, MachineMemOperand *MMO, | 
|  | ISD::MemIndexType IndexType) { | 
|  | assert(Ops.size() == 6 && "Incompatible number of operands"); | 
|  |  | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, ISD::VP_GATHER, VTs, Ops); | 
|  | ID.AddInteger(VT.getRawBits()); | 
|  | ID.AddInteger(getSyntheticNodeSubclassData<VPGatherSDNode>( | 
|  | dl.getIROrder(), VTs, VT, MMO, IndexType)); | 
|  | ID.AddInteger(MMO->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(MMO->getFlags()); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, dl, IP)) { | 
|  | cast<VPGatherSDNode>(E)->refineAlignment(MMO); | 
|  | return SDValue(E, 0); | 
|  | } | 
|  |  | 
|  | auto *N = newSDNode<VPGatherSDNode>(dl.getIROrder(), dl.getDebugLoc(), VTs, | 
|  | VT, MMO, IndexType); | 
|  | createOperands(N, Ops); | 
|  |  | 
|  | assert(N->getMask().getValueType().getVectorElementCount() == | 
|  | N->getValueType(0).getVectorElementCount() && | 
|  | "Vector width mismatch between mask and data"); | 
|  | assert(N->getIndex().getValueType().getVectorElementCount().isScalable() == | 
|  | N->getValueType(0).getVectorElementCount().isScalable() && | 
|  | "Scalable flags of index and data do not match"); | 
|  | assert(ElementCount::isKnownGE( | 
|  | N->getIndex().getValueType().getVectorElementCount(), | 
|  | N->getValueType(0).getVectorElementCount()) && | 
|  | "Vector width mismatch between index and data"); | 
|  | assert(isa<ConstantSDNode>(N->getScale()) && | 
|  | N->getScale()->getAsAPIntVal().isPowerOf2() && | 
|  | "Scale should be a constant power of 2"); | 
|  |  | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | SDValue V(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getScatterVP(SDVTList VTs, EVT VT, const SDLoc &dl, | 
|  | ArrayRef<SDValue> Ops, | 
|  | MachineMemOperand *MMO, | 
|  | ISD::MemIndexType IndexType) { | 
|  | assert(Ops.size() == 7 && "Incompatible number of operands"); | 
|  |  | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, ISD::VP_SCATTER, VTs, Ops); | 
|  | ID.AddInteger(VT.getRawBits()); | 
|  | ID.AddInteger(getSyntheticNodeSubclassData<VPScatterSDNode>( | 
|  | dl.getIROrder(), VTs, VT, MMO, IndexType)); | 
|  | ID.AddInteger(MMO->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(MMO->getFlags()); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, dl, IP)) { | 
|  | cast<VPScatterSDNode>(E)->refineAlignment(MMO); | 
|  | return SDValue(E, 0); | 
|  | } | 
|  | auto *N = newSDNode<VPScatterSDNode>(dl.getIROrder(), dl.getDebugLoc(), VTs, | 
|  | VT, MMO, IndexType); | 
|  | createOperands(N, Ops); | 
|  |  | 
|  | assert(N->getMask().getValueType().getVectorElementCount() == | 
|  | N->getValue().getValueType().getVectorElementCount() && | 
|  | "Vector width mismatch between mask and data"); | 
|  | assert( | 
|  | N->getIndex().getValueType().getVectorElementCount().isScalable() == | 
|  | N->getValue().getValueType().getVectorElementCount().isScalable() && | 
|  | "Scalable flags of index and data do not match"); | 
|  | assert(ElementCount::isKnownGE( | 
|  | N->getIndex().getValueType().getVectorElementCount(), | 
|  | N->getValue().getValueType().getVectorElementCount()) && | 
|  | "Vector width mismatch between index and data"); | 
|  | assert(isa<ConstantSDNode>(N->getScale()) && | 
|  | N->getScale()->getAsAPIntVal().isPowerOf2() && | 
|  | "Scale should be a constant power of 2"); | 
|  |  | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | SDValue V(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getMaskedLoad(EVT VT, const SDLoc &dl, SDValue Chain, | 
|  | SDValue Base, SDValue Offset, SDValue Mask, | 
|  | SDValue PassThru, EVT MemVT, | 
|  | MachineMemOperand *MMO, | 
|  | ISD::MemIndexedMode AM, | 
|  | ISD::LoadExtType ExtTy, bool isExpanding) { | 
|  | bool Indexed = AM != ISD::UNINDEXED; | 
|  | assert((Indexed || Offset.isUndef()) && | 
|  | "Unindexed masked load with an offset!"); | 
|  | SDVTList VTs = Indexed ? getVTList(VT, Base.getValueType(), MVT::Other) | 
|  | : getVTList(VT, MVT::Other); | 
|  | SDValue Ops[] = {Chain, Base, Offset, Mask, PassThru}; | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, ISD::MLOAD, VTs, Ops); | 
|  | ID.AddInteger(MemVT.getRawBits()); | 
|  | ID.AddInteger(getSyntheticNodeSubclassData<MaskedLoadSDNode>( | 
|  | dl.getIROrder(), VTs, AM, ExtTy, isExpanding, MemVT, MMO)); | 
|  | ID.AddInteger(MMO->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(MMO->getFlags()); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, dl, IP)) { | 
|  | cast<MaskedLoadSDNode>(E)->refineAlignment(MMO); | 
|  | return SDValue(E, 0); | 
|  | } | 
|  | auto *N = newSDNode<MaskedLoadSDNode>(dl.getIROrder(), dl.getDebugLoc(), VTs, | 
|  | AM, ExtTy, isExpanding, MemVT, MMO); | 
|  | createOperands(N, Ops); | 
|  |  | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | SDValue V(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getIndexedMaskedLoad(SDValue OrigLoad, const SDLoc &dl, | 
|  | SDValue Base, SDValue Offset, | 
|  | ISD::MemIndexedMode AM) { | 
|  | MaskedLoadSDNode *LD = cast<MaskedLoadSDNode>(OrigLoad); | 
|  | assert(LD->getOffset().isUndef() && "Masked load is already a indexed load!"); | 
|  | return getMaskedLoad(OrigLoad.getValueType(), dl, LD->getChain(), Base, | 
|  | Offset, LD->getMask(), LD->getPassThru(), | 
|  | LD->getMemoryVT(), LD->getMemOperand(), AM, | 
|  | LD->getExtensionType(), LD->isExpandingLoad()); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getMaskedStore(SDValue Chain, const SDLoc &dl, | 
|  | SDValue Val, SDValue Base, SDValue Offset, | 
|  | SDValue Mask, EVT MemVT, | 
|  | MachineMemOperand *MMO, | 
|  | ISD::MemIndexedMode AM, bool IsTruncating, | 
|  | bool IsCompressing) { | 
|  | assert(Chain.getValueType() == MVT::Other && | 
|  | "Invalid chain type"); | 
|  | bool Indexed = AM != ISD::UNINDEXED; | 
|  | assert((Indexed || Offset.isUndef()) && | 
|  | "Unindexed masked store with an offset!"); | 
|  | SDVTList VTs = Indexed ? getVTList(Base.getValueType(), MVT::Other) | 
|  | : getVTList(MVT::Other); | 
|  | SDValue Ops[] = {Chain, Val, Base, Offset, Mask}; | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, ISD::MSTORE, VTs, Ops); | 
|  | ID.AddInteger(MemVT.getRawBits()); | 
|  | ID.AddInteger(getSyntheticNodeSubclassData<MaskedStoreSDNode>( | 
|  | dl.getIROrder(), VTs, AM, IsTruncating, IsCompressing, MemVT, MMO)); | 
|  | ID.AddInteger(MMO->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(MMO->getFlags()); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, dl, IP)) { | 
|  | cast<MaskedStoreSDNode>(E)->refineAlignment(MMO); | 
|  | return SDValue(E, 0); | 
|  | } | 
|  | auto *N = | 
|  | newSDNode<MaskedStoreSDNode>(dl.getIROrder(), dl.getDebugLoc(), VTs, AM, | 
|  | IsTruncating, IsCompressing, MemVT, MMO); | 
|  | createOperands(N, Ops); | 
|  |  | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | SDValue V(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getIndexedMaskedStore(SDValue OrigStore, const SDLoc &dl, | 
|  | SDValue Base, SDValue Offset, | 
|  | ISD::MemIndexedMode AM) { | 
|  | MaskedStoreSDNode *ST = cast<MaskedStoreSDNode>(OrigStore); | 
|  | assert(ST->getOffset().isUndef() && | 
|  | "Masked store is already a indexed store!"); | 
|  | return getMaskedStore(ST->getChain(), dl, ST->getValue(), Base, Offset, | 
|  | ST->getMask(), ST->getMemoryVT(), ST->getMemOperand(), | 
|  | AM, ST->isTruncatingStore(), ST->isCompressingStore()); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getMaskedGather(SDVTList VTs, EVT MemVT, const SDLoc &dl, | 
|  | ArrayRef<SDValue> Ops, | 
|  | MachineMemOperand *MMO, | 
|  | ISD::MemIndexType IndexType, | 
|  | ISD::LoadExtType ExtTy) { | 
|  | assert(Ops.size() == 6 && "Incompatible number of operands"); | 
|  |  | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, ISD::MGATHER, VTs, Ops); | 
|  | ID.AddInteger(MemVT.getRawBits()); | 
|  | ID.AddInteger(getSyntheticNodeSubclassData<MaskedGatherSDNode>( | 
|  | dl.getIROrder(), VTs, MemVT, MMO, IndexType, ExtTy)); | 
|  | ID.AddInteger(MMO->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(MMO->getFlags()); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, dl, IP)) { | 
|  | cast<MaskedGatherSDNode>(E)->refineAlignment(MMO); | 
|  | return SDValue(E, 0); | 
|  | } | 
|  |  | 
|  | auto *N = newSDNode<MaskedGatherSDNode>(dl.getIROrder(), dl.getDebugLoc(), | 
|  | VTs, MemVT, MMO, IndexType, ExtTy); | 
|  | createOperands(N, Ops); | 
|  |  | 
|  | assert(N->getPassThru().getValueType() == N->getValueType(0) && | 
|  | "Incompatible type of the PassThru value in MaskedGatherSDNode"); | 
|  | assert(N->getMask().getValueType().getVectorElementCount() == | 
|  | N->getValueType(0).getVectorElementCount() && | 
|  | "Vector width mismatch between mask and data"); | 
|  | assert(N->getIndex().getValueType().getVectorElementCount().isScalable() == | 
|  | N->getValueType(0).getVectorElementCount().isScalable() && | 
|  | "Scalable flags of index and data do not match"); | 
|  | assert(ElementCount::isKnownGE( | 
|  | N->getIndex().getValueType().getVectorElementCount(), | 
|  | N->getValueType(0).getVectorElementCount()) && | 
|  | "Vector width mismatch between index and data"); | 
|  | assert(isa<ConstantSDNode>(N->getScale()) && | 
|  | N->getScale()->getAsAPIntVal().isPowerOf2() && | 
|  | "Scale should be a constant power of 2"); | 
|  |  | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | SDValue V(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getMaskedScatter(SDVTList VTs, EVT MemVT, const SDLoc &dl, | 
|  | ArrayRef<SDValue> Ops, | 
|  | MachineMemOperand *MMO, | 
|  | ISD::MemIndexType IndexType, | 
|  | bool IsTrunc) { | 
|  | assert(Ops.size() == 6 && "Incompatible number of operands"); | 
|  |  | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, ISD::MSCATTER, VTs, Ops); | 
|  | ID.AddInteger(MemVT.getRawBits()); | 
|  | ID.AddInteger(getSyntheticNodeSubclassData<MaskedScatterSDNode>( | 
|  | dl.getIROrder(), VTs, MemVT, MMO, IndexType, IsTrunc)); | 
|  | ID.AddInteger(MMO->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(MMO->getFlags()); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, dl, IP)) { | 
|  | cast<MaskedScatterSDNode>(E)->refineAlignment(MMO); | 
|  | return SDValue(E, 0); | 
|  | } | 
|  |  | 
|  | auto *N = newSDNode<MaskedScatterSDNode>(dl.getIROrder(), dl.getDebugLoc(), | 
|  | VTs, MemVT, MMO, IndexType, IsTrunc); | 
|  | createOperands(N, Ops); | 
|  |  | 
|  | assert(N->getMask().getValueType().getVectorElementCount() == | 
|  | N->getValue().getValueType().getVectorElementCount() && | 
|  | "Vector width mismatch between mask and data"); | 
|  | assert( | 
|  | N->getIndex().getValueType().getVectorElementCount().isScalable() == | 
|  | N->getValue().getValueType().getVectorElementCount().isScalable() && | 
|  | "Scalable flags of index and data do not match"); | 
|  | assert(ElementCount::isKnownGE( | 
|  | N->getIndex().getValueType().getVectorElementCount(), | 
|  | N->getValue().getValueType().getVectorElementCount()) && | 
|  | "Vector width mismatch between index and data"); | 
|  | assert(isa<ConstantSDNode>(N->getScale()) && | 
|  | N->getScale()->getAsAPIntVal().isPowerOf2() && | 
|  | "Scale should be a constant power of 2"); | 
|  |  | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | SDValue V(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getMaskedHistogram(SDVTList VTs, EVT MemVT, | 
|  | const SDLoc &dl, ArrayRef<SDValue> Ops, | 
|  | MachineMemOperand *MMO, | 
|  | ISD::MemIndexType IndexType) { | 
|  | assert(Ops.size() == 7 && "Incompatible number of operands"); | 
|  |  | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, ISD::EXPERIMENTAL_VECTOR_HISTOGRAM, VTs, Ops); | 
|  | ID.AddInteger(MemVT.getRawBits()); | 
|  | ID.AddInteger(getSyntheticNodeSubclassData<MaskedHistogramSDNode>( | 
|  | dl.getIROrder(), VTs, MemVT, MMO, IndexType)); | 
|  | ID.AddInteger(MMO->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(MMO->getFlags()); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, dl, IP)) { | 
|  | cast<MaskedGatherSDNode>(E)->refineAlignment(MMO); | 
|  | return SDValue(E, 0); | 
|  | } | 
|  |  | 
|  | auto *N = newSDNode<MaskedHistogramSDNode>(dl.getIROrder(), dl.getDebugLoc(), | 
|  | VTs, MemVT, MMO, IndexType); | 
|  | createOperands(N, Ops); | 
|  |  | 
|  | assert(N->getMask().getValueType().getVectorElementCount() == | 
|  | N->getIndex().getValueType().getVectorElementCount() && | 
|  | "Vector width mismatch between mask and data"); | 
|  | assert(isa<ConstantSDNode>(N->getScale()) && | 
|  | N->getScale()->getAsAPIntVal().isPowerOf2() && | 
|  | "Scale should be a constant power of 2"); | 
|  | assert(N->getInc().getValueType().isInteger() && "Non integer update value"); | 
|  |  | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | SDValue V(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getLoadFFVP(EVT VT, const SDLoc &DL, SDValue Chain, | 
|  | SDValue Ptr, SDValue Mask, SDValue EVL, | 
|  | MachineMemOperand *MMO) { | 
|  | SDVTList VTs = getVTList(VT, EVL.getValueType(), MVT::Other); | 
|  | SDValue Ops[] = {Chain, Ptr, Mask, EVL}; | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, ISD::VP_LOAD_FF, VTs, Ops); | 
|  | ID.AddInteger(VT.getRawBits()); | 
|  | ID.AddInteger(getSyntheticNodeSubclassData<VPLoadFFSDNode>(DL.getIROrder(), | 
|  | VTs, VT, MMO)); | 
|  | ID.AddInteger(MMO->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(MMO->getFlags()); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, DL, IP)) { | 
|  | cast<VPLoadFFSDNode>(E)->refineAlignment(MMO); | 
|  | return SDValue(E, 0); | 
|  | } | 
|  | auto *N = newSDNode<VPLoadFFSDNode>(DL.getIROrder(), DL.getDebugLoc(), VTs, | 
|  | VT, MMO); | 
|  | createOperands(N, Ops); | 
|  |  | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | SDValue V(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getGetFPEnv(SDValue Chain, const SDLoc &dl, SDValue Ptr, | 
|  | EVT MemVT, MachineMemOperand *MMO) { | 
|  | assert(Chain.getValueType() == MVT::Other && "Invalid chain type"); | 
|  | SDVTList VTs = getVTList(MVT::Other); | 
|  | SDValue Ops[] = {Chain, Ptr}; | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, ISD::GET_FPENV_MEM, VTs, Ops); | 
|  | ID.AddInteger(MemVT.getRawBits()); | 
|  | ID.AddInteger(getSyntheticNodeSubclassData<FPStateAccessSDNode>( | 
|  | ISD::GET_FPENV_MEM, dl.getIROrder(), VTs, MemVT, MMO)); | 
|  | ID.AddInteger(MMO->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(MMO->getFlags()); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, dl, IP)) | 
|  | return SDValue(E, 0); | 
|  |  | 
|  | auto *N = newSDNode<FPStateAccessSDNode>(ISD::GET_FPENV_MEM, dl.getIROrder(), | 
|  | dl.getDebugLoc(), VTs, MemVT, MMO); | 
|  | createOperands(N, Ops); | 
|  |  | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | SDValue V(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getSetFPEnv(SDValue Chain, const SDLoc &dl, SDValue Ptr, | 
|  | EVT MemVT, MachineMemOperand *MMO) { | 
|  | assert(Chain.getValueType() == MVT::Other && "Invalid chain type"); | 
|  | SDVTList VTs = getVTList(MVT::Other); | 
|  | SDValue Ops[] = {Chain, Ptr}; | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, ISD::SET_FPENV_MEM, VTs, Ops); | 
|  | ID.AddInteger(MemVT.getRawBits()); | 
|  | ID.AddInteger(getSyntheticNodeSubclassData<FPStateAccessSDNode>( | 
|  | ISD::SET_FPENV_MEM, dl.getIROrder(), VTs, MemVT, MMO)); | 
|  | ID.AddInteger(MMO->getPointerInfo().getAddrSpace()); | 
|  | ID.AddInteger(MMO->getFlags()); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, dl, IP)) | 
|  | return SDValue(E, 0); | 
|  |  | 
|  | auto *N = newSDNode<FPStateAccessSDNode>(ISD::SET_FPENV_MEM, dl.getIROrder(), | 
|  | dl.getDebugLoc(), VTs, MemVT, MMO); | 
|  | createOperands(N, Ops); | 
|  |  | 
|  | CSEMap.InsertNode(N, IP); | 
|  | InsertNode(N); | 
|  | SDValue V(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::simplifySelect(SDValue Cond, SDValue T, SDValue F) { | 
|  | // select undef, T, F --> T (if T is a constant), otherwise F | 
|  | // select, ?, undef, F --> F | 
|  | // select, ?, T, undef --> T | 
|  | if (Cond.isUndef()) | 
|  | return isConstantValueOfAnyType(T) ? T : F; | 
|  | if (T.isUndef()) | 
|  | return F; | 
|  | if (F.isUndef()) | 
|  | return T; | 
|  |  | 
|  | // select true, T, F --> T | 
|  | // select false, T, F --> F | 
|  | if (auto C = isBoolConstant(Cond)) | 
|  | return *C ? T : F; | 
|  |  | 
|  | // select ?, T, T --> T | 
|  | if (T == F) | 
|  | return T; | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::simplifyShift(SDValue X, SDValue Y) { | 
|  | // shift undef, Y --> 0 (can always assume that the undef value is 0) | 
|  | if (X.isUndef()) | 
|  | return getConstant(0, SDLoc(X.getNode()), X.getValueType()); | 
|  | // shift X, undef --> undef (because it may shift by the bitwidth) | 
|  | if (Y.isUndef()) | 
|  | return getUNDEF(X.getValueType()); | 
|  |  | 
|  | // shift 0, Y --> 0 | 
|  | // shift X, 0 --> X | 
|  | if (isNullOrNullSplat(X) || isNullOrNullSplat(Y)) | 
|  | return X; | 
|  |  | 
|  | // shift X, C >= bitwidth(X) --> undef | 
|  | // All vector elements must be too big (or undef) to avoid partial undefs. | 
|  | auto isShiftTooBig = [X](ConstantSDNode *Val) { | 
|  | return !Val || Val->getAPIntValue().uge(X.getScalarValueSizeInBits()); | 
|  | }; | 
|  | if (ISD::matchUnaryPredicate(Y, isShiftTooBig, true)) | 
|  | return getUNDEF(X.getValueType()); | 
|  |  | 
|  | // shift i1/vXi1 X, Y --> X (any non-zero shift amount is undefined). | 
|  | if (X.getValueType().getScalarType() == MVT::i1) | 
|  | return X; | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::simplifyFPBinop(unsigned Opcode, SDValue X, SDValue Y, | 
|  | SDNodeFlags Flags) { | 
|  | // If this operation has 'nnan' or 'ninf' and at least 1 disallowed operand | 
|  | // (an undef operand can be chosen to be Nan/Inf), then the result of this | 
|  | // operation is poison. That result can be relaxed to undef. | 
|  | ConstantFPSDNode *XC = isConstOrConstSplatFP(X, /* AllowUndefs */ true); | 
|  | ConstantFPSDNode *YC = isConstOrConstSplatFP(Y, /* AllowUndefs */ true); | 
|  | bool HasNan = (XC && XC->getValueAPF().isNaN()) || | 
|  | (YC && YC->getValueAPF().isNaN()); | 
|  | bool HasInf = (XC && XC->getValueAPF().isInfinity()) || | 
|  | (YC && YC->getValueAPF().isInfinity()); | 
|  |  | 
|  | if (Flags.hasNoNaNs() && (HasNan || X.isUndef() || Y.isUndef())) | 
|  | return getUNDEF(X.getValueType()); | 
|  |  | 
|  | if (Flags.hasNoInfs() && (HasInf || X.isUndef() || Y.isUndef())) | 
|  | return getUNDEF(X.getValueType()); | 
|  |  | 
|  | if (!YC) | 
|  | return SDValue(); | 
|  |  | 
|  | // X + -0.0 --> X | 
|  | if (Opcode == ISD::FADD) | 
|  | if (YC->getValueAPF().isNegZero()) | 
|  | return X; | 
|  |  | 
|  | // X - +0.0 --> X | 
|  | if (Opcode == ISD::FSUB) | 
|  | if (YC->getValueAPF().isPosZero()) | 
|  | return X; | 
|  |  | 
|  | // X * 1.0 --> X | 
|  | // X / 1.0 --> X | 
|  | if (Opcode == ISD::FMUL || Opcode == ISD::FDIV) | 
|  | if (YC->getValueAPF().isExactlyValue(1.0)) | 
|  | return X; | 
|  |  | 
|  | // X * 0.0 --> 0.0 | 
|  | if (Opcode == ISD::FMUL && Flags.hasNoNaNs() && Flags.hasNoSignedZeros()) | 
|  | if (YC->getValueAPF().isZero()) | 
|  | return getConstantFP(0.0, SDLoc(Y), Y.getValueType()); | 
|  |  | 
|  | return SDValue(); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getVAArg(EVT VT, const SDLoc &dl, SDValue Chain, | 
|  | SDValue Ptr, SDValue SV, unsigned Align) { | 
|  | SDValue Ops[] = { Chain, Ptr, SV, getTargetConstant(Align, dl, MVT::i32) }; | 
|  | return getNode(ISD::VAARG, dl, getVTList(VT, MVT::Other), Ops); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT, | 
|  | ArrayRef<SDUse> Ops) { | 
|  | switch (Ops.size()) { | 
|  | case 0: return getNode(Opcode, DL, VT); | 
|  | case 1: return getNode(Opcode, DL, VT, Ops[0].get()); | 
|  | case 2: return getNode(Opcode, DL, VT, Ops[0], Ops[1]); | 
|  | case 3: return getNode(Opcode, DL, VT, Ops[0], Ops[1], Ops[2]); | 
|  | default: break; | 
|  | } | 
|  |  | 
|  | // Copy from an SDUse array into an SDValue array for use with | 
|  | // the regular getNode logic. | 
|  | SmallVector<SDValue, 8> NewOps(Ops); | 
|  | return getNode(Opcode, DL, VT, NewOps); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT, | 
|  | ArrayRef<SDValue> Ops) { | 
|  | SDNodeFlags Flags; | 
|  | if (Inserter) | 
|  | Flags = Inserter->getFlags(); | 
|  | return getNode(Opcode, DL, VT, Ops, Flags); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT, | 
|  | ArrayRef<SDValue> Ops, const SDNodeFlags Flags) { | 
|  | unsigned NumOps = Ops.size(); | 
|  | switch (NumOps) { | 
|  | case 0: return getNode(Opcode, DL, VT); | 
|  | case 1: return getNode(Opcode, DL, VT, Ops[0], Flags); | 
|  | case 2: return getNode(Opcode, DL, VT, Ops[0], Ops[1], Flags); | 
|  | case 3: return getNode(Opcode, DL, VT, Ops[0], Ops[1], Ops[2], Flags); | 
|  | default: break; | 
|  | } | 
|  |  | 
|  | #ifndef NDEBUG | 
|  | for (const auto &Op : Ops) | 
|  | assert(Op.getOpcode() != ISD::DELETED_NODE && | 
|  | "Operand is DELETED_NODE!"); | 
|  | #endif | 
|  |  | 
|  | switch (Opcode) { | 
|  | default: break; | 
|  | case ISD::BUILD_VECTOR: | 
|  | // Attempt to simplify BUILD_VECTOR. | 
|  | if (SDValue V = FoldBUILD_VECTOR(DL, VT, Ops, *this)) | 
|  | return V; | 
|  | break; | 
|  | case ISD::CONCAT_VECTORS: | 
|  | if (SDValue V = foldCONCAT_VECTORS(DL, VT, Ops, *this)) | 
|  | return V; | 
|  | break; | 
|  | case ISD::SELECT_CC: | 
|  | assert(NumOps == 5 && "SELECT_CC takes 5 operands!"); | 
|  | assert(Ops[0].getValueType() == Ops[1].getValueType() && | 
|  | "LHS and RHS of condition must have same type!"); | 
|  | assert(Ops[2].getValueType() == Ops[3].getValueType() && | 
|  | "True and False arms of SelectCC must have same type!"); | 
|  | assert(Ops[2].getValueType() == VT && | 
|  | "select_cc node must be of same type as true and false value!"); | 
|  | assert((!Ops[0].getValueType().isVector() || | 
|  | Ops[0].getValueType().getVectorElementCount() == | 
|  | VT.getVectorElementCount()) && | 
|  | "Expected select_cc with vector result to have the same sized " | 
|  | "comparison type!"); | 
|  | break; | 
|  | case ISD::BR_CC: | 
|  | assert(NumOps == 5 && "BR_CC takes 5 operands!"); | 
|  | assert(Ops[2].getValueType() == Ops[3].getValueType() && | 
|  | "LHS/RHS of comparison should match types!"); | 
|  | break; | 
|  | case ISD::VP_ADD: | 
|  | case ISD::VP_SUB: | 
|  | // If it is VP_ADD/VP_SUB mask operation then turn it to VP_XOR | 
|  | if (VT.getScalarType() == MVT::i1) | 
|  | Opcode = ISD::VP_XOR; | 
|  | break; | 
|  | case ISD::VP_MUL: | 
|  | // If it is VP_MUL mask operation then turn it to VP_AND | 
|  | if (VT.getScalarType() == MVT::i1) | 
|  | Opcode = ISD::VP_AND; | 
|  | break; | 
|  | case ISD::VP_REDUCE_MUL: | 
|  | // If it is VP_REDUCE_MUL mask operation then turn it to VP_REDUCE_AND | 
|  | if (VT == MVT::i1) | 
|  | Opcode = ISD::VP_REDUCE_AND; | 
|  | break; | 
|  | case ISD::VP_REDUCE_ADD: | 
|  | // If it is VP_REDUCE_ADD mask operation then turn it to VP_REDUCE_XOR | 
|  | if (VT == MVT::i1) | 
|  | Opcode = ISD::VP_REDUCE_XOR; | 
|  | break; | 
|  | case ISD::VP_REDUCE_SMAX: | 
|  | case ISD::VP_REDUCE_UMIN: | 
|  | // If it is VP_REDUCE_SMAX/VP_REDUCE_UMIN mask operation then turn it to | 
|  | // VP_REDUCE_AND. | 
|  | if (VT == MVT::i1) | 
|  | Opcode = ISD::VP_REDUCE_AND; | 
|  | break; | 
|  | case ISD::VP_REDUCE_SMIN: | 
|  | case ISD::VP_REDUCE_UMAX: | 
|  | // If it is VP_REDUCE_SMIN/VP_REDUCE_UMAX mask operation then turn it to | 
|  | // VP_REDUCE_OR. | 
|  | if (VT == MVT::i1) | 
|  | Opcode = ISD::VP_REDUCE_OR; | 
|  | break; | 
|  | } | 
|  |  | 
|  | // Memoize nodes. | 
|  | SDNode *N; | 
|  | SDVTList VTs = getVTList(VT); | 
|  |  | 
|  | if (VT != MVT::Glue) { | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, Opcode, VTs, Ops); | 
|  | void *IP = nullptr; | 
|  |  | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, DL, IP)) { | 
|  | E->intersectFlagsWith(Flags); | 
|  | return SDValue(E, 0); | 
|  | } | 
|  |  | 
|  | N = newSDNode<SDNode>(Opcode, DL.getIROrder(), DL.getDebugLoc(), VTs); | 
|  | createOperands(N, Ops); | 
|  |  | 
|  | CSEMap.InsertNode(N, IP); | 
|  | } else { | 
|  | N = newSDNode<SDNode>(Opcode, DL.getIROrder(), DL.getDebugLoc(), VTs); | 
|  | createOperands(N, Ops); | 
|  | } | 
|  |  | 
|  | N->setFlags(Flags); | 
|  | InsertNode(N); | 
|  | SDValue V(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, | 
|  | ArrayRef<EVT> ResultTys, ArrayRef<SDValue> Ops) { | 
|  | SDNodeFlags Flags; | 
|  | if (Inserter) | 
|  | Flags = Inserter->getFlags(); | 
|  | return getNode(Opcode, DL, getVTList(ResultTys), Ops, Flags); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, | 
|  | ArrayRef<EVT> ResultTys, ArrayRef<SDValue> Ops, | 
|  | const SDNodeFlags Flags) { | 
|  | return getNode(Opcode, DL, getVTList(ResultTys), Ops, Flags); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, SDVTList VTList, | 
|  | ArrayRef<SDValue> Ops) { | 
|  | SDNodeFlags Flags; | 
|  | if (Inserter) | 
|  | Flags = Inserter->getFlags(); | 
|  | return getNode(Opcode, DL, VTList, Ops, Flags); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, SDVTList VTList, | 
|  | ArrayRef<SDValue> Ops, const SDNodeFlags Flags) { | 
|  | if (VTList.NumVTs == 1) | 
|  | return getNode(Opcode, DL, VTList.VTs[0], Ops, Flags); | 
|  |  | 
|  | #ifndef NDEBUG | 
|  | for (const auto &Op : Ops) | 
|  | assert(Op.getOpcode() != ISD::DELETED_NODE && | 
|  | "Operand is DELETED_NODE!"); | 
|  | #endif | 
|  |  | 
|  | switch (Opcode) { | 
|  | case ISD::SADDO: | 
|  | case ISD::UADDO: | 
|  | case ISD::SSUBO: | 
|  | case ISD::USUBO: { | 
|  | assert(VTList.NumVTs == 2 && Ops.size() == 2 && | 
|  | "Invalid add/sub overflow op!"); | 
|  | assert(VTList.VTs[0].isInteger() && VTList.VTs[1].isInteger() && | 
|  | Ops[0].getValueType() == Ops[1].getValueType() && | 
|  | Ops[0].getValueType() == VTList.VTs[0] && | 
|  | "Binary operator types must match!"); | 
|  | SDValue N1 = Ops[0], N2 = Ops[1]; | 
|  | canonicalizeCommutativeBinop(Opcode, N1, N2); | 
|  |  | 
|  | // (X +- 0) -> X with zero-overflow. | 
|  | ConstantSDNode *N2CV = isConstOrConstSplat(N2, /*AllowUndefs*/ false, | 
|  | /*AllowTruncation*/ true); | 
|  | if (N2CV && N2CV->isZero()) { | 
|  | SDValue ZeroOverFlow = getConstant(0, DL, VTList.VTs[1]); | 
|  | return getNode(ISD::MERGE_VALUES, DL, VTList, {N1, ZeroOverFlow}, Flags); | 
|  | } | 
|  |  | 
|  | if (VTList.VTs[0].getScalarType() == MVT::i1 && | 
|  | VTList.VTs[1].getScalarType() == MVT::i1) { | 
|  | SDValue F1 = getFreeze(N1); | 
|  | SDValue F2 = getFreeze(N2); | 
|  | // {vXi1,vXi1} (u/s)addo(vXi1 x, vXi1y) -> {xor(x,y),and(x,y)} | 
|  | if (Opcode == ISD::UADDO || Opcode == ISD::SADDO) | 
|  | return getNode(ISD::MERGE_VALUES, DL, VTList, | 
|  | {getNode(ISD::XOR, DL, VTList.VTs[0], F1, F2), | 
|  | getNode(ISD::AND, DL, VTList.VTs[1], F1, F2)}, | 
|  | Flags); | 
|  | // {vXi1,vXi1} (u/s)subo(vXi1 x, vXi1y) -> {xor(x,y),and(~x,y)} | 
|  | if (Opcode == ISD::USUBO || Opcode == ISD::SSUBO) { | 
|  | SDValue NotF1 = getNOT(DL, F1, VTList.VTs[0]); | 
|  | return getNode(ISD::MERGE_VALUES, DL, VTList, | 
|  | {getNode(ISD::XOR, DL, VTList.VTs[0], F1, F2), | 
|  | getNode(ISD::AND, DL, VTList.VTs[1], NotF1, F2)}, | 
|  | Flags); | 
|  | } | 
|  | } | 
|  | break; | 
|  | } | 
|  | case ISD::SADDO_CARRY: | 
|  | case ISD::UADDO_CARRY: | 
|  | case ISD::SSUBO_CARRY: | 
|  | case ISD::USUBO_CARRY: | 
|  | assert(VTList.NumVTs == 2 && Ops.size() == 3 && | 
|  | "Invalid add/sub overflow op!"); | 
|  | assert(VTList.VTs[0].isInteger() && VTList.VTs[1].isInteger() && | 
|  | Ops[0].getValueType() == Ops[1].getValueType() && | 
|  | Ops[0].getValueType() == VTList.VTs[0] && | 
|  | Ops[2].getValueType() == VTList.VTs[1] && | 
|  | "Binary operator types must match!"); | 
|  | break; | 
|  | case ISD::SMUL_LOHI: | 
|  | case ISD::UMUL_LOHI: { | 
|  | assert(VTList.NumVTs == 2 && Ops.size() == 2 && "Invalid mul lo/hi op!"); | 
|  | assert(VTList.VTs[0].isInteger() && VTList.VTs[0] == VTList.VTs[1] && | 
|  | VTList.VTs[0] == Ops[0].getValueType() && | 
|  | VTList.VTs[0] == Ops[1].getValueType() && | 
|  | "Binary operator types must match!"); | 
|  | // Constant fold. | 
|  | ConstantSDNode *LHS = dyn_cast<ConstantSDNode>(Ops[0]); | 
|  | ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Ops[1]); | 
|  | if (LHS && RHS) { | 
|  | unsigned Width = VTList.VTs[0].getScalarSizeInBits(); | 
|  | unsigned OutWidth = Width * 2; | 
|  | APInt Val = LHS->getAPIntValue(); | 
|  | APInt Mul = RHS->getAPIntValue(); | 
|  | if (Opcode == ISD::SMUL_LOHI) { | 
|  | Val = Val.sext(OutWidth); | 
|  | Mul = Mul.sext(OutWidth); | 
|  | } else { | 
|  | Val = Val.zext(OutWidth); | 
|  | Mul = Mul.zext(OutWidth); | 
|  | } | 
|  | Val *= Mul; | 
|  |  | 
|  | SDValue Hi = | 
|  | getConstant(Val.extractBits(Width, Width), DL, VTList.VTs[0]); | 
|  | SDValue Lo = getConstant(Val.trunc(Width), DL, VTList.VTs[0]); | 
|  | return getNode(ISD::MERGE_VALUES, DL, VTList, {Lo, Hi}, Flags); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case ISD::FFREXP: { | 
|  | assert(VTList.NumVTs == 2 && Ops.size() == 1 && "Invalid ffrexp op!"); | 
|  | assert(VTList.VTs[0].isFloatingPoint() && VTList.VTs[1].isInteger() && | 
|  | VTList.VTs[0] == Ops[0].getValueType() && "frexp type mismatch"); | 
|  |  | 
|  | if (const ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(Ops[0])) { | 
|  | int FrexpExp; | 
|  | APFloat FrexpMant = | 
|  | frexp(C->getValueAPF(), FrexpExp, APFloat::rmNearestTiesToEven); | 
|  | SDValue Result0 = getConstantFP(FrexpMant, DL, VTList.VTs[0]); | 
|  | SDValue Result1 = | 
|  | getConstant(FrexpMant.isFinite() ? FrexpExp : 0, DL, VTList.VTs[1]); | 
|  | return getNode(ISD::MERGE_VALUES, DL, VTList, {Result0, Result1}, Flags); | 
|  | } | 
|  |  | 
|  | break; | 
|  | } | 
|  | case ISD::STRICT_FP_EXTEND: | 
|  | assert(VTList.NumVTs == 2 && Ops.size() == 2 && | 
|  | "Invalid STRICT_FP_EXTEND!"); | 
|  | assert(VTList.VTs[0].isFloatingPoint() && | 
|  | Ops[1].getValueType().isFloatingPoint() && "Invalid FP cast!"); | 
|  | assert(VTList.VTs[0].isVector() == Ops[1].getValueType().isVector() && | 
|  | "STRICT_FP_EXTEND result type should be vector iff the operand " | 
|  | "type is vector!"); | 
|  | assert((!VTList.VTs[0].isVector() || | 
|  | VTList.VTs[0].getVectorElementCount() == | 
|  | Ops[1].getValueType().getVectorElementCount()) && | 
|  | "Vector element count mismatch!"); | 
|  | assert(Ops[1].getValueType().bitsLT(VTList.VTs[0]) && | 
|  | "Invalid fpext node, dst <= src!"); | 
|  | break; | 
|  | case ISD::STRICT_FP_ROUND: | 
|  | assert(VTList.NumVTs == 2 && Ops.size() == 3 && "Invalid STRICT_FP_ROUND!"); | 
|  | assert(VTList.VTs[0].isVector() == Ops[1].getValueType().isVector() && | 
|  | "STRICT_FP_ROUND result type should be vector iff the operand " | 
|  | "type is vector!"); | 
|  | assert((!VTList.VTs[0].isVector() || | 
|  | VTList.VTs[0].getVectorElementCount() == | 
|  | Ops[1].getValueType().getVectorElementCount()) && | 
|  | "Vector element count mismatch!"); | 
|  | assert(VTList.VTs[0].isFloatingPoint() && | 
|  | Ops[1].getValueType().isFloatingPoint() && | 
|  | VTList.VTs[0].bitsLT(Ops[1].getValueType()) && | 
|  | Ops[2].getOpcode() == ISD::TargetConstant && | 
|  | (Ops[2]->getAsZExtVal() == 0 || Ops[2]->getAsZExtVal() == 1) && | 
|  | "Invalid STRICT_FP_ROUND!"); | 
|  | break; | 
|  | } | 
|  |  | 
|  | // Memoize the node unless it returns a glue result. | 
|  | SDNode *N; | 
|  | if (VTList.VTs[VTList.NumVTs-1] != MVT::Glue) { | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, Opcode, VTList, Ops); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, DL, IP)) { | 
|  | E->intersectFlagsWith(Flags); | 
|  | return SDValue(E, 0); | 
|  | } | 
|  |  | 
|  | N = newSDNode<SDNode>(Opcode, DL.getIROrder(), DL.getDebugLoc(), VTList); | 
|  | createOperands(N, Ops); | 
|  | CSEMap.InsertNode(N, IP); | 
|  | } else { | 
|  | N = newSDNode<SDNode>(Opcode, DL.getIROrder(), DL.getDebugLoc(), VTList); | 
|  | createOperands(N, Ops); | 
|  | } | 
|  |  | 
|  | N->setFlags(Flags); | 
|  | InsertNode(N); | 
|  | SDValue V(N, 0); | 
|  | NewSDValueDbgMsg(V, "Creating new node: ", this); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, | 
|  | SDVTList VTList) { | 
|  | return getNode(Opcode, DL, VTList, ArrayRef<SDValue>()); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, SDVTList VTList, | 
|  | SDValue N1) { | 
|  | SDValue Ops[] = { N1 }; | 
|  | return getNode(Opcode, DL, VTList, Ops); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, SDVTList VTList, | 
|  | SDValue N1, SDValue N2) { | 
|  | SDValue Ops[] = { N1, N2 }; | 
|  | return getNode(Opcode, DL, VTList, Ops); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, SDVTList VTList, | 
|  | SDValue N1, SDValue N2, SDValue N3) { | 
|  | SDValue Ops[] = { N1, N2, N3 }; | 
|  | return getNode(Opcode, DL, VTList, Ops); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, SDVTList VTList, | 
|  | SDValue N1, SDValue N2, SDValue N3, SDValue N4) { | 
|  | SDValue Ops[] = { N1, N2, N3, N4 }; | 
|  | return getNode(Opcode, DL, VTList, Ops); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, SDVTList VTList, | 
|  | SDValue N1, SDValue N2, SDValue N3, SDValue N4, | 
|  | SDValue N5) { | 
|  | SDValue Ops[] = { N1, N2, N3, N4, N5 }; | 
|  | return getNode(Opcode, DL, VTList, Ops); | 
|  | } | 
|  |  | 
|  | SDVTList SelectionDAG::getVTList(EVT VT) { | 
|  | if (!VT.isExtended()) | 
|  | return makeVTList(SDNode::getValueTypeList(VT.getSimpleVT()), 1); | 
|  |  | 
|  | return makeVTList(&(*EVTs.insert(VT).first), 1); | 
|  | } | 
|  |  | 
|  | SDVTList SelectionDAG::getVTList(EVT VT1, EVT VT2) { | 
|  | FoldingSetNodeID ID; | 
|  | ID.AddInteger(2U); | 
|  | ID.AddInteger(VT1.getRawBits()); | 
|  | ID.AddInteger(VT2.getRawBits()); | 
|  |  | 
|  | void *IP = nullptr; | 
|  | SDVTListNode *Result = VTListMap.FindNodeOrInsertPos(ID, IP); | 
|  | if (!Result) { | 
|  | EVT *Array = Allocator.Allocate<EVT>(2); | 
|  | Array[0] = VT1; | 
|  | Array[1] = VT2; | 
|  | Result = new (Allocator) SDVTListNode(ID.Intern(Allocator), Array, 2); | 
|  | VTListMap.InsertNode(Result, IP); | 
|  | } | 
|  | return Result->getSDVTList(); | 
|  | } | 
|  |  | 
|  | SDVTList SelectionDAG::getVTList(EVT VT1, EVT VT2, EVT VT3) { | 
|  | FoldingSetNodeID ID; | 
|  | ID.AddInteger(3U); | 
|  | ID.AddInteger(VT1.getRawBits()); | 
|  | ID.AddInteger(VT2.getRawBits()); | 
|  | ID.AddInteger(VT3.getRawBits()); | 
|  |  | 
|  | void *IP = nullptr; | 
|  | SDVTListNode *Result = VTListMap.FindNodeOrInsertPos(ID, IP); | 
|  | if (!Result) { | 
|  | EVT *Array = Allocator.Allocate<EVT>(3); | 
|  | Array[0] = VT1; | 
|  | Array[1] = VT2; | 
|  | Array[2] = VT3; | 
|  | Result = new (Allocator) SDVTListNode(ID.Intern(Allocator), Array, 3); | 
|  | VTListMap.InsertNode(Result, IP); | 
|  | } | 
|  | return Result->getSDVTList(); | 
|  | } | 
|  |  | 
|  | SDVTList SelectionDAG::getVTList(EVT VT1, EVT VT2, EVT VT3, EVT VT4) { | 
|  | FoldingSetNodeID ID; | 
|  | ID.AddInteger(4U); | 
|  | ID.AddInteger(VT1.getRawBits()); | 
|  | ID.AddInteger(VT2.getRawBits()); | 
|  | ID.AddInteger(VT3.getRawBits()); | 
|  | ID.AddInteger(VT4.getRawBits()); | 
|  |  | 
|  | void *IP = nullptr; | 
|  | SDVTListNode *Result = VTListMap.FindNodeOrInsertPos(ID, IP); | 
|  | if (!Result) { | 
|  | EVT *Array = Allocator.Allocate<EVT>(4); | 
|  | Array[0] = VT1; | 
|  | Array[1] = VT2; | 
|  | Array[2] = VT3; | 
|  | Array[3] = VT4; | 
|  | Result = new (Allocator) SDVTListNode(ID.Intern(Allocator), Array, 4); | 
|  | VTListMap.InsertNode(Result, IP); | 
|  | } | 
|  | return Result->getSDVTList(); | 
|  | } | 
|  |  | 
|  | SDVTList SelectionDAG::getVTList(ArrayRef<EVT> VTs) { | 
|  | unsigned NumVTs = VTs.size(); | 
|  | FoldingSetNodeID ID; | 
|  | ID.AddInteger(NumVTs); | 
|  | for (unsigned index = 0; index < NumVTs; index++) { | 
|  | ID.AddInteger(VTs[index].getRawBits()); | 
|  | } | 
|  |  | 
|  | void *IP = nullptr; | 
|  | SDVTListNode *Result = VTListMap.FindNodeOrInsertPos(ID, IP); | 
|  | if (!Result) { | 
|  | EVT *Array = Allocator.Allocate<EVT>(NumVTs); | 
|  | llvm::copy(VTs, Array); | 
|  | Result = new (Allocator) SDVTListNode(ID.Intern(Allocator), Array, NumVTs); | 
|  | VTListMap.InsertNode(Result, IP); | 
|  | } | 
|  | return Result->getSDVTList(); | 
|  | } | 
|  |  | 
|  |  | 
|  | /// UpdateNodeOperands - *Mutate* the specified node in-place to have the | 
|  | /// specified operands.  If the resultant node already exists in the DAG, | 
|  | /// this does not modify the specified node, instead it returns the node that | 
|  | /// already exists.  If the resultant node does not exist in the DAG, the | 
|  | /// input node is returned.  As a degenerate case, if you specify the same | 
|  | /// input operands as the node already has, the input node is returned. | 
|  | SDNode *SelectionDAG::UpdateNodeOperands(SDNode *N, SDValue Op) { | 
|  | assert(N->getNumOperands() == 1 && "Update with wrong number of operands"); | 
|  |  | 
|  | // Check to see if there is no change. | 
|  | if (Op == N->getOperand(0)) return N; | 
|  |  | 
|  | // See if the modified node already exists. | 
|  | void *InsertPos = nullptr; | 
|  | if (SDNode *Existing = FindModifiedNodeSlot(N, Op, InsertPos)) | 
|  | return Existing; | 
|  |  | 
|  | // Nope it doesn't.  Remove the node from its current place in the maps. | 
|  | if (InsertPos) | 
|  | if (!RemoveNodeFromCSEMaps(N)) | 
|  | InsertPos = nullptr; | 
|  |  | 
|  | // Now we update the operands. | 
|  | N->OperandList[0].set(Op); | 
|  |  | 
|  | updateDivergence(N); | 
|  | // If this gets put into a CSE map, add it. | 
|  | if (InsertPos) CSEMap.InsertNode(N, InsertPos); | 
|  | return N; | 
|  | } | 
|  |  | 
|  | SDNode *SelectionDAG::UpdateNodeOperands(SDNode *N, SDValue Op1, SDValue Op2) { | 
|  | assert(N->getNumOperands() == 2 && "Update with wrong number of operands"); | 
|  |  | 
|  | // Check to see if there is no change. | 
|  | if (Op1 == N->getOperand(0) && Op2 == N->getOperand(1)) | 
|  | return N;   // No operands changed, just return the input node. | 
|  |  | 
|  | // See if the modified node already exists. | 
|  | void *InsertPos = nullptr; | 
|  | if (SDNode *Existing = FindModifiedNodeSlot(N, Op1, Op2, InsertPos)) | 
|  | return Existing; | 
|  |  | 
|  | // Nope it doesn't.  Remove the node from its current place in the maps. | 
|  | if (InsertPos) | 
|  | if (!RemoveNodeFromCSEMaps(N)) | 
|  | InsertPos = nullptr; | 
|  |  | 
|  | // Now we update the operands. | 
|  | if (N->OperandList[0] != Op1) | 
|  | N->OperandList[0].set(Op1); | 
|  | if (N->OperandList[1] != Op2) | 
|  | N->OperandList[1].set(Op2); | 
|  |  | 
|  | updateDivergence(N); | 
|  | // If this gets put into a CSE map, add it. | 
|  | if (InsertPos) CSEMap.InsertNode(N, InsertPos); | 
|  | return N; | 
|  | } | 
|  |  | 
|  | SDNode *SelectionDAG:: | 
|  | UpdateNodeOperands(SDNode *N, SDValue Op1, SDValue Op2, SDValue Op3) { | 
|  | SDValue Ops[] = { Op1, Op2, Op3 }; | 
|  | return UpdateNodeOperands(N, Ops); | 
|  | } | 
|  |  | 
|  | SDNode *SelectionDAG:: | 
|  | UpdateNodeOperands(SDNode *N, SDValue Op1, SDValue Op2, | 
|  | SDValue Op3, SDValue Op4) { | 
|  | SDValue Ops[] = { Op1, Op2, Op3, Op4 }; | 
|  | return UpdateNodeOperands(N, Ops); | 
|  | } | 
|  |  | 
|  | SDNode *SelectionDAG:: | 
|  | UpdateNodeOperands(SDNode *N, SDValue Op1, SDValue Op2, | 
|  | SDValue Op3, SDValue Op4, SDValue Op5) { | 
|  | SDValue Ops[] = { Op1, Op2, Op3, Op4, Op5 }; | 
|  | return UpdateNodeOperands(N, Ops); | 
|  | } | 
|  |  | 
|  | SDNode *SelectionDAG:: | 
|  | UpdateNodeOperands(SDNode *N, ArrayRef<SDValue> Ops) { | 
|  | unsigned NumOps = Ops.size(); | 
|  | assert(N->getNumOperands() == NumOps && | 
|  | "Update with wrong number of operands"); | 
|  |  | 
|  | // If no operands changed just return the input node. | 
|  | if (std::equal(Ops.begin(), Ops.end(), N->op_begin())) | 
|  | return N; | 
|  |  | 
|  | // See if the modified node already exists. | 
|  | void *InsertPos = nullptr; | 
|  | if (SDNode *Existing = FindModifiedNodeSlot(N, Ops, InsertPos)) | 
|  | return Existing; | 
|  |  | 
|  | // Nope it doesn't.  Remove the node from its current place in the maps. | 
|  | if (InsertPos) | 
|  | if (!RemoveNodeFromCSEMaps(N)) | 
|  | InsertPos = nullptr; | 
|  |  | 
|  | // Now we update the operands. | 
|  | for (unsigned i = 0; i != NumOps; ++i) | 
|  | if (N->OperandList[i] != Ops[i]) | 
|  | N->OperandList[i].set(Ops[i]); | 
|  |  | 
|  | updateDivergence(N); | 
|  | // If this gets put into a CSE map, add it. | 
|  | if (InsertPos) CSEMap.InsertNode(N, InsertPos); | 
|  | return N; | 
|  | } | 
|  |  | 
|  | /// DropOperands - Release the operands and set this node to have | 
|  | /// zero operands. | 
|  | void SDNode::DropOperands() { | 
|  | // Unlike the code in MorphNodeTo that does this, we don't need to | 
|  | // watch for dead nodes here. | 
|  | for (op_iterator I = op_begin(), E = op_end(); I != E; ) { | 
|  | SDUse &Use = *I++; | 
|  | Use.set(SDValue()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SelectionDAG::setNodeMemRefs(MachineSDNode *N, | 
|  | ArrayRef<MachineMemOperand *> NewMemRefs) { | 
|  | if (NewMemRefs.empty()) { | 
|  | N->clearMemRefs(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Check if we can avoid allocating by storing a single reference directly. | 
|  | if (NewMemRefs.size() == 1) { | 
|  | N->MemRefs = NewMemRefs[0]; | 
|  | N->NumMemRefs = 1; | 
|  | return; | 
|  | } | 
|  |  | 
|  | MachineMemOperand **MemRefsBuffer = | 
|  | Allocator.template Allocate<MachineMemOperand *>(NewMemRefs.size()); | 
|  | llvm::copy(NewMemRefs, MemRefsBuffer); | 
|  | N->MemRefs = MemRefsBuffer; | 
|  | N->NumMemRefs = static_cast<int>(NewMemRefs.size()); | 
|  | } | 
|  |  | 
|  | /// SelectNodeTo - These are wrappers around MorphNodeTo that accept a | 
|  | /// machine opcode. | 
|  | /// | 
|  | SDNode *SelectionDAG::SelectNodeTo(SDNode *N, unsigned MachineOpc, | 
|  | EVT VT) { | 
|  | SDVTList VTs = getVTList(VT); | 
|  | return SelectNodeTo(N, MachineOpc, VTs, {}); | 
|  | } | 
|  |  | 
|  | SDNode *SelectionDAG::SelectNodeTo(SDNode *N, unsigned MachineOpc, | 
|  | EVT VT, SDValue Op1) { | 
|  | SDVTList VTs = getVTList(VT); | 
|  | SDValue Ops[] = { Op1 }; | 
|  | return SelectNodeTo(N, MachineOpc, VTs, Ops); | 
|  | } | 
|  |  | 
|  | SDNode *SelectionDAG::SelectNodeTo(SDNode *N, unsigned MachineOpc, | 
|  | EVT VT, SDValue Op1, | 
|  | SDValue Op2) { | 
|  | SDVTList VTs = getVTList(VT); | 
|  | SDValue Ops[] = { Op1, Op2 }; | 
|  | return SelectNodeTo(N, MachineOpc, VTs, Ops); | 
|  | } | 
|  |  | 
|  | SDNode *SelectionDAG::SelectNodeTo(SDNode *N, unsigned MachineOpc, | 
|  | EVT VT, SDValue Op1, | 
|  | SDValue Op2, SDValue Op3) { | 
|  | SDVTList VTs = getVTList(VT); | 
|  | SDValue Ops[] = { Op1, Op2, Op3 }; | 
|  | return SelectNodeTo(N, MachineOpc, VTs, Ops); | 
|  | } | 
|  |  | 
|  | SDNode *SelectionDAG::SelectNodeTo(SDNode *N, unsigned MachineOpc, | 
|  | EVT VT, ArrayRef<SDValue> Ops) { | 
|  | SDVTList VTs = getVTList(VT); | 
|  | return SelectNodeTo(N, MachineOpc, VTs, Ops); | 
|  | } | 
|  |  | 
|  | SDNode *SelectionDAG::SelectNodeTo(SDNode *N, unsigned MachineOpc, | 
|  | EVT VT1, EVT VT2, ArrayRef<SDValue> Ops) { | 
|  | SDVTList VTs = getVTList(VT1, VT2); | 
|  | return SelectNodeTo(N, MachineOpc, VTs, Ops); | 
|  | } | 
|  |  | 
|  | SDNode *SelectionDAG::SelectNodeTo(SDNode *N, unsigned MachineOpc, | 
|  | EVT VT1, EVT VT2) { | 
|  | SDVTList VTs = getVTList(VT1, VT2); | 
|  | return SelectNodeTo(N, MachineOpc, VTs, {}); | 
|  | } | 
|  |  | 
|  | SDNode *SelectionDAG::SelectNodeTo(SDNode *N, unsigned MachineOpc, | 
|  | EVT VT1, EVT VT2, EVT VT3, | 
|  | ArrayRef<SDValue> Ops) { | 
|  | SDVTList VTs = getVTList(VT1, VT2, VT3); | 
|  | return SelectNodeTo(N, MachineOpc, VTs, Ops); | 
|  | } | 
|  |  | 
|  | SDNode *SelectionDAG::SelectNodeTo(SDNode *N, unsigned MachineOpc, | 
|  | EVT VT1, EVT VT2, | 
|  | SDValue Op1, SDValue Op2) { | 
|  | SDVTList VTs = getVTList(VT1, VT2); | 
|  | SDValue Ops[] = { Op1, Op2 }; | 
|  | return SelectNodeTo(N, MachineOpc, VTs, Ops); | 
|  | } | 
|  |  | 
|  | SDNode *SelectionDAG::SelectNodeTo(SDNode *N, unsigned MachineOpc, | 
|  | SDVTList VTs,ArrayRef<SDValue> Ops) { | 
|  | SDNode *New = MorphNodeTo(N, ~MachineOpc, VTs, Ops); | 
|  | // Reset the NodeID to -1. | 
|  | New->setNodeId(-1); | 
|  | if (New != N) { | 
|  | ReplaceAllUsesWith(N, New); | 
|  | RemoveDeadNode(N); | 
|  | } | 
|  | return New; | 
|  | } | 
|  |  | 
|  | /// UpdateSDLocOnMergeSDNode - If the opt level is -O0 then it throws away | 
|  | /// the line number information on the merged node since it is not possible to | 
|  | /// preserve the information that operation is associated with multiple lines. | 
|  | /// This will make the debugger working better at -O0, were there is a higher | 
|  | /// probability having other instructions associated with that line. | 
|  | /// | 
|  | /// For IROrder, we keep the smaller of the two | 
|  | SDNode *SelectionDAG::UpdateSDLocOnMergeSDNode(SDNode *N, const SDLoc &OLoc) { | 
|  | DebugLoc NLoc = N->getDebugLoc(); | 
|  | if (NLoc && OptLevel == CodeGenOptLevel::None && OLoc.getDebugLoc() != NLoc) { | 
|  | N->setDebugLoc(DebugLoc()); | 
|  | } | 
|  | unsigned Order = std::min(N->getIROrder(), OLoc.getIROrder()); | 
|  | N->setIROrder(Order); | 
|  | return N; | 
|  | } | 
|  |  | 
|  | /// MorphNodeTo - This *mutates* the specified node to have the specified | 
|  | /// return type, opcode, and operands. | 
|  | /// | 
|  | /// Note that MorphNodeTo returns the resultant node.  If there is already a | 
|  | /// node of the specified opcode and operands, it returns that node instead of | 
|  | /// the current one.  Note that the SDLoc need not be the same. | 
|  | /// | 
|  | /// Using MorphNodeTo is faster than creating a new node and swapping it in | 
|  | /// with ReplaceAllUsesWith both because it often avoids allocating a new | 
|  | /// node, and because it doesn't require CSE recalculation for any of | 
|  | /// the node's users. | 
|  | /// | 
|  | /// However, note that MorphNodeTo recursively deletes dead nodes from the DAG. | 
|  | /// As a consequence it isn't appropriate to use from within the DAG combiner or | 
|  | /// the legalizer which maintain worklists that would need to be updated when | 
|  | /// deleting things. | 
|  | SDNode *SelectionDAG::MorphNodeTo(SDNode *N, unsigned Opc, | 
|  | SDVTList VTs, ArrayRef<SDValue> Ops) { | 
|  | // If an identical node already exists, use it. | 
|  | void *IP = nullptr; | 
|  | if (VTs.VTs[VTs.NumVTs-1] != MVT::Glue) { | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, Opc, VTs, Ops); | 
|  | if (SDNode *ON = FindNodeOrInsertPos(ID, SDLoc(N), IP)) | 
|  | return UpdateSDLocOnMergeSDNode(ON, SDLoc(N)); | 
|  | } | 
|  |  | 
|  | if (!RemoveNodeFromCSEMaps(N)) | 
|  | IP = nullptr; | 
|  |  | 
|  | // Start the morphing. | 
|  | N->NodeType = Opc; | 
|  | N->ValueList = VTs.VTs; | 
|  | N->NumValues = VTs.NumVTs; | 
|  |  | 
|  | // Clear the operands list, updating used nodes to remove this from their | 
|  | // use list.  Keep track of any operands that become dead as a result. | 
|  | SmallPtrSet<SDNode*, 16> DeadNodeSet; | 
|  | for (SDNode::op_iterator I = N->op_begin(), E = N->op_end(); I != E; ) { | 
|  | SDUse &Use = *I++; | 
|  | SDNode *Used = Use.getNode(); | 
|  | Use.set(SDValue()); | 
|  | if (Used->use_empty()) | 
|  | DeadNodeSet.insert(Used); | 
|  | } | 
|  |  | 
|  | // For MachineNode, initialize the memory references information. | 
|  | if (MachineSDNode *MN = dyn_cast<MachineSDNode>(N)) | 
|  | MN->clearMemRefs(); | 
|  |  | 
|  | // Swap for an appropriately sized array from the recycler. | 
|  | removeOperands(N); | 
|  | createOperands(N, Ops); | 
|  |  | 
|  | // Delete any nodes that are still dead after adding the uses for the | 
|  | // new operands. | 
|  | if (!DeadNodeSet.empty()) { | 
|  | SmallVector<SDNode *, 16> DeadNodes; | 
|  | for (SDNode *N : DeadNodeSet) | 
|  | if (N->use_empty()) | 
|  | DeadNodes.push_back(N); | 
|  | RemoveDeadNodes(DeadNodes); | 
|  | } | 
|  |  | 
|  | if (IP) | 
|  | CSEMap.InsertNode(N, IP);   // Memoize the new node. | 
|  | return N; | 
|  | } | 
|  |  | 
|  | SDNode* SelectionDAG::mutateStrictFPToFP(SDNode *Node) { | 
|  | unsigned OrigOpc = Node->getOpcode(); | 
|  | unsigned NewOpc; | 
|  | switch (OrigOpc) { | 
|  | default: | 
|  | llvm_unreachable("mutateStrictFPToFP called with unexpected opcode!"); | 
|  | #define DAG_INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC, DAGN)               \ | 
|  | case ISD::STRICT_##DAGN: NewOpc = ISD::DAGN; break; | 
|  | #define CMP_INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC, DAGN)               \ | 
|  | case ISD::STRICT_##DAGN: NewOpc = ISD::SETCC; break; | 
|  | #include "llvm/IR/ConstrainedOps.def" | 
|  | } | 
|  |  | 
|  | assert(Node->getNumValues() == 2 && "Unexpected number of results!"); | 
|  |  | 
|  | // We're taking this node out of the chain, so we need to re-link things. | 
|  | SDValue InputChain = Node->getOperand(0); | 
|  | SDValue OutputChain = SDValue(Node, 1); | 
|  | ReplaceAllUsesOfValueWith(OutputChain, InputChain); | 
|  |  | 
|  | SmallVector<SDValue, 3> Ops; | 
|  | for (unsigned i = 1, e = Node->getNumOperands(); i != e; ++i) | 
|  | Ops.push_back(Node->getOperand(i)); | 
|  |  | 
|  | SDVTList VTs = getVTList(Node->getValueType(0)); | 
|  | SDNode *Res = MorphNodeTo(Node, NewOpc, VTs, Ops); | 
|  |  | 
|  | // MorphNodeTo can operate in two ways: if an existing node with the | 
|  | // specified operands exists, it can just return it.  Otherwise, it | 
|  | // updates the node in place to have the requested operands. | 
|  | if (Res == Node) { | 
|  | // If we updated the node in place, reset the node ID.  To the isel, | 
|  | // this should be just like a newly allocated machine node. | 
|  | Res->setNodeId(-1); | 
|  | } else { | 
|  | ReplaceAllUsesWith(Node, Res); | 
|  | RemoveDeadNode(Node); | 
|  | } | 
|  |  | 
|  | return Res; | 
|  | } | 
|  |  | 
|  | /// getMachineNode - These are used for target selectors to create a new node | 
|  | /// with specified return type(s), MachineInstr opcode, and operands. | 
|  | /// | 
|  | /// Note that getMachineNode returns the resultant node.  If there is already a | 
|  | /// node of the specified opcode and operands, it returns that node instead of | 
|  | /// the current one. | 
|  | MachineSDNode *SelectionDAG::getMachineNode(unsigned Opcode, const SDLoc &dl, | 
|  | EVT VT) { | 
|  | SDVTList VTs = getVTList(VT); | 
|  | return getMachineNode(Opcode, dl, VTs, {}); | 
|  | } | 
|  |  | 
|  | MachineSDNode *SelectionDAG::getMachineNode(unsigned Opcode, const SDLoc &dl, | 
|  | EVT VT, SDValue Op1) { | 
|  | SDVTList VTs = getVTList(VT); | 
|  | SDValue Ops[] = { Op1 }; | 
|  | return getMachineNode(Opcode, dl, VTs, Ops); | 
|  | } | 
|  |  | 
|  | MachineSDNode *SelectionDAG::getMachineNode(unsigned Opcode, const SDLoc &dl, | 
|  | EVT VT, SDValue Op1, SDValue Op2) { | 
|  | SDVTList VTs = getVTList(VT); | 
|  | SDValue Ops[] = { Op1, Op2 }; | 
|  | return getMachineNode(Opcode, dl, VTs, Ops); | 
|  | } | 
|  |  | 
|  | MachineSDNode *SelectionDAG::getMachineNode(unsigned Opcode, const SDLoc &dl, | 
|  | EVT VT, SDValue Op1, SDValue Op2, | 
|  | SDValue Op3) { | 
|  | SDVTList VTs = getVTList(VT); | 
|  | SDValue Ops[] = { Op1, Op2, Op3 }; | 
|  | return getMachineNode(Opcode, dl, VTs, Ops); | 
|  | } | 
|  |  | 
|  | MachineSDNode *SelectionDAG::getMachineNode(unsigned Opcode, const SDLoc &dl, | 
|  | EVT VT, ArrayRef<SDValue> Ops) { | 
|  | SDVTList VTs = getVTList(VT); | 
|  | return getMachineNode(Opcode, dl, VTs, Ops); | 
|  | } | 
|  |  | 
|  | MachineSDNode *SelectionDAG::getMachineNode(unsigned Opcode, const SDLoc &dl, | 
|  | EVT VT1, EVT VT2, SDValue Op1, | 
|  | SDValue Op2) { | 
|  | SDVTList VTs = getVTList(VT1, VT2); | 
|  | SDValue Ops[] = { Op1, Op2 }; | 
|  | return getMachineNode(Opcode, dl, VTs, Ops); | 
|  | } | 
|  |  | 
|  | MachineSDNode *SelectionDAG::getMachineNode(unsigned Opcode, const SDLoc &dl, | 
|  | EVT VT1, EVT VT2, SDValue Op1, | 
|  | SDValue Op2, SDValue Op3) { | 
|  | SDVTList VTs = getVTList(VT1, VT2); | 
|  | SDValue Ops[] = { Op1, Op2, Op3 }; | 
|  | return getMachineNode(Opcode, dl, VTs, Ops); | 
|  | } | 
|  |  | 
|  | MachineSDNode *SelectionDAG::getMachineNode(unsigned Opcode, const SDLoc &dl, | 
|  | EVT VT1, EVT VT2, | 
|  | ArrayRef<SDValue> Ops) { | 
|  | SDVTList VTs = getVTList(VT1, VT2); | 
|  | return getMachineNode(Opcode, dl, VTs, Ops); | 
|  | } | 
|  |  | 
|  | MachineSDNode *SelectionDAG::getMachineNode(unsigned Opcode, const SDLoc &dl, | 
|  | EVT VT1, EVT VT2, EVT VT3, | 
|  | SDValue Op1, SDValue Op2) { | 
|  | SDVTList VTs = getVTList(VT1, VT2, VT3); | 
|  | SDValue Ops[] = { Op1, Op2 }; | 
|  | return getMachineNode(Opcode, dl, VTs, Ops); | 
|  | } | 
|  |  | 
|  | MachineSDNode *SelectionDAG::getMachineNode(unsigned Opcode, const SDLoc &dl, | 
|  | EVT VT1, EVT VT2, EVT VT3, | 
|  | SDValue Op1, SDValue Op2, | 
|  | SDValue Op3) { | 
|  | SDVTList VTs = getVTList(VT1, VT2, VT3); | 
|  | SDValue Ops[] = { Op1, Op2, Op3 }; | 
|  | return getMachineNode(Opcode, dl, VTs, Ops); | 
|  | } | 
|  |  | 
|  | MachineSDNode *SelectionDAG::getMachineNode(unsigned Opcode, const SDLoc &dl, | 
|  | EVT VT1, EVT VT2, EVT VT3, | 
|  | ArrayRef<SDValue> Ops) { | 
|  | SDVTList VTs = getVTList(VT1, VT2, VT3); | 
|  | return getMachineNode(Opcode, dl, VTs, Ops); | 
|  | } | 
|  |  | 
|  | MachineSDNode *SelectionDAG::getMachineNode(unsigned Opcode, const SDLoc &dl, | 
|  | ArrayRef<EVT> ResultTys, | 
|  | ArrayRef<SDValue> Ops) { | 
|  | SDVTList VTs = getVTList(ResultTys); | 
|  | return getMachineNode(Opcode, dl, VTs, Ops); | 
|  | } | 
|  |  | 
|  | MachineSDNode *SelectionDAG::getMachineNode(unsigned Opcode, const SDLoc &DL, | 
|  | SDVTList VTs, | 
|  | ArrayRef<SDValue> Ops) { | 
|  | bool DoCSE = VTs.VTs[VTs.NumVTs-1] != MVT::Glue; | 
|  | MachineSDNode *N; | 
|  | void *IP = nullptr; | 
|  |  | 
|  | if (DoCSE) { | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, ~Opcode, VTs, Ops); | 
|  | IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, DL, IP)) { | 
|  | return cast<MachineSDNode>(UpdateSDLocOnMergeSDNode(E, DL)); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Allocate a new MachineSDNode. | 
|  | N = newSDNode<MachineSDNode>(~Opcode, DL.getIROrder(), DL.getDebugLoc(), VTs); | 
|  | createOperands(N, Ops); | 
|  |  | 
|  | if (DoCSE) | 
|  | CSEMap.InsertNode(N, IP); | 
|  |  | 
|  | InsertNode(N); | 
|  | NewSDValueDbgMsg(SDValue(N, 0), "Creating new machine node: ", this); | 
|  | return N; | 
|  | } | 
|  |  | 
|  | /// getTargetExtractSubreg - A convenience function for creating | 
|  | /// TargetOpcode::EXTRACT_SUBREG nodes. | 
|  | SDValue SelectionDAG::getTargetExtractSubreg(int SRIdx, const SDLoc &DL, EVT VT, | 
|  | SDValue Operand) { | 
|  | SDValue SRIdxVal = getTargetConstant(SRIdx, DL, MVT::i32); | 
|  | SDNode *Subreg = getMachineNode(TargetOpcode::EXTRACT_SUBREG, DL, | 
|  | VT, Operand, SRIdxVal); | 
|  | return SDValue(Subreg, 0); | 
|  | } | 
|  |  | 
|  | /// getTargetInsertSubreg - A convenience function for creating | 
|  | /// TargetOpcode::INSERT_SUBREG nodes. | 
|  | SDValue SelectionDAG::getTargetInsertSubreg(int SRIdx, const SDLoc &DL, EVT VT, | 
|  | SDValue Operand, SDValue Subreg) { | 
|  | SDValue SRIdxVal = getTargetConstant(SRIdx, DL, MVT::i32); | 
|  | SDNode *Result = getMachineNode(TargetOpcode::INSERT_SUBREG, DL, | 
|  | VT, Operand, Subreg, SRIdxVal); | 
|  | return SDValue(Result, 0); | 
|  | } | 
|  |  | 
|  | /// getNodeIfExists - Get the specified node if it's already available, or | 
|  | /// else return NULL. | 
|  | SDNode *SelectionDAG::getNodeIfExists(unsigned Opcode, SDVTList VTList, | 
|  | ArrayRef<SDValue> Ops) { | 
|  | SDNodeFlags Flags; | 
|  | if (Inserter) | 
|  | Flags = Inserter->getFlags(); | 
|  | return getNodeIfExists(Opcode, VTList, Ops, Flags); | 
|  | } | 
|  |  | 
|  | SDNode *SelectionDAG::getNodeIfExists(unsigned Opcode, SDVTList VTList, | 
|  | ArrayRef<SDValue> Ops, | 
|  | const SDNodeFlags Flags) { | 
|  | if (VTList.VTs[VTList.NumVTs - 1] != MVT::Glue) { | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, Opcode, VTList, Ops); | 
|  | void *IP = nullptr; | 
|  | if (SDNode *E = FindNodeOrInsertPos(ID, SDLoc(), IP)) { | 
|  | E->intersectFlagsWith(Flags); | 
|  | return E; | 
|  | } | 
|  | } | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | /// doesNodeExist - Check if a node exists without modifying its flags. | 
|  | bool SelectionDAG::doesNodeExist(unsigned Opcode, SDVTList VTList, | 
|  | ArrayRef<SDValue> Ops) { | 
|  | if (VTList.VTs[VTList.NumVTs - 1] != MVT::Glue) { | 
|  | FoldingSetNodeID ID; | 
|  | AddNodeIDNode(ID, Opcode, VTList, Ops); | 
|  | void *IP = nullptr; | 
|  | if (FindNodeOrInsertPos(ID, SDLoc(), IP)) | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /// getDbgValue - Creates a SDDbgValue node. | 
|  | /// | 
|  | /// SDNode | 
|  | SDDbgValue *SelectionDAG::getDbgValue(DIVariable *Var, DIExpression *Expr, | 
|  | SDNode *N, unsigned R, bool IsIndirect, | 
|  | const DebugLoc &DL, unsigned O) { | 
|  | assert(cast<DILocalVariable>(Var)->isValidLocationForIntrinsic(DL) && | 
|  | "Expected inlined-at fields to agree"); | 
|  | return new (DbgInfo->getAlloc()) | 
|  | SDDbgValue(DbgInfo->getAlloc(), Var, Expr, SDDbgOperand::fromNode(N, R), | 
|  | {}, IsIndirect, DL, O, | 
|  | /*IsVariadic=*/false); | 
|  | } | 
|  |  | 
|  | /// Constant | 
|  | SDDbgValue *SelectionDAG::getConstantDbgValue(DIVariable *Var, | 
|  | DIExpression *Expr, | 
|  | const Value *C, | 
|  | const DebugLoc &DL, unsigned O) { | 
|  | assert(cast<DILocalVariable>(Var)->isValidLocationForIntrinsic(DL) && | 
|  | "Expected inlined-at fields to agree"); | 
|  | return new (DbgInfo->getAlloc()) | 
|  | SDDbgValue(DbgInfo->getAlloc(), Var, Expr, SDDbgOperand::fromConst(C), {}, | 
|  | /*IsIndirect=*/false, DL, O, | 
|  | /*IsVariadic=*/false); | 
|  | } | 
|  |  | 
|  | /// FrameIndex | 
|  | SDDbgValue *SelectionDAG::getFrameIndexDbgValue(DIVariable *Var, | 
|  | DIExpression *Expr, unsigned FI, | 
|  | bool IsIndirect, | 
|  | const DebugLoc &DL, | 
|  | unsigned O) { | 
|  | assert(cast<DILocalVariable>(Var)->isValidLocationForIntrinsic(DL) && | 
|  | "Expected inlined-at fields to agree"); | 
|  | return getFrameIndexDbgValue(Var, Expr, FI, {}, IsIndirect, DL, O); | 
|  | } | 
|  |  | 
|  | /// FrameIndex with dependencies | 
|  | SDDbgValue *SelectionDAG::getFrameIndexDbgValue(DIVariable *Var, | 
|  | DIExpression *Expr, unsigned FI, | 
|  | ArrayRef<SDNode *> Dependencies, | 
|  | bool IsIndirect, | 
|  | const DebugLoc &DL, | 
|  | unsigned O) { | 
|  | assert(cast<DILocalVariable>(Var)->isValidLocationForIntrinsic(DL) && | 
|  | "Expected inlined-at fields to agree"); | 
|  | return new (DbgInfo->getAlloc()) | 
|  | SDDbgValue(DbgInfo->getAlloc(), Var, Expr, SDDbgOperand::fromFrameIdx(FI), | 
|  | Dependencies, IsIndirect, DL, O, | 
|  | /*IsVariadic=*/false); | 
|  | } | 
|  |  | 
|  | /// VReg | 
|  | SDDbgValue *SelectionDAG::getVRegDbgValue(DIVariable *Var, DIExpression *Expr, | 
|  | Register VReg, bool IsIndirect, | 
|  | const DebugLoc &DL, unsigned O) { | 
|  | assert(cast<DILocalVariable>(Var)->isValidLocationForIntrinsic(DL) && | 
|  | "Expected inlined-at fields to agree"); | 
|  | return new (DbgInfo->getAlloc()) | 
|  | SDDbgValue(DbgInfo->getAlloc(), Var, Expr, SDDbgOperand::fromVReg(VReg), | 
|  | {}, IsIndirect, DL, O, | 
|  | /*IsVariadic=*/false); | 
|  | } | 
|  |  | 
|  | SDDbgValue *SelectionDAG::getDbgValueList(DIVariable *Var, DIExpression *Expr, | 
|  | ArrayRef<SDDbgOperand> Locs, | 
|  | ArrayRef<SDNode *> Dependencies, | 
|  | bool IsIndirect, const DebugLoc &DL, | 
|  | unsigned O, bool IsVariadic) { | 
|  | assert(cast<DILocalVariable>(Var)->isValidLocationForIntrinsic(DL) && | 
|  | "Expected inlined-at fields to agree"); | 
|  | return new (DbgInfo->getAlloc()) | 
|  | SDDbgValue(DbgInfo->getAlloc(), Var, Expr, Locs, Dependencies, IsIndirect, | 
|  | DL, O, IsVariadic); | 
|  | } | 
|  |  | 
|  | void SelectionDAG::transferDbgValues(SDValue From, SDValue To, | 
|  | unsigned OffsetInBits, unsigned SizeInBits, | 
|  | bool InvalidateDbg) { | 
|  | SDNode *FromNode = From.getNode(); | 
|  | SDNode *ToNode = To.getNode(); | 
|  | assert(FromNode && ToNode && "Can't modify dbg values"); | 
|  |  | 
|  | // PR35338 | 
|  | // TODO: assert(From != To && "Redundant dbg value transfer"); | 
|  | // TODO: assert(FromNode != ToNode && "Intranode dbg value transfer"); | 
|  | if (From == To || FromNode == ToNode) | 
|  | return; | 
|  |  | 
|  | if (!FromNode->getHasDebugValue()) | 
|  | return; | 
|  |  | 
|  | SDDbgOperand FromLocOp = | 
|  | SDDbgOperand::fromNode(From.getNode(), From.getResNo()); | 
|  | SDDbgOperand ToLocOp = SDDbgOperand::fromNode(To.getNode(), To.getResNo()); | 
|  |  | 
|  | SmallVector<SDDbgValue *, 2> ClonedDVs; | 
|  | for (SDDbgValue *Dbg : GetDbgValues(FromNode)) { | 
|  | if (Dbg->isInvalidated()) | 
|  | continue; | 
|  |  | 
|  | // TODO: assert(!Dbg->isInvalidated() && "Transfer of invalid dbg value"); | 
|  |  | 
|  | // Create a new location ops vector that is equal to the old vector, but | 
|  | // with each instance of FromLocOp replaced with ToLocOp. | 
|  | bool Changed = false; | 
|  | auto NewLocOps = Dbg->copyLocationOps(); | 
|  | std::replace_if( | 
|  | NewLocOps.begin(), NewLocOps.end(), | 
|  | [&Changed, FromLocOp](const SDDbgOperand &Op) { | 
|  | bool Match = Op == FromLocOp; | 
|  | Changed |= Match; | 
|  | return Match; | 
|  | }, | 
|  | ToLocOp); | 
|  | // Ignore this SDDbgValue if we didn't find a matching location. | 
|  | if (!Changed) | 
|  | continue; | 
|  |  | 
|  | DIVariable *Var = Dbg->getVariable(); | 
|  | auto *Expr = Dbg->getExpression(); | 
|  | // If a fragment is requested, update the expression. | 
|  | if (SizeInBits) { | 
|  | // When splitting a larger (e.g., sign-extended) value whose | 
|  | // lower bits are described with an SDDbgValue, do not attempt | 
|  | // to transfer the SDDbgValue to the upper bits. | 
|  | if (auto FI = Expr->getFragmentInfo()) | 
|  | if (OffsetInBits + SizeInBits > FI->SizeInBits) | 
|  | continue; | 
|  | auto Fragment = DIExpression::createFragmentExpression(Expr, OffsetInBits, | 
|  | SizeInBits); | 
|  | if (!Fragment) | 
|  | continue; | 
|  | Expr = *Fragment; | 
|  | } | 
|  |  | 
|  | auto AdditionalDependencies = Dbg->getAdditionalDependencies(); | 
|  | // Clone the SDDbgValue and move it to To. | 
|  | SDDbgValue *Clone = getDbgValueList( | 
|  | Var, Expr, NewLocOps, AdditionalDependencies, Dbg->isIndirect(), | 
|  | Dbg->getDebugLoc(), std::max(ToNode->getIROrder(), Dbg->getOrder()), | 
|  | Dbg->isVariadic()); | 
|  | ClonedDVs.push_back(Clone); | 
|  |  | 
|  | if (InvalidateDbg) { | 
|  | // Invalidate value and indicate the SDDbgValue should not be emitted. | 
|  | Dbg->setIsInvalidated(); | 
|  | Dbg->setIsEmitted(); | 
|  | } | 
|  | } | 
|  |  | 
|  | for (SDDbgValue *Dbg : ClonedDVs) { | 
|  | assert(is_contained(Dbg->getSDNodes(), ToNode) && | 
|  | "Transferred DbgValues should depend on the new SDNode"); | 
|  | AddDbgValue(Dbg, false); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SelectionDAG::salvageDebugInfo(SDNode &N) { | 
|  | if (!N.getHasDebugValue()) | 
|  | return; | 
|  |  | 
|  | auto GetLocationOperand = [](SDNode *Node, unsigned ResNo) { | 
|  | if (auto *FISDN = dyn_cast<FrameIndexSDNode>(Node)) | 
|  | return SDDbgOperand::fromFrameIdx(FISDN->getIndex()); | 
|  | return SDDbgOperand::fromNode(Node, ResNo); | 
|  | }; | 
|  |  | 
|  | SmallVector<SDDbgValue *, 2> ClonedDVs; | 
|  | for (auto *DV : GetDbgValues(&N)) { | 
|  | if (DV->isInvalidated()) | 
|  | continue; | 
|  | switch (N.getOpcode()) { | 
|  | default: | 
|  | break; | 
|  | case ISD::ADD: { | 
|  | SDValue N0 = N.getOperand(0); | 
|  | SDValue N1 = N.getOperand(1); | 
|  | if (!isa<ConstantSDNode>(N0)) { | 
|  | bool RHSConstant = isa<ConstantSDNode>(N1); | 
|  | uint64_t Offset; | 
|  | if (RHSConstant) | 
|  | Offset = N.getConstantOperandVal(1); | 
|  | // We are not allowed to turn indirect debug values variadic, so | 
|  | // don't salvage those. | 
|  | if (!RHSConstant && DV->isIndirect()) | 
|  | continue; | 
|  |  | 
|  | // Rewrite an ADD constant node into a DIExpression. Since we are | 
|  | // performing arithmetic to compute the variable's *value* in the | 
|  | // DIExpression, we need to mark the expression with a | 
|  | // DW_OP_stack_value. | 
|  | auto *DIExpr = DV->getExpression(); | 
|  | auto NewLocOps = DV->copyLocationOps(); | 
|  | bool Changed = false; | 
|  | size_t OrigLocOpsSize = NewLocOps.size(); | 
|  | for (size_t i = 0; i < OrigLocOpsSize; ++i) { | 
|  | // We're not given a ResNo to compare against because the whole | 
|  | // node is going away. We know that any ISD::ADD only has one | 
|  | // result, so we can assume any node match is using the result. | 
|  | if (NewLocOps[i].getKind() != SDDbgOperand::SDNODE || | 
|  | NewLocOps[i].getSDNode() != &N) | 
|  | continue; | 
|  | NewLocOps[i] = GetLocationOperand(N0.getNode(), N0.getResNo()); | 
|  | if (RHSConstant) { | 
|  | SmallVector<uint64_t, 3> ExprOps; | 
|  | DIExpression::appendOffset(ExprOps, Offset); | 
|  | DIExpr = DIExpression::appendOpsToArg(DIExpr, ExprOps, i, true); | 
|  | } else { | 
|  | // Convert to a variadic expression (if not already). | 
|  | // convertToVariadicExpression() returns a const pointer, so we use | 
|  | // a temporary const variable here. | 
|  | const auto *TmpDIExpr = | 
|  | DIExpression::convertToVariadicExpression(DIExpr); | 
|  | SmallVector<uint64_t, 3> ExprOps; | 
|  | ExprOps.push_back(dwarf::DW_OP_LLVM_arg); | 
|  | ExprOps.push_back(NewLocOps.size()); | 
|  | ExprOps.push_back(dwarf::DW_OP_plus); | 
|  | SDDbgOperand RHS = | 
|  | SDDbgOperand::fromNode(N1.getNode(), N1.getResNo()); | 
|  | NewLocOps.push_back(RHS); | 
|  | DIExpr = DIExpression::appendOpsToArg(TmpDIExpr, ExprOps, i, true); | 
|  | } | 
|  | Changed = true; | 
|  | } | 
|  | (void)Changed; | 
|  | assert(Changed && "Salvage target doesn't use N"); | 
|  |  | 
|  | bool IsVariadic = | 
|  | DV->isVariadic() || OrigLocOpsSize != NewLocOps.size(); | 
|  |  | 
|  | auto AdditionalDependencies = DV->getAdditionalDependencies(); | 
|  | SDDbgValue *Clone = getDbgValueList( | 
|  | DV->getVariable(), DIExpr, NewLocOps, AdditionalDependencies, | 
|  | DV->isIndirect(), DV->getDebugLoc(), DV->getOrder(), IsVariadic); | 
|  | ClonedDVs.push_back(Clone); | 
|  | DV->setIsInvalidated(); | 
|  | DV->setIsEmitted(); | 
|  | LLVM_DEBUG(dbgs() << "SALVAGE: Rewriting"; | 
|  | N0.getNode()->dumprFull(this); | 
|  | dbgs() << " into " << *DIExpr << '\n'); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case ISD::TRUNCATE: { | 
|  | SDValue N0 = N.getOperand(0); | 
|  | TypeSize FromSize = N0.getValueSizeInBits(); | 
|  | TypeSize ToSize = N.getValueSizeInBits(0); | 
|  |  | 
|  | DIExpression *DbgExpression = DV->getExpression(); | 
|  | auto ExtOps = DIExpression::getExtOps(FromSize, ToSize, false); | 
|  | auto NewLocOps = DV->copyLocationOps(); | 
|  | bool Changed = false; | 
|  | for (size_t i = 0; i < NewLocOps.size(); ++i) { | 
|  | if (NewLocOps[i].getKind() != SDDbgOperand::SDNODE || | 
|  | NewLocOps[i].getSDNode() != &N) | 
|  | continue; | 
|  |  | 
|  | NewLocOps[i] = GetLocationOperand(N0.getNode(), N0.getResNo()); | 
|  | DbgExpression = DIExpression::appendOpsToArg(DbgExpression, ExtOps, i); | 
|  | Changed = true; | 
|  | } | 
|  | assert(Changed && "Salvage target doesn't use N"); | 
|  | (void)Changed; | 
|  |  | 
|  | SDDbgValue *Clone = | 
|  | getDbgValueList(DV->getVariable(), DbgExpression, NewLocOps, | 
|  | DV->getAdditionalDependencies(), DV->isIndirect(), | 
|  | DV->getDebugLoc(), DV->getOrder(), DV->isVariadic()); | 
|  |  | 
|  | ClonedDVs.push_back(Clone); | 
|  | DV->setIsInvalidated(); | 
|  | DV->setIsEmitted(); | 
|  | LLVM_DEBUG(dbgs() << "SALVAGE: Rewriting"; N0.getNode()->dumprFull(this); | 
|  | dbgs() << " into " << *DbgExpression << '\n'); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | for (SDDbgValue *Dbg : ClonedDVs) { | 
|  | assert((!Dbg->getSDNodes().empty() || | 
|  | llvm::any_of(Dbg->getLocationOps(), | 
|  | [&](const SDDbgOperand &Op) { | 
|  | return Op.getKind() == SDDbgOperand::FRAMEIX; | 
|  | })) && | 
|  | "Salvaged DbgValue should depend on a new SDNode"); | 
|  | AddDbgValue(Dbg, false); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Creates a SDDbgLabel node. | 
|  | SDDbgLabel *SelectionDAG::getDbgLabel(DILabel *Label, | 
|  | const DebugLoc &DL, unsigned O) { | 
|  | assert(cast<DILabel>(Label)->isValidLocationForIntrinsic(DL) && | 
|  | "Expected inlined-at fields to agree"); | 
|  | return new (DbgInfo->getAlloc()) SDDbgLabel(Label, DL, O); | 
|  | } | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | /// RAUWUpdateListener - Helper for ReplaceAllUsesWith - When the node | 
|  | /// pointed to by a use iterator is deleted, increment the use iterator | 
|  | /// so that it doesn't dangle. | 
|  | /// | 
|  | class RAUWUpdateListener : public SelectionDAG::DAGUpdateListener { | 
|  | SDNode::use_iterator &UI; | 
|  | SDNode::use_iterator &UE; | 
|  |  | 
|  | void NodeDeleted(SDNode *N, SDNode *E) override { | 
|  | // Increment the iterator as needed. | 
|  | while (UI != UE && N == UI->getUser()) | 
|  | ++UI; | 
|  | } | 
|  |  | 
|  | public: | 
|  | RAUWUpdateListener(SelectionDAG &d, | 
|  | SDNode::use_iterator &ui, | 
|  | SDNode::use_iterator &ue) | 
|  | : SelectionDAG::DAGUpdateListener(d), UI(ui), UE(ue) {} | 
|  | }; | 
|  |  | 
|  | } // end anonymous namespace | 
|  |  | 
|  | /// ReplaceAllUsesWith - Modify anything using 'From' to use 'To' instead. | 
|  | /// This can cause recursive merging of nodes in the DAG. | 
|  | /// | 
|  | /// This version assumes From has a single result value. | 
|  | /// | 
|  | void SelectionDAG::ReplaceAllUsesWith(SDValue FromN, SDValue To) { | 
|  | SDNode *From = FromN.getNode(); | 
|  | assert(From->getNumValues() == 1 && FromN.getResNo() == 0 && | 
|  | "Cannot replace with this method!"); | 
|  | assert(From != To.getNode() && "Cannot replace uses of with self"); | 
|  |  | 
|  | // Preserve Debug Values | 
|  | transferDbgValues(FromN, To); | 
|  | // Preserve extra info. | 
|  | copyExtraInfo(From, To.getNode()); | 
|  |  | 
|  | // Iterate over all the existing uses of From. New uses will be added | 
|  | // to the beginning of the use list, which we avoid visiting. | 
|  | // This specifically avoids visiting uses of From that arise while the | 
|  | // replacement is happening, because any such uses would be the result | 
|  | // of CSE: If an existing node looks like From after one of its operands | 
|  | // is replaced by To, we don't want to replace of all its users with To | 
|  | // too. See PR3018 for more info. | 
|  | SDNode::use_iterator UI = From->use_begin(), UE = From->use_end(); | 
|  | RAUWUpdateListener Listener(*this, UI, UE); | 
|  | while (UI != UE) { | 
|  | SDNode *User = UI->getUser(); | 
|  |  | 
|  | // This node is about to morph, remove its old self from the CSE maps. | 
|  | RemoveNodeFromCSEMaps(User); | 
|  |  | 
|  | // A user can appear in a use list multiple times, and when this | 
|  | // happens the uses are usually next to each other in the list. | 
|  | // To help reduce the number of CSE recomputations, process all | 
|  | // the uses of this user that we can find this way. | 
|  | do { | 
|  | SDUse &Use = *UI; | 
|  | ++UI; | 
|  | Use.set(To); | 
|  | if (To->isDivergent() != From->isDivergent()) | 
|  | updateDivergence(User); | 
|  | } while (UI != UE && UI->getUser() == User); | 
|  | // Now that we have modified User, add it back to the CSE maps.  If it | 
|  | // already exists there, recursively merge the results together. | 
|  | AddModifiedNodeToCSEMaps(User); | 
|  | } | 
|  |  | 
|  | // If we just RAUW'd the root, take note. | 
|  | if (FromN == getRoot()) | 
|  | setRoot(To); | 
|  | } | 
|  |  | 
|  | /// ReplaceAllUsesWith - Modify anything using 'From' to use 'To' instead. | 
|  | /// This can cause recursive merging of nodes in the DAG. | 
|  | /// | 
|  | /// This version assumes that for each value of From, there is a | 
|  | /// corresponding value in To in the same position with the same type. | 
|  | /// | 
|  | void SelectionDAG::ReplaceAllUsesWith(SDNode *From, SDNode *To) { | 
|  | #ifndef NDEBUG | 
|  | for (unsigned i = 0, e = From->getNumValues(); i != e; ++i) | 
|  | assert((!From->hasAnyUseOfValue(i) || | 
|  | From->getValueType(i) == To->getValueType(i)) && | 
|  | "Cannot use this version of ReplaceAllUsesWith!"); | 
|  | #endif | 
|  |  | 
|  | // Handle the trivial case. | 
|  | if (From == To) | 
|  | return; | 
|  |  | 
|  | // Preserve Debug Info. Only do this if there's a use. | 
|  | for (unsigned i = 0, e = From->getNumValues(); i != e; ++i) | 
|  | if (From->hasAnyUseOfValue(i)) { | 
|  | assert((i < To->getNumValues()) && "Invalid To location"); | 
|  | transferDbgValues(SDValue(From, i), SDValue(To, i)); | 
|  | } | 
|  | // Preserve extra info. | 
|  | copyExtraInfo(From, To); | 
|  |  | 
|  | // Iterate over just the existing users of From. See the comments in | 
|  | // the ReplaceAllUsesWith above. | 
|  | SDNode::use_iterator UI = From->use_begin(), UE = From->use_end(); | 
|  | RAUWUpdateListener Listener(*this, UI, UE); | 
|  | while (UI != UE) { | 
|  | SDNode *User = UI->getUser(); | 
|  |  | 
|  | // This node is about to morph, remove its old self from the CSE maps. | 
|  | RemoveNodeFromCSEMaps(User); | 
|  |  | 
|  | // A user can appear in a use list multiple times, and when this | 
|  | // happens the uses are usually next to each other in the list. | 
|  | // To help reduce the number of CSE recomputations, process all | 
|  | // the uses of this user that we can find this way. | 
|  | do { | 
|  | SDUse &Use = *UI; | 
|  | ++UI; | 
|  | Use.setNode(To); | 
|  | if (To->isDivergent() != From->isDivergent()) | 
|  | updateDivergence(User); | 
|  | } while (UI != UE && UI->getUser() == User); | 
|  |  | 
|  | // Now that we have modified User, add it back to the CSE maps.  If it | 
|  | // already exists there, recursively merge the results together. | 
|  | AddModifiedNodeToCSEMaps(User); | 
|  | } | 
|  |  | 
|  | // If we just RAUW'd the root, take note. | 
|  | if (From == getRoot().getNode()) | 
|  | setRoot(SDValue(To, getRoot().getResNo())); | 
|  | } | 
|  |  | 
|  | /// ReplaceAllUsesWith - Modify anything using 'From' to use 'To' instead. | 
|  | /// This can cause recursive merging of nodes in the DAG. | 
|  | /// | 
|  | /// This version can replace From with any result values.  To must match the | 
|  | /// number and types of values returned by From. | 
|  | void SelectionDAG::ReplaceAllUsesWith(SDNode *From, const SDValue *To) { | 
|  | if (From->getNumValues() == 1)  // Handle the simple case efficiently. | 
|  | return ReplaceAllUsesWith(SDValue(From, 0), To[0]); | 
|  |  | 
|  | for (unsigned i = 0, e = From->getNumValues(); i != e; ++i) { | 
|  | // Preserve Debug Info. | 
|  | transferDbgValues(SDValue(From, i), To[i]); | 
|  | // Preserve extra info. | 
|  | copyExtraInfo(From, To[i].getNode()); | 
|  | } | 
|  |  | 
|  | // Iterate over just the existing users of From. See the comments in | 
|  | // the ReplaceAllUsesWith above. | 
|  | SDNode::use_iterator UI = From->use_begin(), UE = From->use_end(); | 
|  | RAUWUpdateListener Listener(*this, UI, UE); | 
|  | while (UI != UE) { | 
|  | SDNode *User = UI->getUser(); | 
|  |  | 
|  | // This node is about to morph, remove its old self from the CSE maps. | 
|  | RemoveNodeFromCSEMaps(User); | 
|  |  | 
|  | // A user can appear in a use list multiple times, and when this happens the | 
|  | // uses are usually next to each other in the list.  To help reduce the | 
|  | // number of CSE and divergence recomputations, process all the uses of this | 
|  | // user that we can find this way. | 
|  | bool To_IsDivergent = false; | 
|  | do { | 
|  | SDUse &Use = *UI; | 
|  | const SDValue &ToOp = To[Use.getResNo()]; | 
|  | ++UI; | 
|  | Use.set(ToOp); | 
|  | To_IsDivergent |= ToOp->isDivergent(); | 
|  | } while (UI != UE && UI->getUser() == User); | 
|  |  | 
|  | if (To_IsDivergent != From->isDivergent()) | 
|  | updateDivergence(User); | 
|  |  | 
|  | // Now that we have modified User, add it back to the CSE maps.  If it | 
|  | // already exists there, recursively merge the results together. | 
|  | AddModifiedNodeToCSEMaps(User); | 
|  | } | 
|  |  | 
|  | // If we just RAUW'd the root, take note. | 
|  | if (From == getRoot().getNode()) | 
|  | setRoot(SDValue(To[getRoot().getResNo()])); | 
|  | } | 
|  |  | 
|  | /// ReplaceAllUsesOfValueWith - Replace any uses of From with To, leaving | 
|  | /// uses of other values produced by From.getNode() alone.  The Deleted | 
|  | /// vector is handled the same way as for ReplaceAllUsesWith. | 
|  | void SelectionDAG::ReplaceAllUsesOfValueWith(SDValue From, SDValue To){ | 
|  | // Handle the really simple, really trivial case efficiently. | 
|  | if (From == To) return; | 
|  |  | 
|  | // Handle the simple, trivial, case efficiently. | 
|  | if (From.getNode()->getNumValues() == 1) { | 
|  | ReplaceAllUsesWith(From, To); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Preserve Debug Info. | 
|  | transferDbgValues(From, To); | 
|  | copyExtraInfo(From.getNode(), To.getNode()); | 
|  |  | 
|  | // Iterate over just the existing users of From. See the comments in | 
|  | // the ReplaceAllUsesWith above. | 
|  | SDNode::use_iterator UI = From.getNode()->use_begin(), | 
|  | UE = From.getNode()->use_end(); | 
|  | RAUWUpdateListener Listener(*this, UI, UE); | 
|  | while (UI != UE) { | 
|  | SDNode *User = UI->getUser(); | 
|  | bool UserRemovedFromCSEMaps = false; | 
|  |  | 
|  | // A user can appear in a use list multiple times, and when this | 
|  | // happens the uses are usually next to each other in the list. | 
|  | // To help reduce the number of CSE recomputations, process all | 
|  | // the uses of this user that we can find this way. | 
|  | do { | 
|  | SDUse &Use = *UI; | 
|  |  | 
|  | // Skip uses of different values from the same node. | 
|  | if (Use.getResNo() != From.getResNo()) { | 
|  | ++UI; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // If this node hasn't been modified yet, it's still in the CSE maps, | 
|  | // so remove its old self from the CSE maps. | 
|  | if (!UserRemovedFromCSEMaps) { | 
|  | RemoveNodeFromCSEMaps(User); | 
|  | UserRemovedFromCSEMaps = true; | 
|  | } | 
|  |  | 
|  | ++UI; | 
|  | Use.set(To); | 
|  | if (To->isDivergent() != From->isDivergent()) | 
|  | updateDivergence(User); | 
|  | } while (UI != UE && UI->getUser() == User); | 
|  | // We are iterating over all uses of the From node, so if a use | 
|  | // doesn't use the specific value, no changes are made. | 
|  | if (!UserRemovedFromCSEMaps) | 
|  | continue; | 
|  |  | 
|  | // Now that we have modified User, add it back to the CSE maps.  If it | 
|  | // already exists there, recursively merge the results together. | 
|  | AddModifiedNodeToCSEMaps(User); | 
|  | } | 
|  |  | 
|  | // If we just RAUW'd the root, take note. | 
|  | if (From == getRoot()) | 
|  | setRoot(To); | 
|  | } | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | /// UseMemo - This class is used by SelectionDAG::ReplaceAllUsesOfValuesWith | 
|  | /// to record information about a use. | 
|  | struct UseMemo { | 
|  | SDNode *User; | 
|  | unsigned Index; | 
|  | SDUse *Use; | 
|  | }; | 
|  |  | 
|  | /// operator< - Sort Memos by User. | 
|  | bool operator<(const UseMemo &L, const UseMemo &R) { | 
|  | return (intptr_t)L.User < (intptr_t)R.User; | 
|  | } | 
|  |  | 
|  | /// RAUOVWUpdateListener - Helper for ReplaceAllUsesOfValuesWith - When the node | 
|  | /// pointed to by a UseMemo is deleted, set the User to nullptr to indicate that | 
|  | /// the node already has been taken care of recursively. | 
|  | class RAUOVWUpdateListener : public SelectionDAG::DAGUpdateListener { | 
|  | SmallVectorImpl<UseMemo> &Uses; | 
|  |  | 
|  | void NodeDeleted(SDNode *N, SDNode *E) override { | 
|  | for (UseMemo &Memo : Uses) | 
|  | if (Memo.User == N) | 
|  | Memo.User = nullptr; | 
|  | } | 
|  |  | 
|  | public: | 
|  | RAUOVWUpdateListener(SelectionDAG &d, SmallVectorImpl<UseMemo> &uses) | 
|  | : SelectionDAG::DAGUpdateListener(d), Uses(uses) {} | 
|  | }; | 
|  |  | 
|  | } // end anonymous namespace | 
|  |  | 
|  | /// Return true if a glue output should propagate divergence information. | 
|  | static bool gluePropagatesDivergence(const SDNode *Node) { | 
|  | switch (Node->getOpcode()) { | 
|  | case ISD::CopyFromReg: | 
|  | case ISD::CopyToReg: | 
|  | return false; | 
|  | default: | 
|  | return true; | 
|  | } | 
|  |  | 
|  | llvm_unreachable("covered opcode switch"); | 
|  | } | 
|  |  | 
|  | bool SelectionDAG::calculateDivergence(SDNode *N) { | 
|  | if (TLI->isSDNodeAlwaysUniform(N)) { | 
|  | assert(!TLI->isSDNodeSourceOfDivergence(N, FLI, UA) && | 
|  | "Conflicting divergence information!"); | 
|  | return false; | 
|  | } | 
|  | if (TLI->isSDNodeSourceOfDivergence(N, FLI, UA)) | 
|  | return true; | 
|  | for (const auto &Op : N->ops()) { | 
|  | EVT VT = Op.getValueType(); | 
|  |  | 
|  | // Skip Chain. It does not carry divergence. | 
|  | if (VT != MVT::Other && Op.getNode()->isDivergent() && | 
|  | (VT != MVT::Glue || gluePropagatesDivergence(Op.getNode()))) | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void SelectionDAG::updateDivergence(SDNode *N) { | 
|  | SmallVector<SDNode *, 16> Worklist(1, N); | 
|  | do { | 
|  | N = Worklist.pop_back_val(); | 
|  | bool IsDivergent = calculateDivergence(N); | 
|  | if (N->SDNodeBits.IsDivergent != IsDivergent) { | 
|  | N->SDNodeBits.IsDivergent = IsDivergent; | 
|  | llvm::append_range(Worklist, N->users()); | 
|  | } | 
|  | } while (!Worklist.empty()); | 
|  | } | 
|  |  | 
|  | void SelectionDAG::CreateTopologicalOrder(std::vector<SDNode *> &Order) { | 
|  | DenseMap<SDNode *, unsigned> Degree; | 
|  | Order.reserve(AllNodes.size()); | 
|  | for (auto &N : allnodes()) { | 
|  | unsigned NOps = N.getNumOperands(); | 
|  | Degree[&N] = NOps; | 
|  | if (0 == NOps) | 
|  | Order.push_back(&N); | 
|  | } | 
|  | for (size_t I = 0; I != Order.size(); ++I) { | 
|  | SDNode *N = Order[I]; | 
|  | for (auto *U : N->users()) { | 
|  | unsigned &UnsortedOps = Degree[U]; | 
|  | if (0 == --UnsortedOps) | 
|  | Order.push_back(U); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | #if !defined(NDEBUG) && LLVM_ENABLE_ABI_BREAKING_CHECKS | 
|  | void SelectionDAG::VerifyDAGDivergence() { | 
|  | std::vector<SDNode *> TopoOrder; | 
|  | CreateTopologicalOrder(TopoOrder); | 
|  | for (auto *N : TopoOrder) { | 
|  | assert(calculateDivergence(N) == N->isDivergent() && | 
|  | "Divergence bit inconsistency detected"); | 
|  | } | 
|  | } | 
|  | #endif | 
|  |  | 
|  | /// ReplaceAllUsesOfValuesWith - Replace any uses of From with To, leaving | 
|  | /// uses of other values produced by From.getNode() alone.  The same value | 
|  | /// may appear in both the From and To list.  The Deleted vector is | 
|  | /// handled the same way as for ReplaceAllUsesWith. | 
|  | void SelectionDAG::ReplaceAllUsesOfValuesWith(const SDValue *From, | 
|  | const SDValue *To, | 
|  | unsigned Num){ | 
|  | // Handle the simple, trivial case efficiently. | 
|  | if (Num == 1) | 
|  | return ReplaceAllUsesOfValueWith(*From, *To); | 
|  |  | 
|  | transferDbgValues(*From, *To); | 
|  | copyExtraInfo(From->getNode(), To->getNode()); | 
|  |  | 
|  | // Read up all the uses and make records of them. This helps | 
|  | // processing new uses that are introduced during the | 
|  | // replacement process. | 
|  | SmallVector<UseMemo, 4> Uses; | 
|  | for (unsigned i = 0; i != Num; ++i) { | 
|  | unsigned FromResNo = From[i].getResNo(); | 
|  | SDNode *FromNode = From[i].getNode(); | 
|  | for (SDUse &Use : FromNode->uses()) { | 
|  | if (Use.getResNo() == FromResNo) { | 
|  | UseMemo Memo = {Use.getUser(), i, &Use}; | 
|  | Uses.push_back(Memo); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Sort the uses, so that all the uses from a given User are together. | 
|  | llvm::sort(Uses); | 
|  | RAUOVWUpdateListener Listener(*this, Uses); | 
|  |  | 
|  | for (unsigned UseIndex = 0, UseIndexEnd = Uses.size(); | 
|  | UseIndex != UseIndexEnd; ) { | 
|  | // We know that this user uses some value of From.  If it is the right | 
|  | // value, update it. | 
|  | SDNode *User = Uses[UseIndex].User; | 
|  | // If the node has been deleted by recursive CSE updates when updating | 
|  | // another node, then just skip this entry. | 
|  | if (User == nullptr) { | 
|  | ++UseIndex; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // This node is about to morph, remove its old self from the CSE maps. | 
|  | RemoveNodeFromCSEMaps(User); | 
|  |  | 
|  | // The Uses array is sorted, so all the uses for a given User | 
|  | // are next to each other in the list. | 
|  | // To help reduce the number of CSE recomputations, process all | 
|  | // the uses of this user that we can find this way. | 
|  | do { | 
|  | unsigned i = Uses[UseIndex].Index; | 
|  | SDUse &Use = *Uses[UseIndex].Use; | 
|  | ++UseIndex; | 
|  |  | 
|  | Use.set(To[i]); | 
|  | } while (UseIndex != UseIndexEnd && Uses[UseIndex].User == User); | 
|  |  | 
|  | // Now that we have modified User, add it back to the CSE maps.  If it | 
|  | // already exists there, recursively merge the results together. | 
|  | AddModifiedNodeToCSEMaps(User); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// AssignTopologicalOrder - Assign a unique node id for each node in the DAG | 
|  | /// based on their topological order. It returns the maximum id and a vector | 
|  | /// of the SDNodes* in assigned order by reference. | 
|  | unsigned SelectionDAG::AssignTopologicalOrder() { | 
|  | unsigned DAGSize = 0; | 
|  |  | 
|  | // SortedPos tracks the progress of the algorithm. Nodes before it are | 
|  | // sorted, nodes after it are unsorted. When the algorithm completes | 
|  | // it is at the end of the list. | 
|  | allnodes_iterator SortedPos = allnodes_begin(); | 
|  |  | 
|  | // Visit all the nodes. Move nodes with no operands to the front of | 
|  | // the list immediately. Annotate nodes that do have operands with their | 
|  | // operand count. Before we do this, the Node Id fields of the nodes | 
|  | // may contain arbitrary values. After, the Node Id fields for nodes | 
|  | // before SortedPos will contain the topological sort index, and the | 
|  | // Node Id fields for nodes At SortedPos and after will contain the | 
|  | // count of outstanding operands. | 
|  | for (SDNode &N : llvm::make_early_inc_range(allnodes())) { | 
|  | checkForCycles(&N, this); | 
|  | unsigned Degree = N.getNumOperands(); | 
|  | if (Degree == 0) { | 
|  | // A node with no uses, add it to the result array immediately. | 
|  | N.setNodeId(DAGSize++); | 
|  | allnodes_iterator Q(&N); | 
|  | if (Q != SortedPos) | 
|  | SortedPos = AllNodes.insert(SortedPos, AllNodes.remove(Q)); | 
|  | assert(SortedPos != AllNodes.end() && "Overran node list"); | 
|  | ++SortedPos; | 
|  | } else { | 
|  | // Temporarily use the Node Id as scratch space for the degree count. | 
|  | N.setNodeId(Degree); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Visit all the nodes. As we iterate, move nodes into sorted order, | 
|  | // such that by the time the end is reached all nodes will be sorted. | 
|  | for (SDNode &Node : allnodes()) { | 
|  | SDNode *N = &Node; | 
|  | checkForCycles(N, this); | 
|  | // N is in sorted position, so all its uses have one less operand | 
|  | // that needs to be sorted. | 
|  | for (SDNode *P : N->users()) { | 
|  | unsigned Degree = P->getNodeId(); | 
|  | assert(Degree != 0 && "Invalid node degree"); | 
|  | --Degree; | 
|  | if (Degree == 0) { | 
|  | // All of P's operands are sorted, so P may sorted now. | 
|  | P->setNodeId(DAGSize++); | 
|  | if (P->getIterator() != SortedPos) | 
|  | SortedPos = AllNodes.insert(SortedPos, AllNodes.remove(P)); | 
|  | assert(SortedPos != AllNodes.end() && "Overran node list"); | 
|  | ++SortedPos; | 
|  | } else { | 
|  | // Update P's outstanding operand count. | 
|  | P->setNodeId(Degree); | 
|  | } | 
|  | } | 
|  | if (Node.getIterator() == SortedPos) { | 
|  | #ifndef NDEBUG | 
|  | allnodes_iterator I(N); | 
|  | SDNode *S = &*++I; | 
|  | dbgs() << "Overran sorted position:\n"; | 
|  | S->dumprFull(this); dbgs() << "\n"; | 
|  | dbgs() << "Checking if this is due to cycles\n"; | 
|  | checkForCycles(this, true); | 
|  | #endif | 
|  | llvm_unreachable(nullptr); | 
|  | } | 
|  | } | 
|  |  | 
|  | assert(SortedPos == AllNodes.end() && | 
|  | "Topological sort incomplete!"); | 
|  | assert(AllNodes.front().getOpcode() == ISD::EntryToken && | 
|  | "First node in topological sort is not the entry token!"); | 
|  | assert(AllNodes.front().getNodeId() == 0 && | 
|  | "First node in topological sort has non-zero id!"); | 
|  | assert(AllNodes.front().getNumOperands() == 0 && | 
|  | "First node in topological sort has operands!"); | 
|  | assert(AllNodes.back().getNodeId() == (int)DAGSize-1 && | 
|  | "Last node in topologic sort has unexpected id!"); | 
|  | assert(AllNodes.back().use_empty() && | 
|  | "Last node in topologic sort has users!"); | 
|  | assert(DAGSize == allnodes_size() && "Node count mismatch!"); | 
|  | return DAGSize; | 
|  | } | 
|  |  | 
|  | /// AddDbgValue - Add a dbg_value SDNode. If SD is non-null that means the | 
|  | /// value is produced by SD. | 
|  | void SelectionDAG::AddDbgValue(SDDbgValue *DB, bool isParameter) { | 
|  | for (SDNode *SD : DB->getSDNodes()) { | 
|  | if (!SD) | 
|  | continue; | 
|  | assert(DbgInfo->getSDDbgValues(SD).empty() || SD->getHasDebugValue()); | 
|  | SD->setHasDebugValue(true); | 
|  | } | 
|  | DbgInfo->add(DB, isParameter); | 
|  | } | 
|  |  | 
|  | void SelectionDAG::AddDbgLabel(SDDbgLabel *DB) { DbgInfo->add(DB); } | 
|  |  | 
|  | SDValue SelectionDAG::makeEquivalentMemoryOrdering(SDValue OldChain, | 
|  | SDValue NewMemOpChain) { | 
|  | assert(isa<MemSDNode>(NewMemOpChain) && "Expected a memop node"); | 
|  | assert(NewMemOpChain.getValueType() == MVT::Other && "Expected a token VT"); | 
|  | // The new memory operation must have the same position as the old load in | 
|  | // terms of memory dependency. Create a TokenFactor for the old load and new | 
|  | // memory operation and update uses of the old load's output chain to use that | 
|  | // TokenFactor. | 
|  | if (OldChain == NewMemOpChain || OldChain.use_empty()) | 
|  | return NewMemOpChain; | 
|  |  | 
|  | SDValue TokenFactor = getNode(ISD::TokenFactor, SDLoc(OldChain), MVT::Other, | 
|  | OldChain, NewMemOpChain); | 
|  | ReplaceAllUsesOfValueWith(OldChain, TokenFactor); | 
|  | UpdateNodeOperands(TokenFactor.getNode(), OldChain, NewMemOpChain); | 
|  | return TokenFactor; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::makeEquivalentMemoryOrdering(LoadSDNode *OldLoad, | 
|  | SDValue NewMemOp) { | 
|  | assert(isa<MemSDNode>(NewMemOp.getNode()) && "Expected a memop node"); | 
|  | SDValue OldChain = SDValue(OldLoad, 1); | 
|  | SDValue NewMemOpChain = NewMemOp.getValue(1); | 
|  | return makeEquivalentMemoryOrdering(OldChain, NewMemOpChain); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getSymbolFunctionGlobalAddress(SDValue Op, | 
|  | Function **OutFunction) { | 
|  | assert(isa<ExternalSymbolSDNode>(Op) && "Node should be an ExternalSymbol"); | 
|  |  | 
|  | auto *Symbol = cast<ExternalSymbolSDNode>(Op)->getSymbol(); | 
|  | auto *Module = MF->getFunction().getParent(); | 
|  | auto *Function = Module->getFunction(Symbol); | 
|  |  | 
|  | if (OutFunction != nullptr) | 
|  | *OutFunction = Function; | 
|  |  | 
|  | if (Function != nullptr) { | 
|  | auto PtrTy = TLI->getPointerTy(getDataLayout(), Function->getAddressSpace()); | 
|  | return getGlobalAddress(Function, SDLoc(Op), PtrTy); | 
|  | } | 
|  |  | 
|  | std::string ErrorStr; | 
|  | raw_string_ostream ErrorFormatter(ErrorStr); | 
|  | ErrorFormatter << "Undefined external symbol "; | 
|  | ErrorFormatter << '"' << Symbol << '"'; | 
|  | report_fatal_error(Twine(ErrorStr)); | 
|  | } | 
|  |  | 
|  | //===----------------------------------------------------------------------===// | 
|  | //                              SDNode Class | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | bool llvm::isNullConstant(SDValue V) { | 
|  | ConstantSDNode *Const = dyn_cast<ConstantSDNode>(V); | 
|  | return Const != nullptr && Const->isZero(); | 
|  | } | 
|  |  | 
|  | bool llvm::isNullConstantOrUndef(SDValue V) { | 
|  | return V.isUndef() || isNullConstant(V); | 
|  | } | 
|  |  | 
|  | bool llvm::isNullFPConstant(SDValue V) { | 
|  | ConstantFPSDNode *Const = dyn_cast<ConstantFPSDNode>(V); | 
|  | return Const != nullptr && Const->isZero() && !Const->isNegative(); | 
|  | } | 
|  |  | 
|  | bool llvm::isAllOnesConstant(SDValue V) { | 
|  | ConstantSDNode *Const = dyn_cast<ConstantSDNode>(V); | 
|  | return Const != nullptr && Const->isAllOnes(); | 
|  | } | 
|  |  | 
|  | bool llvm::isOneConstant(SDValue V) { | 
|  | ConstantSDNode *Const = dyn_cast<ConstantSDNode>(V); | 
|  | return Const != nullptr && Const->isOne(); | 
|  | } | 
|  |  | 
|  | bool llvm::isMinSignedConstant(SDValue V) { | 
|  | ConstantSDNode *Const = dyn_cast<ConstantSDNode>(V); | 
|  | return Const != nullptr && Const->isMinSignedValue(); | 
|  | } | 
|  |  | 
|  | bool llvm::isNeutralConstant(unsigned Opcode, SDNodeFlags Flags, SDValue V, | 
|  | unsigned OperandNo) { | 
|  | // NOTE: The cases should match with IR's ConstantExpr::getBinOpIdentity(). | 
|  | // TODO: Target-specific opcodes could be added. | 
|  | if (auto *ConstV = isConstOrConstSplat(V, /*AllowUndefs*/ false, | 
|  | /*AllowTruncation*/ true)) { | 
|  | APInt Const = ConstV->getAPIntValue().trunc(V.getScalarValueSizeInBits()); | 
|  | switch (Opcode) { | 
|  | case ISD::ADD: | 
|  | case ISD::OR: | 
|  | case ISD::XOR: | 
|  | case ISD::UMAX: | 
|  | return Const.isZero(); | 
|  | case ISD::MUL: | 
|  | return Const.isOne(); | 
|  | case ISD::AND: | 
|  | case ISD::UMIN: | 
|  | return Const.isAllOnes(); | 
|  | case ISD::SMAX: | 
|  | return Const.isMinSignedValue(); | 
|  | case ISD::SMIN: | 
|  | return Const.isMaxSignedValue(); | 
|  | case ISD::SUB: | 
|  | case ISD::SHL: | 
|  | case ISD::SRA: | 
|  | case ISD::SRL: | 
|  | return OperandNo == 1 && Const.isZero(); | 
|  | case ISD::UDIV: | 
|  | case ISD::SDIV: | 
|  | return OperandNo == 1 && Const.isOne(); | 
|  | } | 
|  | } else if (auto *ConstFP = isConstOrConstSplatFP(V)) { | 
|  | switch (Opcode) { | 
|  | case ISD::FADD: | 
|  | return ConstFP->isZero() && | 
|  | (Flags.hasNoSignedZeros() || ConstFP->isNegative()); | 
|  | case ISD::FSUB: | 
|  | return OperandNo == 1 && ConstFP->isZero() && | 
|  | (Flags.hasNoSignedZeros() || !ConstFP->isNegative()); | 
|  | case ISD::FMUL: | 
|  | return ConstFP->isExactlyValue(1.0); | 
|  | case ISD::FDIV: | 
|  | return OperandNo == 1 && ConstFP->isExactlyValue(1.0); | 
|  | case ISD::FMINNUM: | 
|  | case ISD::FMAXNUM: { | 
|  | // Neutral element for fminnum is NaN, Inf or FLT_MAX, depending on FMF. | 
|  | EVT VT = V.getValueType(); | 
|  | const fltSemantics &Semantics = VT.getFltSemantics(); | 
|  | APFloat NeutralAF = !Flags.hasNoNaNs() | 
|  | ? APFloat::getQNaN(Semantics) | 
|  | : !Flags.hasNoInfs() | 
|  | ? APFloat::getInf(Semantics) | 
|  | : APFloat::getLargest(Semantics); | 
|  | if (Opcode == ISD::FMAXNUM) | 
|  | NeutralAF.changeSign(); | 
|  |  | 
|  | return ConstFP->isExactlyValue(NeutralAF); | 
|  | } | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | SDValue llvm::peekThroughBitcasts(SDValue V) { | 
|  | while (V.getOpcode() == ISD::BITCAST) | 
|  | V = V.getOperand(0); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue llvm::peekThroughOneUseBitcasts(SDValue V) { | 
|  | while (V.getOpcode() == ISD::BITCAST && V.getOperand(0).hasOneUse()) | 
|  | V = V.getOperand(0); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue llvm::peekThroughExtractSubvectors(SDValue V) { | 
|  | while (V.getOpcode() == ISD::EXTRACT_SUBVECTOR) | 
|  | V = V.getOperand(0); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | SDValue llvm::peekThroughTruncates(SDValue V) { | 
|  | while (V.getOpcode() == ISD::TRUNCATE) | 
|  | V = V.getOperand(0); | 
|  | return V; | 
|  | } | 
|  |  | 
|  | bool llvm::isBitwiseNot(SDValue V, bool AllowUndefs) { | 
|  | if (V.getOpcode() != ISD::XOR) | 
|  | return false; | 
|  | V = peekThroughBitcasts(V.getOperand(1)); | 
|  | unsigned NumBits = V.getScalarValueSizeInBits(); | 
|  | ConstantSDNode *C = | 
|  | isConstOrConstSplat(V, AllowUndefs, /*AllowTruncation*/ true); | 
|  | return C && (C->getAPIntValue().countr_one() >= NumBits); | 
|  | } | 
|  |  | 
|  | ConstantSDNode *llvm::isConstOrConstSplat(SDValue N, bool AllowUndefs, | 
|  | bool AllowTruncation) { | 
|  | EVT VT = N.getValueType(); | 
|  | APInt DemandedElts = VT.isFixedLengthVector() | 
|  | ? APInt::getAllOnes(VT.getVectorMinNumElements()) | 
|  | : APInt(1, 1); | 
|  | return isConstOrConstSplat(N, DemandedElts, AllowUndefs, AllowTruncation); | 
|  | } | 
|  |  | 
|  | ConstantSDNode *llvm::isConstOrConstSplat(SDValue N, const APInt &DemandedElts, | 
|  | bool AllowUndefs, | 
|  | bool AllowTruncation) { | 
|  | if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N)) | 
|  | return CN; | 
|  |  | 
|  | // SplatVectors can truncate their operands. Ignore that case here unless | 
|  | // AllowTruncation is set. | 
|  | if (N->getOpcode() == ISD::SPLAT_VECTOR) { | 
|  | EVT VecEltVT = N->getValueType(0).getVectorElementType(); | 
|  | if (auto *CN = dyn_cast<ConstantSDNode>(N->getOperand(0))) { | 
|  | EVT CVT = CN->getValueType(0); | 
|  | assert(CVT.bitsGE(VecEltVT) && "Illegal splat_vector element extension"); | 
|  | if (AllowTruncation || CVT == VecEltVT) | 
|  | return CN; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (BuildVectorSDNode *BV = dyn_cast<BuildVectorSDNode>(N)) { | 
|  | BitVector UndefElements; | 
|  | ConstantSDNode *CN = BV->getConstantSplatNode(DemandedElts, &UndefElements); | 
|  |  | 
|  | // BuildVectors can truncate their operands. Ignore that case here unless | 
|  | // AllowTruncation is set. | 
|  | // TODO: Look into whether we should allow UndefElements in non-DemandedElts | 
|  | if (CN && (UndefElements.none() || AllowUndefs)) { | 
|  | EVT CVT = CN->getValueType(0); | 
|  | EVT NSVT = N.getValueType().getScalarType(); | 
|  | assert(CVT.bitsGE(NSVT) && "Illegal build vector element extension"); | 
|  | if (AllowTruncation || (CVT == NSVT)) | 
|  | return CN; | 
|  | } | 
|  | } | 
|  |  | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | ConstantFPSDNode *llvm::isConstOrConstSplatFP(SDValue N, bool AllowUndefs) { | 
|  | EVT VT = N.getValueType(); | 
|  | APInt DemandedElts = VT.isFixedLengthVector() | 
|  | ? APInt::getAllOnes(VT.getVectorMinNumElements()) | 
|  | : APInt(1, 1); | 
|  | return isConstOrConstSplatFP(N, DemandedElts, AllowUndefs); | 
|  | } | 
|  |  | 
|  | ConstantFPSDNode *llvm::isConstOrConstSplatFP(SDValue N, | 
|  | const APInt &DemandedElts, | 
|  | bool AllowUndefs) { | 
|  | if (ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(N)) | 
|  | return CN; | 
|  |  | 
|  | if (BuildVectorSDNode *BV = dyn_cast<BuildVectorSDNode>(N)) { | 
|  | BitVector UndefElements; | 
|  | ConstantFPSDNode *CN = | 
|  | BV->getConstantFPSplatNode(DemandedElts, &UndefElements); | 
|  | // TODO: Look into whether we should allow UndefElements in non-DemandedElts | 
|  | if (CN && (UndefElements.none() || AllowUndefs)) | 
|  | return CN; | 
|  | } | 
|  |  | 
|  | if (N.getOpcode() == ISD::SPLAT_VECTOR) | 
|  | if (ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(N.getOperand(0))) | 
|  | return CN; | 
|  |  | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | bool llvm::isNullOrNullSplat(SDValue N, bool AllowUndefs) { | 
|  | // TODO: may want to use peekThroughBitcast() here. | 
|  | ConstantSDNode *C = | 
|  | isConstOrConstSplat(N, AllowUndefs, /*AllowTruncation=*/true); | 
|  | return C && C->isZero(); | 
|  | } | 
|  |  | 
|  | bool llvm::isOneOrOneSplat(SDValue N, bool AllowUndefs) { | 
|  | ConstantSDNode *C = | 
|  | isConstOrConstSplat(N, AllowUndefs, /*AllowTruncation*/ true); | 
|  | return C && C->isOne(); | 
|  | } | 
|  |  | 
|  | bool llvm::isAllOnesOrAllOnesSplat(SDValue N, bool AllowUndefs) { | 
|  | N = peekThroughBitcasts(N); | 
|  | unsigned BitWidth = N.getScalarValueSizeInBits(); | 
|  | ConstantSDNode *C = isConstOrConstSplat(N, AllowUndefs); | 
|  | return C && C->isAllOnes() && C->getValueSizeInBits(0) == BitWidth; | 
|  | } | 
|  |  | 
|  | bool llvm::isOnesOrOnesSplat(SDValue N, bool AllowUndefs) { | 
|  | ConstantSDNode *C = isConstOrConstSplat(N, AllowUndefs); | 
|  | return C && APInt::isSameValue(C->getAPIntValue(), | 
|  | APInt(C->getAPIntValue().getBitWidth(), 1)); | 
|  | } | 
|  |  | 
|  | bool llvm::isZeroOrZeroSplat(SDValue N, bool AllowUndefs) { | 
|  | N = peekThroughBitcasts(N); | 
|  | ConstantSDNode *C = isConstOrConstSplat(N, AllowUndefs, true); | 
|  | return C && C->isZero(); | 
|  | } | 
|  |  | 
|  | HandleSDNode::~HandleSDNode() { | 
|  | DropOperands(); | 
|  | } | 
|  |  | 
|  | MemSDNode::MemSDNode(unsigned Opc, unsigned Order, const DebugLoc &dl, | 
|  | SDVTList VTs, EVT memvt, MachineMemOperand *mmo) | 
|  | : SDNode(Opc, Order, dl, VTs), MemoryVT(memvt), MMO(mmo) { | 
|  | MemSDNodeBits.IsVolatile = MMO->isVolatile(); | 
|  | MemSDNodeBits.IsNonTemporal = MMO->isNonTemporal(); | 
|  | MemSDNodeBits.IsDereferenceable = MMO->isDereferenceable(); | 
|  | MemSDNodeBits.IsInvariant = MMO->isInvariant(); | 
|  |  | 
|  | // We check here that the size of the memory operand fits within the size of | 
|  | // the MMO. This is because the MMO might indicate only a possible address | 
|  | // range instead of specifying the affected memory addresses precisely. | 
|  | assert( | 
|  | (!MMO->getType().isValid() || | 
|  | TypeSize::isKnownLE(memvt.getStoreSize(), MMO->getSize().getValue())) && | 
|  | "Size mismatch!"); | 
|  | } | 
|  |  | 
|  | /// Profile - Gather unique data for the node. | 
|  | /// | 
|  | void SDNode::Profile(FoldingSetNodeID &ID) const { | 
|  | AddNodeIDNode(ID, this); | 
|  | } | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | struct EVTArray { | 
|  | std::vector<EVT> VTs; | 
|  |  | 
|  | EVTArray() { | 
|  | VTs.reserve(MVT::VALUETYPE_SIZE); | 
|  | for (unsigned i = 0; i < MVT::VALUETYPE_SIZE; ++i) | 
|  | VTs.push_back(MVT((MVT::SimpleValueType)i)); | 
|  | } | 
|  | }; | 
|  |  | 
|  | } // end anonymous namespace | 
|  |  | 
|  | /// getValueTypeList - Return a pointer to the specified value type. | 
|  | /// | 
|  | const EVT *SDNode::getValueTypeList(MVT VT) { | 
|  | static EVTArray SimpleVTArray; | 
|  |  | 
|  | assert(VT < MVT::VALUETYPE_SIZE && "Value type out of range!"); | 
|  | return &SimpleVTArray.VTs[VT.SimpleTy]; | 
|  | } | 
|  |  | 
|  | /// hasAnyUseOfValue - Return true if there are any use of the indicated | 
|  | /// value. This method ignores uses of other values defined by this operation. | 
|  | bool SDNode::hasAnyUseOfValue(unsigned Value) const { | 
|  | assert(Value < getNumValues() && "Bad value!"); | 
|  |  | 
|  | for (SDUse &U : uses()) | 
|  | if (U.getResNo() == Value) | 
|  | return true; | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /// isOnlyUserOf - Return true if this node is the only use of N. | 
|  | bool SDNode::isOnlyUserOf(const SDNode *N) const { | 
|  | bool Seen = false; | 
|  | for (const SDNode *User : N->users()) { | 
|  | if (User == this) | 
|  | Seen = true; | 
|  | else | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return Seen; | 
|  | } | 
|  |  | 
|  | /// Return true if the only users of N are contained in Nodes. | 
|  | bool SDNode::areOnlyUsersOf(ArrayRef<const SDNode *> Nodes, const SDNode *N) { | 
|  | bool Seen = false; | 
|  | for (const SDNode *User : N->users()) { | 
|  | if (llvm::is_contained(Nodes, User)) | 
|  | Seen = true; | 
|  | else | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return Seen; | 
|  | } | 
|  |  | 
|  | /// Return true if the referenced return value is an operand of N. | 
|  | bool SDValue::isOperandOf(const SDNode *N) const { | 
|  | return is_contained(N->op_values(), *this); | 
|  | } | 
|  |  | 
|  | bool SDNode::isOperandOf(const SDNode *N) const { | 
|  | return any_of(N->op_values(), | 
|  | [this](SDValue Op) { return this == Op.getNode(); }); | 
|  | } | 
|  |  | 
|  | /// reachesChainWithoutSideEffects - Return true if this operand (which must | 
|  | /// be a chain) reaches the specified operand without crossing any | 
|  | /// side-effecting instructions on any chain path.  In practice, this looks | 
|  | /// through token factors and non-volatile loads.  In order to remain efficient, | 
|  | /// this only looks a couple of nodes in, it does not do an exhaustive search. | 
|  | /// | 
|  | /// Note that we only need to examine chains when we're searching for | 
|  | /// side-effects; SelectionDAG requires that all side-effects are represented | 
|  | /// by chains, even if another operand would force a specific ordering. This | 
|  | /// constraint is necessary to allow transformations like splitting loads. | 
|  | bool SDValue::reachesChainWithoutSideEffects(SDValue Dest, | 
|  | unsigned Depth) const { | 
|  | if (*this == Dest) return true; | 
|  |  | 
|  | // Don't search too deeply, we just want to be able to see through | 
|  | // TokenFactor's etc. | 
|  | if (Depth == 0) return false; | 
|  |  | 
|  | // If this is a token factor, all inputs to the TF happen in parallel. | 
|  | if (getOpcode() == ISD::TokenFactor) { | 
|  | // First, try a shallow search. | 
|  | if (is_contained((*this)->ops(), Dest)) { | 
|  | // We found the chain we want as an operand of this TokenFactor. | 
|  | // Essentially, we reach the chain without side-effects if we could | 
|  | // serialize the TokenFactor into a simple chain of operations with | 
|  | // Dest as the last operation. This is automatically true if the | 
|  | // chain has one use: there are no other ordering constraints. | 
|  | // If the chain has more than one use, we give up: some other | 
|  | // use of Dest might force a side-effect between Dest and the current | 
|  | // node. | 
|  | if (Dest.hasOneUse()) | 
|  | return true; | 
|  | } | 
|  | // Next, try a deep search: check whether every operand of the TokenFactor | 
|  | // reaches Dest. | 
|  | return llvm::all_of((*this)->ops(), [=](SDValue Op) { | 
|  | return Op.reachesChainWithoutSideEffects(Dest, Depth - 1); | 
|  | }); | 
|  | } | 
|  |  | 
|  | // Loads don't have side effects, look through them. | 
|  | if (LoadSDNode *Ld = dyn_cast<LoadSDNode>(*this)) { | 
|  | if (Ld->isUnordered()) | 
|  | return Ld->getChain().reachesChainWithoutSideEffects(Dest, Depth-1); | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool SDNode::hasPredecessor(const SDNode *N) const { | 
|  | SmallPtrSet<const SDNode *, 32> Visited; | 
|  | SmallVector<const SDNode *, 16> Worklist; | 
|  | Worklist.push_back(this); | 
|  | return hasPredecessorHelper(N, Visited, Worklist); | 
|  | } | 
|  |  | 
|  | void SDNode::intersectFlagsWith(const SDNodeFlags Flags) { | 
|  | this->Flags &= Flags; | 
|  | } | 
|  |  | 
|  | SDValue | 
|  | SelectionDAG::matchBinOpReduction(SDNode *Extract, ISD::NodeType &BinOp, | 
|  | ArrayRef<ISD::NodeType> CandidateBinOps, | 
|  | bool AllowPartials) { | 
|  | // The pattern must end in an extract from index 0. | 
|  | if (Extract->getOpcode() != ISD::EXTRACT_VECTOR_ELT || | 
|  | !isNullConstant(Extract->getOperand(1))) | 
|  | return SDValue(); | 
|  |  | 
|  | // Match against one of the candidate binary ops. | 
|  | SDValue Op = Extract->getOperand(0); | 
|  | if (llvm::none_of(CandidateBinOps, [Op](ISD::NodeType BinOp) { | 
|  | return Op.getOpcode() == unsigned(BinOp); | 
|  | })) | 
|  | return SDValue(); | 
|  |  | 
|  | // Floating-point reductions may require relaxed constraints on the final step | 
|  | // of the reduction because they may reorder intermediate operations. | 
|  | unsigned CandidateBinOp = Op.getOpcode(); | 
|  | if (Op.getValueType().isFloatingPoint()) { | 
|  | SDNodeFlags Flags = Op->getFlags(); | 
|  | switch (CandidateBinOp) { | 
|  | case ISD::FADD: | 
|  | if (!Flags.hasNoSignedZeros() || !Flags.hasAllowReassociation()) | 
|  | return SDValue(); | 
|  | break; | 
|  | default: | 
|  | llvm_unreachable("Unhandled FP opcode for binop reduction"); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Matching failed - attempt to see if we did enough stages that a partial | 
|  | // reduction from a subvector is possible. | 
|  | auto PartialReduction = [&](SDValue Op, unsigned NumSubElts) { | 
|  | if (!AllowPartials || !Op) | 
|  | return SDValue(); | 
|  | EVT OpVT = Op.getValueType(); | 
|  | EVT OpSVT = OpVT.getScalarType(); | 
|  | EVT SubVT = EVT::getVectorVT(*getContext(), OpSVT, NumSubElts); | 
|  | if (!TLI->isExtractSubvectorCheap(SubVT, OpVT, 0)) | 
|  | return SDValue(); | 
|  | BinOp = (ISD::NodeType)CandidateBinOp; | 
|  | return getExtractSubvector(SDLoc(Op), SubVT, Op, 0); | 
|  | }; | 
|  |  | 
|  | // At each stage, we're looking for something that looks like: | 
|  | // %s = shufflevector <8 x i32> %op, <8 x i32> undef, | 
|  | //                    <8 x i32> <i32 2, i32 3, i32 undef, i32 undef, | 
|  | //                               i32 undef, i32 undef, i32 undef, i32 undef> | 
|  | // %a = binop <8 x i32> %op, %s | 
|  | // Where the mask changes according to the stage. E.g. for a 3-stage pyramid, | 
|  | // we expect something like: | 
|  | // <4,5,6,7,u,u,u,u> | 
|  | // <2,3,u,u,u,u,u,u> | 
|  | // <1,u,u,u,u,u,u,u> | 
|  | // While a partial reduction match would be: | 
|  | // <2,3,u,u,u,u,u,u> | 
|  | // <1,u,u,u,u,u,u,u> | 
|  | unsigned Stages = Log2_32(Op.getValueType().getVectorNumElements()); | 
|  | SDValue PrevOp; | 
|  | for (unsigned i = 0; i < Stages; ++i) { | 
|  | unsigned MaskEnd = (1 << i); | 
|  |  | 
|  | if (Op.getOpcode() != CandidateBinOp) | 
|  | return PartialReduction(PrevOp, MaskEnd); | 
|  |  | 
|  | SDValue Op0 = Op.getOperand(0); | 
|  | SDValue Op1 = Op.getOperand(1); | 
|  |  | 
|  | ShuffleVectorSDNode *Shuffle = dyn_cast<ShuffleVectorSDNode>(Op0); | 
|  | if (Shuffle) { | 
|  | Op = Op1; | 
|  | } else { | 
|  | Shuffle = dyn_cast<ShuffleVectorSDNode>(Op1); | 
|  | Op = Op0; | 
|  | } | 
|  |  | 
|  | // The first operand of the shuffle should be the same as the other operand | 
|  | // of the binop. | 
|  | if (!Shuffle || Shuffle->getOperand(0) != Op) | 
|  | return PartialReduction(PrevOp, MaskEnd); | 
|  |  | 
|  | // Verify the shuffle has the expected (at this stage of the pyramid) mask. | 
|  | for (int Index = 0; Index < (int)MaskEnd; ++Index) | 
|  | if (Shuffle->getMaskElt(Index) != (int)(MaskEnd + Index)) | 
|  | return PartialReduction(PrevOp, MaskEnd); | 
|  |  | 
|  | PrevOp = Op; | 
|  | } | 
|  |  | 
|  | // Handle subvector reductions, which tend to appear after the shuffle | 
|  | // reduction stages. | 
|  | while (Op.getOpcode() == CandidateBinOp) { | 
|  | unsigned NumElts = Op.getValueType().getVectorNumElements(); | 
|  | SDValue Op0 = Op.getOperand(0); | 
|  | SDValue Op1 = Op.getOperand(1); | 
|  | if (Op0.getOpcode() != ISD::EXTRACT_SUBVECTOR || | 
|  | Op1.getOpcode() != ISD::EXTRACT_SUBVECTOR || | 
|  | Op0.getOperand(0) != Op1.getOperand(0)) | 
|  | break; | 
|  | SDValue Src = Op0.getOperand(0); | 
|  | unsigned NumSrcElts = Src.getValueType().getVectorNumElements(); | 
|  | if (NumSrcElts != (2 * NumElts)) | 
|  | break; | 
|  | if (!(Op0.getConstantOperandAPInt(1) == 0 && | 
|  | Op1.getConstantOperandAPInt(1) == NumElts) && | 
|  | !(Op1.getConstantOperandAPInt(1) == 0 && | 
|  | Op0.getConstantOperandAPInt(1) == NumElts)) | 
|  | break; | 
|  | Op = Src; | 
|  | } | 
|  |  | 
|  | BinOp = (ISD::NodeType)CandidateBinOp; | 
|  | return Op; | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::UnrollVectorOp(SDNode *N, unsigned ResNE) { | 
|  | EVT VT = N->getValueType(0); | 
|  | EVT EltVT = VT.getVectorElementType(); | 
|  | unsigned NE = VT.getVectorNumElements(); | 
|  |  | 
|  | SDLoc dl(N); | 
|  |  | 
|  | // If ResNE is 0, fully unroll the vector op. | 
|  | if (ResNE == 0) | 
|  | ResNE = NE; | 
|  | else if (NE > ResNE) | 
|  | NE = ResNE; | 
|  |  | 
|  | if (N->getNumValues() == 2) { | 
|  | SmallVector<SDValue, 8> Scalars0, Scalars1; | 
|  | SmallVector<SDValue, 4> Operands(N->getNumOperands()); | 
|  | EVT VT1 = N->getValueType(1); | 
|  | EVT EltVT1 = VT1.getVectorElementType(); | 
|  |  | 
|  | unsigned i; | 
|  | for (i = 0; i != NE; ++i) { | 
|  | for (unsigned j = 0, e = N->getNumOperands(); j != e; ++j) { | 
|  | SDValue Operand = N->getOperand(j); | 
|  | EVT OperandVT = Operand.getValueType(); | 
|  |  | 
|  | // A vector operand; extract a single element. | 
|  | EVT OperandEltVT = OperandVT.getVectorElementType(); | 
|  | Operands[j] = getExtractVectorElt(dl, OperandEltVT, Operand, i); | 
|  | } | 
|  |  | 
|  | SDValue EltOp = getNode(N->getOpcode(), dl, {EltVT, EltVT1}, Operands); | 
|  | Scalars0.push_back(EltOp); | 
|  | Scalars1.push_back(EltOp.getValue(1)); | 
|  | } | 
|  |  | 
|  | for (; i < ResNE; ++i) { | 
|  | Scalars0.push_back(getUNDEF(EltVT)); | 
|  | Scalars1.push_back(getUNDEF(EltVT1)); | 
|  | } | 
|  |  | 
|  | EVT VecVT = EVT::getVectorVT(*getContext(), EltVT, ResNE); | 
|  | EVT VecVT1 = EVT::getVectorVT(*getContext(), EltVT1, ResNE); | 
|  | SDValue Vec0 = getBuildVector(VecVT, dl, Scalars0); | 
|  | SDValue Vec1 = getBuildVector(VecVT1, dl, Scalars1); | 
|  | return getMergeValues({Vec0, Vec1}, dl); | 
|  | } | 
|  |  | 
|  | assert(N->getNumValues() == 1 && | 
|  | "Can't unroll a vector with multiple results!"); | 
|  |  | 
|  | SmallVector<SDValue, 8> Scalars; | 
|  | SmallVector<SDValue, 4> Operands(N->getNumOperands()); | 
|  |  | 
|  | unsigned i; | 
|  | for (i= 0; i != NE; ++i) { | 
|  | for (unsigned j = 0, e = N->getNumOperands(); j != e; ++j) { | 
|  | SDValue Operand = N->getOperand(j); | 
|  | EVT OperandVT = Operand.getValueType(); | 
|  | if (OperandVT.isVector()) { | 
|  | // A vector operand; extract a single element. | 
|  | EVT OperandEltVT = OperandVT.getVectorElementType(); | 
|  | Operands[j] = getExtractVectorElt(dl, OperandEltVT, Operand, i); | 
|  | } else { | 
|  | // A scalar operand; just use it as is. | 
|  | Operands[j] = Operand; | 
|  | } | 
|  | } | 
|  |  | 
|  | switch (N->getOpcode()) { | 
|  | default: { | 
|  | Scalars.push_back(getNode(N->getOpcode(), dl, EltVT, Operands, | 
|  | N->getFlags())); | 
|  | break; | 
|  | } | 
|  | case ISD::VSELECT: | 
|  | Scalars.push_back(getNode(ISD::SELECT, dl, EltVT, Operands)); | 
|  | break; | 
|  | case ISD::SHL: | 
|  | case ISD::SRA: | 
|  | case ISD::SRL: | 
|  | case ISD::ROTL: | 
|  | case ISD::ROTR: | 
|  | Scalars.push_back(getNode(N->getOpcode(), dl, EltVT, Operands[0], | 
|  | getShiftAmountOperand(Operands[0].getValueType(), | 
|  | Operands[1]))); | 
|  | break; | 
|  | case ISD::SIGN_EXTEND_INREG: { | 
|  | EVT ExtVT = cast<VTSDNode>(Operands[1])->getVT().getVectorElementType(); | 
|  | Scalars.push_back(getNode(N->getOpcode(), dl, EltVT, | 
|  | Operands[0], | 
|  | getValueType(ExtVT))); | 
|  | break; | 
|  | } | 
|  | case ISD::ADDRSPACECAST: { | 
|  | const auto *ASC = cast<AddrSpaceCastSDNode>(N); | 
|  | Scalars.push_back(getAddrSpaceCast(dl, EltVT, Operands[0], | 
|  | ASC->getSrcAddressSpace(), | 
|  | ASC->getDestAddressSpace())); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | for (; i < ResNE; ++i) | 
|  | Scalars.push_back(getUNDEF(EltVT)); | 
|  |  | 
|  | EVT VecVT = EVT::getVectorVT(*getContext(), EltVT, ResNE); | 
|  | return getBuildVector(VecVT, dl, Scalars); | 
|  | } | 
|  |  | 
|  | std::pair<SDValue, SDValue> SelectionDAG::UnrollVectorOverflowOp( | 
|  | SDNode *N, unsigned ResNE) { | 
|  | unsigned Opcode = N->getOpcode(); | 
|  | assert((Opcode == ISD::UADDO || Opcode == ISD::SADDO || | 
|  | Opcode == ISD::USUBO || Opcode == ISD::SSUBO || | 
|  | Opcode == ISD::UMULO || Opcode == ISD::SMULO) && | 
|  | "Expected an overflow opcode"); | 
|  |  | 
|  | EVT ResVT = N->getValueType(0); | 
|  | EVT OvVT = N->getValueType(1); | 
|  | EVT ResEltVT = ResVT.getVectorElementType(); | 
|  | EVT OvEltVT = OvVT.getVectorElementType(); | 
|  | SDLoc dl(N); | 
|  |  | 
|  | // If ResNE is 0, fully unroll the vector op. | 
|  | unsigned NE = ResVT.getVectorNumElements(); | 
|  | if (ResNE == 0) | 
|  | ResNE = NE; | 
|  | else if (NE > ResNE) | 
|  | NE = ResNE; | 
|  |  | 
|  | SmallVector<SDValue, 8> LHSScalars; | 
|  | SmallVector<SDValue, 8> RHSScalars; | 
|  | ExtractVectorElements(N->getOperand(0), LHSScalars, 0, NE); | 
|  | ExtractVectorElements(N->getOperand(1), RHSScalars, 0, NE); | 
|  |  | 
|  | EVT SVT = TLI->getSetCCResultType(getDataLayout(), *getContext(), ResEltVT); | 
|  | SDVTList VTs = getVTList(ResEltVT, SVT); | 
|  | SmallVector<SDValue, 8> ResScalars; | 
|  | SmallVector<SDValue, 8> OvScalars; | 
|  | for (unsigned i = 0; i < NE; ++i) { | 
|  | SDValue Res = getNode(Opcode, dl, VTs, LHSScalars[i], RHSScalars[i]); | 
|  | SDValue Ov = | 
|  | getSelect(dl, OvEltVT, Res.getValue(1), | 
|  | getBoolConstant(true, dl, OvEltVT, ResVT), | 
|  | getConstant(0, dl, OvEltVT)); | 
|  |  | 
|  | ResScalars.push_back(Res); | 
|  | OvScalars.push_back(Ov); | 
|  | } | 
|  |  | 
|  | ResScalars.append(ResNE - NE, getUNDEF(ResEltVT)); | 
|  | OvScalars.append(ResNE - NE, getUNDEF(OvEltVT)); | 
|  |  | 
|  | EVT NewResVT = EVT::getVectorVT(*getContext(), ResEltVT, ResNE); | 
|  | EVT NewOvVT = EVT::getVectorVT(*getContext(), OvEltVT, ResNE); | 
|  | return std::make_pair(getBuildVector(NewResVT, dl, ResScalars), | 
|  | getBuildVector(NewOvVT, dl, OvScalars)); | 
|  | } | 
|  |  | 
|  | bool SelectionDAG::areNonVolatileConsecutiveLoads(LoadSDNode *LD, | 
|  | LoadSDNode *Base, | 
|  | unsigned Bytes, | 
|  | int Dist) const { | 
|  | if (LD->isVolatile() || Base->isVolatile()) | 
|  | return false; | 
|  | // TODO: probably too restrictive for atomics, revisit | 
|  | if (!LD->isSimple()) | 
|  | return false; | 
|  | if (LD->isIndexed() || Base->isIndexed()) | 
|  | return false; | 
|  | if (LD->getChain() != Base->getChain()) | 
|  | return false; | 
|  | EVT VT = LD->getMemoryVT(); | 
|  | if (VT.getSizeInBits() / 8 != Bytes) | 
|  | return false; | 
|  |  | 
|  | auto BaseLocDecomp = BaseIndexOffset::match(Base, *this); | 
|  | auto LocDecomp = BaseIndexOffset::match(LD, *this); | 
|  |  | 
|  | int64_t Offset = 0; | 
|  | if (BaseLocDecomp.equalBaseIndex(LocDecomp, *this, Offset)) | 
|  | return (Dist * (int64_t)Bytes == Offset); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /// InferPtrAlignment - Infer alignment of a load / store address. Return | 
|  | /// std::nullopt if it cannot be inferred. | 
|  | MaybeAlign SelectionDAG::InferPtrAlign(SDValue Ptr) const { | 
|  | // If this is a GlobalAddress + cst, return the alignment. | 
|  | const GlobalValue *GV = nullptr; | 
|  | int64_t GVOffset = 0; | 
|  | if (TLI->isGAPlusOffset(Ptr.getNode(), GV, GVOffset)) { | 
|  | unsigned PtrWidth = getDataLayout().getPointerTypeSizeInBits(GV->getType()); | 
|  | KnownBits Known(PtrWidth); | 
|  | llvm::computeKnownBits(GV, Known, getDataLayout()); | 
|  | unsigned AlignBits = Known.countMinTrailingZeros(); | 
|  | if (AlignBits) | 
|  | return commonAlignment(Align(1ull << std::min(31U, AlignBits)), GVOffset); | 
|  | } | 
|  |  | 
|  | // If this is a direct reference to a stack slot, use information about the | 
|  | // stack slot's alignment. | 
|  | int FrameIdx = INT_MIN; | 
|  | int64_t FrameOffset = 0; | 
|  | if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(Ptr)) { | 
|  | FrameIdx = FI->getIndex(); | 
|  | } else if (isBaseWithConstantOffset(Ptr) && | 
|  | isa<FrameIndexSDNode>(Ptr.getOperand(0))) { | 
|  | // Handle FI+Cst | 
|  | FrameIdx = cast<FrameIndexSDNode>(Ptr.getOperand(0))->getIndex(); | 
|  | FrameOffset = Ptr.getConstantOperandVal(1); | 
|  | } | 
|  |  | 
|  | if (FrameIdx != INT_MIN) { | 
|  | const MachineFrameInfo &MFI = getMachineFunction().getFrameInfo(); | 
|  | return commonAlignment(MFI.getObjectAlign(FrameIdx), FrameOffset); | 
|  | } | 
|  |  | 
|  | return std::nullopt; | 
|  | } | 
|  |  | 
|  | /// Split the scalar node with EXTRACT_ELEMENT using the provided | 
|  | /// VTs and return the low/high part. | 
|  | std::pair<SDValue, SDValue> SelectionDAG::SplitScalar(const SDValue &N, | 
|  | const SDLoc &DL, | 
|  | const EVT &LoVT, | 
|  | const EVT &HiVT) { | 
|  | assert(!LoVT.isVector() && !HiVT.isVector() && !N.getValueType().isVector() && | 
|  | "Split node must be a scalar type"); | 
|  | SDValue Lo = | 
|  | getNode(ISD::EXTRACT_ELEMENT, DL, LoVT, N, getIntPtrConstant(0, DL)); | 
|  | SDValue Hi = | 
|  | getNode(ISD::EXTRACT_ELEMENT, DL, HiVT, N, getIntPtrConstant(1, DL)); | 
|  | return std::make_pair(Lo, Hi); | 
|  | } | 
|  |  | 
|  | /// GetSplitDestVTs - Compute the VTs needed for the low/hi parts of a type | 
|  | /// which is split (or expanded) into two not necessarily identical pieces. | 
|  | std::pair<EVT, EVT> SelectionDAG::GetSplitDestVTs(const EVT &VT) const { | 
|  | // Currently all types are split in half. | 
|  | EVT LoVT, HiVT; | 
|  | if (!VT.isVector()) | 
|  | LoVT = HiVT = TLI->getTypeToTransformTo(*getContext(), VT); | 
|  | else | 
|  | LoVT = HiVT = VT.getHalfNumVectorElementsVT(*getContext()); | 
|  |  | 
|  | return std::make_pair(LoVT, HiVT); | 
|  | } | 
|  |  | 
|  | /// GetDependentSplitDestVTs - Compute the VTs needed for the low/hi parts of a | 
|  | /// type, dependent on an enveloping VT that has been split into two identical | 
|  | /// pieces. Sets the HiIsEmpty flag when hi type has zero storage size. | 
|  | std::pair<EVT, EVT> | 
|  | SelectionDAG::GetDependentSplitDestVTs(const EVT &VT, const EVT &EnvVT, | 
|  | bool *HiIsEmpty) const { | 
|  | EVT EltTp = VT.getVectorElementType(); | 
|  | // Examples: | 
|  | //   custom VL=8  with enveloping VL=8/8 yields 8/0 (hi empty) | 
|  | //   custom VL=9  with enveloping VL=8/8 yields 8/1 | 
|  | //   custom VL=10 with enveloping VL=8/8 yields 8/2 | 
|  | //   etc. | 
|  | ElementCount VTNumElts = VT.getVectorElementCount(); | 
|  | ElementCount EnvNumElts = EnvVT.getVectorElementCount(); | 
|  | assert(VTNumElts.isScalable() == EnvNumElts.isScalable() && | 
|  | "Mixing fixed width and scalable vectors when enveloping a type"); | 
|  | EVT LoVT, HiVT; | 
|  | if (VTNumElts.getKnownMinValue() > EnvNumElts.getKnownMinValue()) { | 
|  | LoVT = EVT::getVectorVT(*getContext(), EltTp, EnvNumElts); | 
|  | HiVT = EVT::getVectorVT(*getContext(), EltTp, VTNumElts - EnvNumElts); | 
|  | *HiIsEmpty = false; | 
|  | } else { | 
|  | // Flag that hi type has zero storage size, but return split envelop type | 
|  | // (this would be easier if vector types with zero elements were allowed). | 
|  | LoVT = EVT::getVectorVT(*getContext(), EltTp, VTNumElts); | 
|  | HiVT = EVT::getVectorVT(*getContext(), EltTp, EnvNumElts); | 
|  | *HiIsEmpty = true; | 
|  | } | 
|  | return std::make_pair(LoVT, HiVT); | 
|  | } | 
|  |  | 
|  | /// SplitVector - Split the vector with EXTRACT_SUBVECTOR and return the | 
|  | /// low/high part. | 
|  | std::pair<SDValue, SDValue> | 
|  | SelectionDAG::SplitVector(const SDValue &N, const SDLoc &DL, const EVT &LoVT, | 
|  | const EVT &HiVT) { | 
|  | assert(LoVT.isScalableVector() == HiVT.isScalableVector() && | 
|  | LoVT.isScalableVector() == N.getValueType().isScalableVector() && | 
|  | "Splitting vector with an invalid mixture of fixed and scalable " | 
|  | "vector types"); | 
|  | assert(LoVT.getVectorMinNumElements() + HiVT.getVectorMinNumElements() <= | 
|  | N.getValueType().getVectorMinNumElements() && | 
|  | "More vector elements requested than available!"); | 
|  | SDValue Lo, Hi; | 
|  | Lo = getExtractSubvector(DL, LoVT, N, 0); | 
|  | // For scalable vectors it is safe to use LoVT.getVectorMinNumElements() | 
|  | // (rather than having to use ElementCount), because EXTRACT_SUBVECTOR scales | 
|  | // IDX with the runtime scaling factor of the result vector type. For | 
|  | // fixed-width result vectors, that runtime scaling factor is 1. | 
|  | Hi = getNode(ISD::EXTRACT_SUBVECTOR, DL, HiVT, N, | 
|  | getVectorIdxConstant(LoVT.getVectorMinNumElements(), DL)); | 
|  | return std::make_pair(Lo, Hi); | 
|  | } | 
|  |  | 
|  | std::pair<SDValue, SDValue> SelectionDAG::SplitEVL(SDValue N, EVT VecVT, | 
|  | const SDLoc &DL) { | 
|  | // Split the vector length parameter. | 
|  | // %evl -> umin(%evl, %halfnumelts) and usubsat(%evl - %halfnumelts). | 
|  | EVT VT = N.getValueType(); | 
|  | assert(VecVT.getVectorElementCount().isKnownEven() && | 
|  | "Expecting the mask to be an evenly-sized vector"); | 
|  | unsigned HalfMinNumElts = VecVT.getVectorMinNumElements() / 2; | 
|  | SDValue HalfNumElts = | 
|  | VecVT.isFixedLengthVector() | 
|  | ? getConstant(HalfMinNumElts, DL, VT) | 
|  | : getVScale(DL, VT, APInt(VT.getScalarSizeInBits(), HalfMinNumElts)); | 
|  | SDValue Lo = getNode(ISD::UMIN, DL, VT, N, HalfNumElts); | 
|  | SDValue Hi = getNode(ISD::USUBSAT, DL, VT, N, HalfNumElts); | 
|  | return std::make_pair(Lo, Hi); | 
|  | } | 
|  |  | 
|  | /// Widen the vector up to the next power of two using INSERT_SUBVECTOR. | 
|  | SDValue SelectionDAG::WidenVector(const SDValue &N, const SDLoc &DL) { | 
|  | EVT VT = N.getValueType(); | 
|  | EVT WideVT = EVT::getVectorVT(*getContext(), VT.getVectorElementType(), | 
|  | NextPowerOf2(VT.getVectorNumElements())); | 
|  | return getInsertSubvector(DL, getUNDEF(WideVT), N, 0); | 
|  | } | 
|  |  | 
|  | void SelectionDAG::ExtractVectorElements(SDValue Op, | 
|  | SmallVectorImpl<SDValue> &Args, | 
|  | unsigned Start, unsigned Count, | 
|  | EVT EltVT) { | 
|  | EVT VT = Op.getValueType(); | 
|  | if (Count == 0) | 
|  | Count = VT.getVectorNumElements(); | 
|  | if (EltVT == EVT()) | 
|  | EltVT = VT.getVectorElementType(); | 
|  | SDLoc SL(Op); | 
|  | for (unsigned i = Start, e = Start + Count; i != e; ++i) { | 
|  | Args.push_back(getExtractVectorElt(SL, EltVT, Op, i)); | 
|  | } | 
|  | } | 
|  |  | 
|  | // getAddressSpace - Return the address space this GlobalAddress belongs to. | 
|  | unsigned GlobalAddressSDNode::getAddressSpace() const { | 
|  | return getGlobal()->getType()->getAddressSpace(); | 
|  | } | 
|  |  | 
|  | Type *ConstantPoolSDNode::getType() const { | 
|  | if (isMachineConstantPoolEntry()) | 
|  | return Val.MachineCPVal->getType(); | 
|  | return Val.ConstVal->getType(); | 
|  | } | 
|  |  | 
|  | bool BuildVectorSDNode::isConstantSplat(APInt &SplatValue, APInt &SplatUndef, | 
|  | unsigned &SplatBitSize, | 
|  | bool &HasAnyUndefs, | 
|  | unsigned MinSplatBits, | 
|  | bool IsBigEndian) const { | 
|  | EVT VT = getValueType(0); | 
|  | assert(VT.isVector() && "Expected a vector type"); | 
|  | unsigned VecWidth = VT.getSizeInBits(); | 
|  | if (MinSplatBits > VecWidth) | 
|  | return false; | 
|  |  | 
|  | // FIXME: The widths are based on this node's type, but build vectors can | 
|  | // truncate their operands. | 
|  | SplatValue = APInt(VecWidth, 0); | 
|  | SplatUndef = APInt(VecWidth, 0); | 
|  |  | 
|  | // Get the bits. Bits with undefined values (when the corresponding element | 
|  | // of the vector is an ISD::UNDEF value) are set in SplatUndef and cleared | 
|  | // in SplatValue. If any of the values are not constant, give up and return | 
|  | // false. | 
|  | unsigned int NumOps = getNumOperands(); | 
|  | assert(NumOps > 0 && "isConstantSplat has 0-size build vector"); | 
|  | unsigned EltWidth = VT.getScalarSizeInBits(); | 
|  |  | 
|  | for (unsigned j = 0; j < NumOps; ++j) { | 
|  | unsigned i = IsBigEndian ? NumOps - 1 - j : j; | 
|  | SDValue OpVal = getOperand(i); | 
|  | unsigned BitPos = j * EltWidth; | 
|  |  | 
|  | if (OpVal.isUndef()) | 
|  | SplatUndef.setBits(BitPos, BitPos + EltWidth); | 
|  | else if (auto *CN = dyn_cast<ConstantSDNode>(OpVal)) | 
|  | SplatValue.insertBits(CN->getAPIntValue().zextOrTrunc(EltWidth), BitPos); | 
|  | else if (auto *CN = dyn_cast<ConstantFPSDNode>(OpVal)) | 
|  | SplatValue.insertBits(CN->getValueAPF().bitcastToAPInt(), BitPos); | 
|  | else | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // The build_vector is all constants or undefs. Find the smallest element | 
|  | // size that splats the vector. | 
|  | HasAnyUndefs = (SplatUndef != 0); | 
|  |  | 
|  | // FIXME: This does not work for vectors with elements less than 8 bits. | 
|  | while (VecWidth > 8) { | 
|  | // If we can't split in half, stop here. | 
|  | if (VecWidth & 1) | 
|  | break; | 
|  |  | 
|  | unsigned HalfSize = VecWidth / 2; | 
|  | APInt HighValue = SplatValue.extractBits(HalfSize, HalfSize); | 
|  | APInt LowValue = SplatValue.extractBits(HalfSize, 0); | 
|  | APInt HighUndef = SplatUndef.extractBits(HalfSize, HalfSize); | 
|  | APInt LowUndef = SplatUndef.extractBits(HalfSize, 0); | 
|  |  | 
|  | // If the two halves do not match (ignoring undef bits), stop here. | 
|  | if ((HighValue & ~LowUndef) != (LowValue & ~HighUndef) || | 
|  | MinSplatBits > HalfSize) | 
|  | break; | 
|  |  | 
|  | SplatValue = HighValue | LowValue; | 
|  | SplatUndef = HighUndef & LowUndef; | 
|  |  | 
|  | VecWidth = HalfSize; | 
|  | } | 
|  |  | 
|  | // FIXME: The loop above only tries to split in halves. But if the input | 
|  | // vector for example is <3 x i16> it wouldn't be able to detect a | 
|  | // SplatBitSize of 16. No idea if that is a design flaw currently limiting | 
|  | // optimizations. I guess that back in the days when this helper was created | 
|  | // vectors normally was power-of-2 sized. | 
|  |  | 
|  | SplatBitSize = VecWidth; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | SDValue BuildVectorSDNode::getSplatValue(const APInt &DemandedElts, | 
|  | BitVector *UndefElements) const { | 
|  | unsigned NumOps = getNumOperands(); | 
|  | if (UndefElements) { | 
|  | UndefElements->clear(); | 
|  | UndefElements->resize(NumOps); | 
|  | } | 
|  | assert(NumOps == DemandedElts.getBitWidth() && "Unexpected vector size"); | 
|  | if (!DemandedElts) | 
|  | return SDValue(); | 
|  | SDValue Splatted; | 
|  | for (unsigned i = 0; i != NumOps; ++i) { | 
|  | if (!DemandedElts[i]) | 
|  | continue; | 
|  | SDValue Op = getOperand(i); | 
|  | if (Op.isUndef()) { | 
|  | if (UndefElements) | 
|  | (*UndefElements)[i] = true; | 
|  | } else if (!Splatted) { | 
|  | Splatted = Op; | 
|  | } else if (Splatted != Op) { | 
|  | return SDValue(); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!Splatted) { | 
|  | unsigned FirstDemandedIdx = DemandedElts.countr_zero(); | 
|  | assert(getOperand(FirstDemandedIdx).isUndef() && | 
|  | "Can only have a splat without a constant for all undefs."); | 
|  | return getOperand(FirstDemandedIdx); | 
|  | } | 
|  |  | 
|  | return Splatted; | 
|  | } | 
|  |  | 
|  | SDValue BuildVectorSDNode::getSplatValue(BitVector *UndefElements) const { | 
|  | APInt DemandedElts = APInt::getAllOnes(getNumOperands()); | 
|  | return getSplatValue(DemandedElts, UndefElements); | 
|  | } | 
|  |  | 
|  | bool BuildVectorSDNode::getRepeatedSequence(const APInt &DemandedElts, | 
|  | SmallVectorImpl<SDValue> &Sequence, | 
|  | BitVector *UndefElements) const { | 
|  | unsigned NumOps = getNumOperands(); | 
|  | Sequence.clear(); | 
|  | if (UndefElements) { | 
|  | UndefElements->clear(); | 
|  | UndefElements->resize(NumOps); | 
|  | } | 
|  | assert(NumOps == DemandedElts.getBitWidth() && "Unexpected vector size"); | 
|  | if (!DemandedElts || NumOps < 2 || !isPowerOf2_32(NumOps)) | 
|  | return false; | 
|  |  | 
|  | // Set the undefs even if we don't find a sequence (like getSplatValue). | 
|  | if (UndefElements) | 
|  | for (unsigned I = 0; I != NumOps; ++I) | 
|  | if (DemandedElts[I] && getOperand(I).isUndef()) | 
|  | (*UndefElements)[I] = true; | 
|  |  | 
|  | // Iteratively widen the sequence length looking for repetitions. | 
|  | for (unsigned SeqLen = 1; SeqLen < NumOps; SeqLen *= 2) { | 
|  | Sequence.append(SeqLen, SDValue()); | 
|  | for (unsigned I = 0; I != NumOps; ++I) { | 
|  | if (!DemandedElts[I]) | 
|  | continue; | 
|  | SDValue &SeqOp = Sequence[I % SeqLen]; | 
|  | SDValue Op = getOperand(I); | 
|  | if (Op.isUndef()) { | 
|  | if (!SeqOp) | 
|  | SeqOp = Op; | 
|  | continue; | 
|  | } | 
|  | if (SeqOp && !SeqOp.isUndef() && SeqOp != Op) { | 
|  | Sequence.clear(); | 
|  | break; | 
|  | } | 
|  | SeqOp = Op; | 
|  | } | 
|  | if (!Sequence.empty()) | 
|  | return true; | 
|  | } | 
|  |  | 
|  | assert(Sequence.empty() && "Failed to empty non-repeating sequence pattern"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool BuildVectorSDNode::getRepeatedSequence(SmallVectorImpl<SDValue> &Sequence, | 
|  | BitVector *UndefElements) const { | 
|  | APInt DemandedElts = APInt::getAllOnes(getNumOperands()); | 
|  | return getRepeatedSequence(DemandedElts, Sequence, UndefElements); | 
|  | } | 
|  |  | 
|  | ConstantSDNode * | 
|  | BuildVectorSDNode::getConstantSplatNode(const APInt &DemandedElts, | 
|  | BitVector *UndefElements) const { | 
|  | return dyn_cast_or_null<ConstantSDNode>( | 
|  | getSplatValue(DemandedElts, UndefElements)); | 
|  | } | 
|  |  | 
|  | ConstantSDNode * | 
|  | BuildVectorSDNode::getConstantSplatNode(BitVector *UndefElements) const { | 
|  | return dyn_cast_or_null<ConstantSDNode>(getSplatValue(UndefElements)); | 
|  | } | 
|  |  | 
|  | ConstantFPSDNode * | 
|  | BuildVectorSDNode::getConstantFPSplatNode(const APInt &DemandedElts, | 
|  | BitVector *UndefElements) const { | 
|  | return dyn_cast_or_null<ConstantFPSDNode>( | 
|  | getSplatValue(DemandedElts, UndefElements)); | 
|  | } | 
|  |  | 
|  | ConstantFPSDNode * | 
|  | BuildVectorSDNode::getConstantFPSplatNode(BitVector *UndefElements) const { | 
|  | return dyn_cast_or_null<ConstantFPSDNode>(getSplatValue(UndefElements)); | 
|  | } | 
|  |  | 
|  | int32_t | 
|  | BuildVectorSDNode::getConstantFPSplatPow2ToLog2Int(BitVector *UndefElements, | 
|  | uint32_t BitWidth) const { | 
|  | if (ConstantFPSDNode *CN = | 
|  | dyn_cast_or_null<ConstantFPSDNode>(getSplatValue(UndefElements))) { | 
|  | bool IsExact; | 
|  | APSInt IntVal(BitWidth); | 
|  | const APFloat &APF = CN->getValueAPF(); | 
|  | if (APF.convertToInteger(IntVal, APFloat::rmTowardZero, &IsExact) != | 
|  | APFloat::opOK || | 
|  | !IsExact) | 
|  | return -1; | 
|  |  | 
|  | return IntVal.exactLogBase2(); | 
|  | } | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | bool BuildVectorSDNode::getConstantRawBits( | 
|  | bool IsLittleEndian, unsigned DstEltSizeInBits, | 
|  | SmallVectorImpl<APInt> &RawBitElements, BitVector &UndefElements) const { | 
|  | // Early-out if this contains anything but Undef/Constant/ConstantFP. | 
|  | if (!isConstant()) | 
|  | return false; | 
|  |  | 
|  | unsigned NumSrcOps = getNumOperands(); | 
|  | unsigned SrcEltSizeInBits = getValueType(0).getScalarSizeInBits(); | 
|  | assert(((NumSrcOps * SrcEltSizeInBits) % DstEltSizeInBits) == 0 && | 
|  | "Invalid bitcast scale"); | 
|  |  | 
|  | // Extract raw src bits. | 
|  | SmallVector<APInt> SrcBitElements(NumSrcOps, | 
|  | APInt::getZero(SrcEltSizeInBits)); | 
|  | BitVector SrcUndeElements(NumSrcOps, false); | 
|  |  | 
|  | for (unsigned I = 0; I != NumSrcOps; ++I) { | 
|  | SDValue Op = getOperand(I); | 
|  | if (Op.isUndef()) { | 
|  | SrcUndeElements.set(I); | 
|  | continue; | 
|  | } | 
|  | auto *CInt = dyn_cast<ConstantSDNode>(Op); | 
|  | auto *CFP = dyn_cast<ConstantFPSDNode>(Op); | 
|  | assert((CInt || CFP) && "Unknown constant"); | 
|  | SrcBitElements[I] = CInt ? CInt->getAPIntValue().trunc(SrcEltSizeInBits) | 
|  | : CFP->getValueAPF().bitcastToAPInt(); | 
|  | } | 
|  |  | 
|  | // Recast to dst width. | 
|  | recastRawBits(IsLittleEndian, DstEltSizeInBits, RawBitElements, | 
|  | SrcBitElements, UndefElements, SrcUndeElements); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void BuildVectorSDNode::recastRawBits(bool IsLittleEndian, | 
|  | unsigned DstEltSizeInBits, | 
|  | SmallVectorImpl<APInt> &DstBitElements, | 
|  | ArrayRef<APInt> SrcBitElements, | 
|  | BitVector &DstUndefElements, | 
|  | const BitVector &SrcUndefElements) { | 
|  | unsigned NumSrcOps = SrcBitElements.size(); | 
|  | unsigned SrcEltSizeInBits = SrcBitElements[0].getBitWidth(); | 
|  | assert(((NumSrcOps * SrcEltSizeInBits) % DstEltSizeInBits) == 0 && | 
|  | "Invalid bitcast scale"); | 
|  | assert(NumSrcOps == SrcUndefElements.size() && | 
|  | "Vector size mismatch"); | 
|  |  | 
|  | unsigned NumDstOps = (NumSrcOps * SrcEltSizeInBits) / DstEltSizeInBits; | 
|  | DstUndefElements.clear(); | 
|  | DstUndefElements.resize(NumDstOps, false); | 
|  | DstBitElements.assign(NumDstOps, APInt::getZero(DstEltSizeInBits)); | 
|  |  | 
|  | // Concatenate src elements constant bits together into dst element. | 
|  | if (SrcEltSizeInBits <= DstEltSizeInBits) { | 
|  | unsigned Scale = DstEltSizeInBits / SrcEltSizeInBits; | 
|  | for (unsigned I = 0; I != NumDstOps; ++I) { | 
|  | DstUndefElements.set(I); | 
|  | APInt &DstBits = DstBitElements[I]; | 
|  | for (unsigned J = 0; J != Scale; ++J) { | 
|  | unsigned Idx = (I * Scale) + (IsLittleEndian ? J : (Scale - J - 1)); | 
|  | if (SrcUndefElements[Idx]) | 
|  | continue; | 
|  | DstUndefElements.reset(I); | 
|  | const APInt &SrcBits = SrcBitElements[Idx]; | 
|  | assert(SrcBits.getBitWidth() == SrcEltSizeInBits && | 
|  | "Illegal constant bitwidths"); | 
|  | DstBits.insertBits(SrcBits, J * SrcEltSizeInBits); | 
|  | } | 
|  | } | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Split src element constant bits into dst elements. | 
|  | unsigned Scale = SrcEltSizeInBits / DstEltSizeInBits; | 
|  | for (unsigned I = 0; I != NumSrcOps; ++I) { | 
|  | if (SrcUndefElements[I]) { | 
|  | DstUndefElements.set(I * Scale, (I + 1) * Scale); | 
|  | continue; | 
|  | } | 
|  | const APInt &SrcBits = SrcBitElements[I]; | 
|  | for (unsigned J = 0; J != Scale; ++J) { | 
|  | unsigned Idx = (I * Scale) + (IsLittleEndian ? J : (Scale - J - 1)); | 
|  | APInt &DstBits = DstBitElements[Idx]; | 
|  | DstBits = SrcBits.extractBits(DstEltSizeInBits, J * DstEltSizeInBits); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | bool BuildVectorSDNode::isConstant() const { | 
|  | for (const SDValue &Op : op_values()) { | 
|  | unsigned Opc = Op.getOpcode(); | 
|  | if (!Op.isUndef() && Opc != ISD::Constant && Opc != ISD::ConstantFP) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | std::optional<std::pair<APInt, APInt>> | 
|  | BuildVectorSDNode::isConstantSequence() const { | 
|  | unsigned NumOps = getNumOperands(); | 
|  | if (NumOps < 2) | 
|  | return std::nullopt; | 
|  |  | 
|  | if (!isa<ConstantSDNode>(getOperand(0)) || | 
|  | !isa<ConstantSDNode>(getOperand(1))) | 
|  | return std::nullopt; | 
|  |  | 
|  | unsigned EltSize = getValueType(0).getScalarSizeInBits(); | 
|  | APInt Start = getConstantOperandAPInt(0).trunc(EltSize); | 
|  | APInt Stride = getConstantOperandAPInt(1).trunc(EltSize) - Start; | 
|  |  | 
|  | if (Stride.isZero()) | 
|  | return std::nullopt; | 
|  |  | 
|  | for (unsigned i = 2; i < NumOps; ++i) { | 
|  | if (!isa<ConstantSDNode>(getOperand(i))) | 
|  | return std::nullopt; | 
|  |  | 
|  | APInt Val = getConstantOperandAPInt(i).trunc(EltSize); | 
|  | if (Val != (Start + (Stride * i))) | 
|  | return std::nullopt; | 
|  | } | 
|  |  | 
|  | return std::make_pair(Start, Stride); | 
|  | } | 
|  |  | 
|  | bool ShuffleVectorSDNode::isSplatMask(ArrayRef<int> Mask) { | 
|  | // Find the first non-undef value in the shuffle mask. | 
|  | unsigned i, e; | 
|  | for (i = 0, e = Mask.size(); i != e && Mask[i] < 0; ++i) | 
|  | /* search */; | 
|  |  | 
|  | // If all elements are undefined, this shuffle can be considered a splat | 
|  | // (although it should eventually get simplified away completely). | 
|  | if (i == e) | 
|  | return true; | 
|  |  | 
|  | // Make sure all remaining elements are either undef or the same as the first | 
|  | // non-undef value. | 
|  | for (int Idx = Mask[i]; i != e; ++i) | 
|  | if (Mask[i] >= 0 && Mask[i] != Idx) | 
|  | return false; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Returns true if it is a constant integer BuildVector or constant integer, | 
|  | // possibly hidden by a bitcast. | 
|  | bool SelectionDAG::isConstantIntBuildVectorOrConstantInt( | 
|  | SDValue N, bool AllowOpaques) const { | 
|  | N = peekThroughBitcasts(N); | 
|  |  | 
|  | if (auto *C = dyn_cast<ConstantSDNode>(N)) | 
|  | return AllowOpaques || !C->isOpaque(); | 
|  |  | 
|  | if (ISD::isBuildVectorOfConstantSDNodes(N.getNode())) | 
|  | return true; | 
|  |  | 
|  | // Treat a GlobalAddress supporting constant offset folding as a | 
|  | // constant integer. | 
|  | if (auto *GA = dyn_cast<GlobalAddressSDNode>(N)) | 
|  | if (GA->getOpcode() == ISD::GlobalAddress && | 
|  | TLI->isOffsetFoldingLegal(GA)) | 
|  | return true; | 
|  |  | 
|  | if ((N.getOpcode() == ISD::SPLAT_VECTOR) && | 
|  | isa<ConstantSDNode>(N.getOperand(0))) | 
|  | return true; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Returns true if it is a constant float BuildVector or constant float. | 
|  | bool SelectionDAG::isConstantFPBuildVectorOrConstantFP(SDValue N) const { | 
|  | if (isa<ConstantFPSDNode>(N)) | 
|  | return true; | 
|  |  | 
|  | if (ISD::isBuildVectorOfConstantFPSDNodes(N.getNode())) | 
|  | return true; | 
|  |  | 
|  | if ((N.getOpcode() == ISD::SPLAT_VECTOR) && | 
|  | isa<ConstantFPSDNode>(N.getOperand(0))) | 
|  | return true; | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | std::optional<bool> SelectionDAG::isBoolConstant(SDValue N) const { | 
|  | ConstantSDNode *Const = | 
|  | isConstOrConstSplat(N, false, /*AllowTruncation=*/true); | 
|  | if (!Const) | 
|  | return std::nullopt; | 
|  |  | 
|  | EVT VT = N->getValueType(0); | 
|  | const APInt CVal = Const->getAPIntValue().trunc(VT.getScalarSizeInBits()); | 
|  | switch (TLI->getBooleanContents(N.getValueType())) { | 
|  | case TargetLowering::ZeroOrOneBooleanContent: | 
|  | if (CVal.isOne()) | 
|  | return true; | 
|  | if (CVal.isZero()) | 
|  | return false; | 
|  | return std::nullopt; | 
|  | case TargetLowering::ZeroOrNegativeOneBooleanContent: | 
|  | if (CVal.isAllOnes()) | 
|  | return true; | 
|  | if (CVal.isZero()) | 
|  | return false; | 
|  | return std::nullopt; | 
|  | case TargetLowering::UndefinedBooleanContent: | 
|  | return CVal[0]; | 
|  | } | 
|  | llvm_unreachable("Unknown BooleanContent enum"); | 
|  | } | 
|  |  | 
|  | void SelectionDAG::createOperands(SDNode *Node, ArrayRef<SDValue> Vals) { | 
|  | assert(!Node->OperandList && "Node already has operands"); | 
|  | assert(SDNode::getMaxNumOperands() >= Vals.size() && | 
|  | "too many operands to fit into SDNode"); | 
|  | SDUse *Ops = OperandRecycler.allocate( | 
|  | ArrayRecycler<SDUse>::Capacity::get(Vals.size()), OperandAllocator); | 
|  |  | 
|  | bool IsDivergent = false; | 
|  | for (unsigned I = 0; I != Vals.size(); ++I) { | 
|  | Ops[I].setUser(Node); | 
|  | Ops[I].setInitial(Vals[I]); | 
|  | EVT VT = Ops[I].getValueType(); | 
|  |  | 
|  | // Skip Chain. It does not carry divergence. | 
|  | if (VT != MVT::Other && | 
|  | (VT != MVT::Glue || gluePropagatesDivergence(Ops[I].getNode())) && | 
|  | Ops[I].getNode()->isDivergent()) { | 
|  | IsDivergent = true; | 
|  | } | 
|  | } | 
|  | Node->NumOperands = Vals.size(); | 
|  | Node->OperandList = Ops; | 
|  | if (!TLI->isSDNodeAlwaysUniform(Node)) { | 
|  | IsDivergent |= TLI->isSDNodeSourceOfDivergence(Node, FLI, UA); | 
|  | Node->SDNodeBits.IsDivergent = IsDivergent; | 
|  | } | 
|  | checkForCycles(Node); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getTokenFactor(const SDLoc &DL, | 
|  | SmallVectorImpl<SDValue> &Vals) { | 
|  | size_t Limit = SDNode::getMaxNumOperands(); | 
|  | while (Vals.size() > Limit) { | 
|  | unsigned SliceIdx = Vals.size() - Limit; | 
|  | auto ExtractedTFs = ArrayRef<SDValue>(Vals).slice(SliceIdx, Limit); | 
|  | SDValue NewTF = getNode(ISD::TokenFactor, DL, MVT::Other, ExtractedTFs); | 
|  | Vals.erase(Vals.begin() + SliceIdx, Vals.end()); | 
|  | Vals.emplace_back(NewTF); | 
|  | } | 
|  | return getNode(ISD::TokenFactor, DL, MVT::Other, Vals); | 
|  | } | 
|  |  | 
|  | SDValue SelectionDAG::getNeutralElement(unsigned Opcode, const SDLoc &DL, | 
|  | EVT VT, SDNodeFlags Flags) { | 
|  | switch (Opcode) { | 
|  | default: | 
|  | return SDValue(); | 
|  | case ISD::ADD: | 
|  | case ISD::OR: | 
|  | case ISD::XOR: | 
|  | case ISD::UMAX: | 
|  | return getConstant(0, DL, VT); | 
|  | case ISD::MUL: | 
|  | return getConstant(1, DL, VT); | 
|  | case ISD::AND: | 
|  | case ISD::UMIN: | 
|  | return getAllOnesConstant(DL, VT); | 
|  | case ISD::SMAX: | 
|  | return getConstant(APInt::getSignedMinValue(VT.getSizeInBits()), DL, VT); | 
|  | case ISD::SMIN: | 
|  | return getConstant(APInt::getSignedMaxValue(VT.getSizeInBits()), DL, VT); | 
|  | case ISD::FADD: | 
|  | // If flags allow, prefer positive zero since it's generally cheaper | 
|  | // to materialize on most targets. | 
|  | return getConstantFP(Flags.hasNoSignedZeros() ? 0.0 : -0.0, DL, VT); | 
|  | case ISD::FMUL: | 
|  | return getConstantFP(1.0, DL, VT); | 
|  | case ISD::FMINNUM: | 
|  | case ISD::FMAXNUM: { | 
|  | // Neutral element for fminnum is NaN, Inf or FLT_MAX, depending on FMF. | 
|  | const fltSemantics &Semantics = VT.getFltSemantics(); | 
|  | APFloat NeutralAF = !Flags.hasNoNaNs() ? APFloat::getQNaN(Semantics) : | 
|  | !Flags.hasNoInfs() ? APFloat::getInf(Semantics) : | 
|  | APFloat::getLargest(Semantics); | 
|  | if (Opcode == ISD::FMAXNUM) | 
|  | NeutralAF.changeSign(); | 
|  |  | 
|  | return getConstantFP(NeutralAF, DL, VT); | 
|  | } | 
|  | case ISD::FMINIMUM: | 
|  | case ISD::FMAXIMUM: { | 
|  | // Neutral element for fminimum is Inf or FLT_MAX, depending on FMF. | 
|  | const fltSemantics &Semantics = VT.getFltSemantics(); | 
|  | APFloat NeutralAF = !Flags.hasNoInfs() ? APFloat::getInf(Semantics) | 
|  | : APFloat::getLargest(Semantics); | 
|  | if (Opcode == ISD::FMAXIMUM) | 
|  | NeutralAF.changeSign(); | 
|  |  | 
|  | return getConstantFP(NeutralAF, DL, VT); | 
|  | } | 
|  |  | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Helper used to make a call to a library function that has one argument of | 
|  | /// pointer type. | 
|  | /// | 
|  | /// Such functions include 'fegetmode', 'fesetenv' and some others, which are | 
|  | /// used to get or set floating-point state. They have one argument of pointer | 
|  | /// type, which points to the memory region containing bits of the | 
|  | /// floating-point state. The value returned by such function is ignored in the | 
|  | /// created call. | 
|  | /// | 
|  | /// \param LibFunc Reference to library function (value of RTLIB::Libcall). | 
|  | /// \param Ptr Pointer used to save/load state. | 
|  | /// \param InChain Ingoing token chain. | 
|  | /// \returns Outgoing chain token. | 
|  | SDValue SelectionDAG::makeStateFunctionCall(unsigned LibFunc, SDValue Ptr, | 
|  | SDValue InChain, | 
|  | const SDLoc &DLoc) { | 
|  | assert(InChain.getValueType() == MVT::Other && "Expected token chain"); | 
|  | TargetLowering::ArgListTy Args; | 
|  | Args.emplace_back(Ptr, Ptr.getValueType().getTypeForEVT(*getContext())); | 
|  | RTLIB::Libcall LC = static_cast<RTLIB::Libcall>(LibFunc); | 
|  | SDValue Callee = getExternalSymbol(TLI->getLibcallName(LC), | 
|  | TLI->getPointerTy(getDataLayout())); | 
|  | TargetLowering::CallLoweringInfo CLI(*this); | 
|  | CLI.setDebugLoc(DLoc).setChain(InChain).setLibCallee( | 
|  | TLI->getLibcallCallingConv(LC), Type::getVoidTy(*getContext()), Callee, | 
|  | std::move(Args)); | 
|  | return TLI->LowerCallTo(CLI).second; | 
|  | } | 
|  |  | 
|  | void SelectionDAG::copyExtraInfo(SDNode *From, SDNode *To) { | 
|  | assert(From && To && "Invalid SDNode; empty source SDValue?"); | 
|  | auto I = SDEI.find(From); | 
|  | if (I == SDEI.end()) | 
|  | return; | 
|  |  | 
|  | // Use of operator[] on the DenseMap may cause an insertion, which invalidates | 
|  | // the iterator, hence the need to make a copy to prevent a use-after-free. | 
|  | NodeExtraInfo NEI = I->second; | 
|  | if (LLVM_LIKELY(!NEI.PCSections)) { | 
|  | // No deep copy required for the types of extra info set. | 
|  | // | 
|  | // FIXME: Investigate if other types of extra info also need deep copy. This | 
|  | // depends on the types of nodes they can be attached to: if some extra info | 
|  | // is only ever attached to nodes where a replacement To node is always the | 
|  | // node where later use and propagation of the extra info has the intended | 
|  | // semantics, no deep copy is required. | 
|  | SDEI[To] = std::move(NEI); | 
|  | return; | 
|  | } | 
|  |  | 
|  | const SDNode *EntrySDN = getEntryNode().getNode(); | 
|  |  | 
|  | // We need to copy NodeExtraInfo to all _new_ nodes that are being introduced | 
|  | // through the replacement of From with To. Otherwise, replacements of a node | 
|  | // (From) with more complex nodes (To and its operands) may result in lost | 
|  | // extra info where the root node (To) is insignificant in further propagating | 
|  | // and using extra info when further lowering to MIR. | 
|  | // | 
|  | // In the first step pre-populate the visited set with the nodes reachable | 
|  | // from the old From node. This avoids copying NodeExtraInfo to parts of the | 
|  | // DAG that is not new and should be left untouched. | 
|  | SmallVector<const SDNode *> Leafs{From}; // Leafs reachable with VisitFrom. | 
|  | DenseSet<const SDNode *> FromReach; // The set of nodes reachable from From. | 
|  | auto VisitFrom = [&](auto &&Self, const SDNode *N, int MaxDepth) { | 
|  | if (MaxDepth == 0) { | 
|  | // Remember this node in case we need to increase MaxDepth and continue | 
|  | // populating FromReach from this node. | 
|  | Leafs.emplace_back(N); | 
|  | return; | 
|  | } | 
|  | if (!FromReach.insert(N).second) | 
|  | return; | 
|  | for (const SDValue &Op : N->op_values()) | 
|  | Self(Self, Op.getNode(), MaxDepth - 1); | 
|  | }; | 
|  |  | 
|  | // Copy extra info to To and all its transitive operands (that are new). | 
|  | SmallPtrSet<const SDNode *, 8> Visited; | 
|  | auto DeepCopyTo = [&](auto &&Self, const SDNode *N) { | 
|  | if (FromReach.contains(N)) | 
|  | return true; | 
|  | if (!Visited.insert(N).second) | 
|  | return true; | 
|  | if (EntrySDN == N) | 
|  | return false; | 
|  | for (const SDValue &Op : N->op_values()) { | 
|  | if (N == To && Op.getNode() == EntrySDN) { | 
|  | // Special case: New node's operand is the entry node; just need to | 
|  | // copy extra info to new node. | 
|  | break; | 
|  | } | 
|  | if (!Self(Self, Op.getNode())) | 
|  | return false; | 
|  | } | 
|  | // Copy only if entry node was not reached. | 
|  | SDEI[N] = NEI; | 
|  | return true; | 
|  | }; | 
|  |  | 
|  | // We first try with a lower MaxDepth, assuming that the path to common | 
|  | // operands between From and To is relatively short. This significantly | 
|  | // improves performance in the common case. The initial MaxDepth is big | 
|  | // enough to avoid retry in the common case; the last MaxDepth is large | 
|  | // enough to avoid having to use the fallback below (and protects from | 
|  | // potential stack exhaustion from recursion). | 
|  | for (int PrevDepth = 0, MaxDepth = 16; MaxDepth <= 1024; | 
|  | PrevDepth = MaxDepth, MaxDepth *= 2, Visited.clear()) { | 
|  | // StartFrom is the previous (or initial) set of leafs reachable at the | 
|  | // previous maximum depth. | 
|  | SmallVector<const SDNode *> StartFrom; | 
|  | std::swap(StartFrom, Leafs); | 
|  | for (const SDNode *N : StartFrom) | 
|  | VisitFrom(VisitFrom, N, MaxDepth - PrevDepth); | 
|  | if (LLVM_LIKELY(DeepCopyTo(DeepCopyTo, To))) | 
|  | return; | 
|  | // This should happen very rarely (reached the entry node). | 
|  | LLVM_DEBUG(dbgs() << __func__ << ": MaxDepth=" << MaxDepth << " too low\n"); | 
|  | assert(!Leafs.empty()); | 
|  | } | 
|  |  | 
|  | // This should not happen - but if it did, that means the subgraph reachable | 
|  | // from From has depth greater or equal to maximum MaxDepth, and VisitFrom() | 
|  | // could not visit all reachable common operands. Consequently, we were able | 
|  | // to reach the entry node. | 
|  | errs() << "warning: incomplete propagation of SelectionDAG::NodeExtraInfo\n"; | 
|  | assert(false && "From subgraph too complex - increase max. MaxDepth?"); | 
|  | // Best-effort fallback if assertions disabled. | 
|  | SDEI[To] = std::move(NEI); | 
|  | } | 
|  |  | 
|  | #ifndef NDEBUG | 
|  | static void checkForCyclesHelper(const SDNode *N, | 
|  | SmallPtrSetImpl<const SDNode*> &Visited, | 
|  | SmallPtrSetImpl<const SDNode*> &Checked, | 
|  | const llvm::SelectionDAG *DAG) { | 
|  | // If this node has already been checked, don't check it again. | 
|  | if (Checked.count(N)) | 
|  | return; | 
|  |  | 
|  | // If a node has already been visited on this depth-first walk, reject it as | 
|  | // a cycle. | 
|  | if (!Visited.insert(N).second) { | 
|  | errs() << "Detected cycle in SelectionDAG\n"; | 
|  | dbgs() << "Offending node:\n"; | 
|  | N->dumprFull(DAG); dbgs() << "\n"; | 
|  | abort(); | 
|  | } | 
|  |  | 
|  | for (const SDValue &Op : N->op_values()) | 
|  | checkForCyclesHelper(Op.getNode(), Visited, Checked, DAG); | 
|  |  | 
|  | Checked.insert(N); | 
|  | Visited.erase(N); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | void llvm::checkForCycles(const llvm::SDNode *N, | 
|  | const llvm::SelectionDAG *DAG, | 
|  | bool force) { | 
|  | #ifndef NDEBUG | 
|  | bool check = force; | 
|  | #ifdef EXPENSIVE_CHECKS | 
|  | check = true; | 
|  | #endif  // EXPENSIVE_CHECKS | 
|  | if (check) { | 
|  | assert(N && "Checking nonexistent SDNode"); | 
|  | SmallPtrSet<const SDNode*, 32> visited; | 
|  | SmallPtrSet<const SDNode*, 32> checked; | 
|  | checkForCyclesHelper(N, visited, checked, DAG); | 
|  | } | 
|  | #endif  // !NDEBUG | 
|  | } | 
|  |  | 
|  | void llvm::checkForCycles(const llvm::SelectionDAG *DAG, bool force) { | 
|  | checkForCycles(DAG->getRoot().getNode(), DAG, force); | 
|  | } |