Vendor import of llvm release_70 branch r348686:
https://llvm.org/svn/llvm-project/llvm/branches/release_70@348686
This commit is contained in:
parent
d17fea9f41
commit
cfd4990248
@ -30,8 +30,6 @@ class GSIHashIterator
|
||||
GSIHashIterator, FixedStreamArrayIterator<PSHashRecord>,
|
||||
std::random_access_iterator_tag, const uint32_t> {
|
||||
public:
|
||||
GSIHashIterator() = default;
|
||||
|
||||
template <typename T>
|
||||
GSIHashIterator(T &&v)
|
||||
: GSIHashIterator::iterator_adaptor_base(std::forward<T &&>(v)) {}
|
||||
|
@ -49,7 +49,7 @@ class ModuleDebugStreamRef {
|
||||
BinarySubstreamRef getC13LinesSubstream() const;
|
||||
BinarySubstreamRef getGlobalRefsSubstream() const;
|
||||
|
||||
ModuleDebugStreamRef &operator=(ModuleDebugStreamRef &&Other) = default;
|
||||
ModuleDebugStreamRef &operator=(ModuleDebugStreamRef &&Other) = delete;
|
||||
|
||||
iterator_range<DebugSubsectionIterator> subsections() const;
|
||||
codeview::DebugSubsectionArray getSubsectionsArray() const {
|
||||
|
@ -126,7 +126,7 @@ class MaterializationResponsibility {
|
||||
public:
|
||||
MaterializationResponsibility(MaterializationResponsibility &&) = default;
|
||||
MaterializationResponsibility &
|
||||
operator=(MaterializationResponsibility &&) = default;
|
||||
operator=(MaterializationResponsibility &&) = delete;
|
||||
|
||||
/// Destruct a MaterializationResponsibility instance. In debug mode
|
||||
/// this asserts that all symbols being tracked have been either
|
||||
|
@ -70,8 +70,7 @@ class OrcRemoteTargetClient
|
||||
RemoteRTDyldMemoryManager &
|
||||
operator=(const RemoteRTDyldMemoryManager &) = delete;
|
||||
RemoteRTDyldMemoryManager(RemoteRTDyldMemoryManager &&) = default;
|
||||
RemoteRTDyldMemoryManager &
|
||||
operator=(RemoteRTDyldMemoryManager &&) = default;
|
||||
RemoteRTDyldMemoryManager &operator=(RemoteRTDyldMemoryManager &&) = delete;
|
||||
|
||||
uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
|
||||
unsigned SectionID,
|
||||
|
@ -641,8 +641,6 @@ class LineCoverageIterator
|
||||
this->operator++();
|
||||
}
|
||||
|
||||
LineCoverageIterator &operator=(const LineCoverageIterator &R) = default;
|
||||
|
||||
bool operator==(const LineCoverageIterator &R) const {
|
||||
return &CD == &R.CD && Next == R.Next && Ended == R.Ended;
|
||||
}
|
||||
|
@ -119,7 +119,6 @@ class MemoryLocOrCall {
|
||||
public:
|
||||
bool IsCall = false;
|
||||
|
||||
MemoryLocOrCall() = default;
|
||||
MemoryLocOrCall(MemoryUseOrDef *MUD)
|
||||
: MemoryLocOrCall(MUD->getMemoryInst()) {}
|
||||
MemoryLocOrCall(const MemoryUseOrDef *MUD)
|
||||
|
@ -275,7 +275,7 @@ RuntimeDyldImpl::loadObjectImpl(const object::ObjectFile &Obj) {
|
||||
uint64_t Size = I->getCommonSize();
|
||||
if (!CommonAlign)
|
||||
CommonAlign = Align;
|
||||
CommonSize += alignTo(CommonSize, Align) + Size;
|
||||
CommonSize = alignTo(CommonSize, Align) + Size;
|
||||
CommonSymbolsToAllocate.push_back(*I);
|
||||
}
|
||||
} else
|
||||
|
@ -1515,39 +1515,50 @@ static SDValue emitComparison(SDValue LHS, SDValue RHS, ISD::CondCode CC,
|
||||
/// The CCMP/CCMN/FCCMP/FCCMPE instructions allow the conditional execution of
|
||||
/// a comparison. They set the NZCV flags to a predefined value if their
|
||||
/// predicate is false. This allows to express arbitrary conjunctions, for
|
||||
/// example "cmp 0 (and (setCA (cmp A)) (setCB (cmp B))))"
|
||||
/// example "cmp 0 (and (setCA (cmp A)) (setCB (cmp B)))"
|
||||
/// expressed as:
|
||||
/// cmp A
|
||||
/// ccmp B, inv(CB), CA
|
||||
/// check for CB flags
|
||||
///
|
||||
/// In general we can create code for arbitrary "... (and (and A B) C)"
|
||||
/// sequences. We can also implement some "or" expressions, because "(or A B)"
|
||||
/// is equivalent to "not (and (not A) (not B))" and we can implement some
|
||||
/// negation operations:
|
||||
/// We can negate the results of a single comparison by inverting the flags
|
||||
/// used when the predicate fails and inverting the flags tested in the next
|
||||
/// instruction; We can also negate the results of the whole previous
|
||||
/// conditional compare sequence by inverting the flags tested in the next
|
||||
/// instruction. However there is no way to negate the result of a partial
|
||||
/// sequence.
|
||||
/// This naturally lets us implement chains of AND operations with SETCC
|
||||
/// operands. And we can even implement some other situations by transforming
|
||||
/// them:
|
||||
/// - We can implement (NEG SETCC) i.e. negating a single comparison by
|
||||
/// negating the flags used in a CCMP/FCCMP operations.
|
||||
/// - We can negate the result of a whole chain of CMP/CCMP/FCCMP operations
|
||||
/// by negating the flags we test for afterwards. i.e.
|
||||
/// NEG (CMP CCMP CCCMP ...) can be implemented.
|
||||
/// - Note that we can only ever negate all previously processed results.
|
||||
/// What we can not implement by flipping the flags to test is a negation
|
||||
/// of two sub-trees (because the negation affects all sub-trees emitted so
|
||||
/// far, so the 2nd sub-tree we emit would also affect the first).
|
||||
/// With those tools we can implement some OR operations:
|
||||
/// - (OR (SETCC A) (SETCC B)) can be implemented via:
|
||||
/// NEG (AND (NEG (SETCC A)) (NEG (SETCC B)))
|
||||
/// - After transforming OR to NEG/AND combinations we may be able to use NEG
|
||||
/// elimination rules from earlier to implement the whole thing as a
|
||||
/// CCMP/FCCMP chain.
|
||||
///
|
||||
/// Therefore on encountering an "or" expression we can negate the subtree on
|
||||
/// one side and have to be able to push the negate to the leafs of the subtree
|
||||
/// on the other side (see also the comments in code). As complete example:
|
||||
/// "or (or (setCA (cmp A)) (setCB (cmp B)))
|
||||
/// (and (setCC (cmp C)) (setCD (cmp D)))"
|
||||
/// is transformed to
|
||||
/// "not (and (not (and (setCC (cmp C)) (setCC (cmp D))))
|
||||
/// (and (not (setCA (cmp A)) (not (setCB (cmp B))))))"
|
||||
/// and implemented as:
|
||||
/// As complete example:
|
||||
/// or (or (setCA (cmp A)) (setCB (cmp B)))
|
||||
/// (and (setCC (cmp C)) (setCD (cmp D)))"
|
||||
/// can be reassociated to:
|
||||
/// or (and (setCC (cmp C)) setCD (cmp D))
|
||||
// (or (setCA (cmp A)) (setCB (cmp B)))
|
||||
/// can be transformed to:
|
||||
/// not (and (not (and (setCC (cmp C)) (setCD (cmp D))))
|
||||
/// (and (not (setCA (cmp A)) (not (setCB (cmp B))))))"
|
||||
/// which can be implemented as:
|
||||
/// cmp C
|
||||
/// ccmp D, inv(CD), CC
|
||||
/// ccmp A, CA, inv(CD)
|
||||
/// ccmp B, CB, inv(CA)
|
||||
/// check for CB flags
|
||||
/// A counterexample is "or (and A B) (and C D)" which cannot be implemented
|
||||
/// by conditional compare sequences.
|
||||
///
|
||||
/// A counterexample is "or (and A B) (and C D)" which translates to
|
||||
/// not (and (not (and (not A) (not B))) (not (and (not C) (not D)))), we
|
||||
/// can only implement 1 of the inner (not) operations, but not both!
|
||||
/// @{
|
||||
|
||||
/// Create a conditional comparison; Use CCMP, CCMN or FCCMP as appropriate.
|
||||
@ -1585,14 +1596,23 @@ static SDValue emitConditionalComparison(SDValue LHS, SDValue RHS,
|
||||
return DAG.getNode(Opcode, DL, MVT_CC, LHS, RHS, NZCVOp, Condition, CCOp);
|
||||
}
|
||||
|
||||
/// Returns true if @p Val is a tree of AND/OR/SETCC operations.
|
||||
/// CanPushNegate is set to true if we can push a negate operation through
|
||||
/// the tree in a was that we are left with AND operations and negate operations
|
||||
/// at the leafs only. i.e. "not (or (or x y) z)" can be changed to
|
||||
/// "and (and (not x) (not y)) (not z)"; "not (or (and x y) z)" cannot be
|
||||
/// brought into such a form.
|
||||
static bool isConjunctionDisjunctionTree(const SDValue Val, bool &CanNegate,
|
||||
unsigned Depth = 0) {
|
||||
/// Returns true if @p Val is a tree of AND/OR/SETCC operations that can be
|
||||
/// expressed as a conjunction. See \ref AArch64CCMP.
|
||||
/// \param CanNegate Set to true if we can negate the whole sub-tree just by
|
||||
/// changing the conditions on the SETCC tests.
|
||||
/// (this means we can call emitConjunctionRec() with
|
||||
/// Negate==true on this sub-tree)
|
||||
/// \param MustBeFirst Set to true if this subtree needs to be negated and we
|
||||
/// cannot do the negation naturally. We are required to
|
||||
/// emit the subtree first in this case.
|
||||
/// \param WillNegate Is true if are called when the result of this
|
||||
/// subexpression must be negated. This happens when the
|
||||
/// outer expression is an OR. We can use this fact to know
|
||||
/// that we have a double negation (or (or ...) ...) that
|
||||
/// can be implemented for free.
|
||||
static bool canEmitConjunction(const SDValue Val, bool &CanNegate,
|
||||
bool &MustBeFirst, bool WillNegate,
|
||||
unsigned Depth = 0) {
|
||||
if (!Val.hasOneUse())
|
||||
return false;
|
||||
unsigned Opcode = Val->getOpcode();
|
||||
@ -1600,39 +1620,44 @@ static bool isConjunctionDisjunctionTree(const SDValue Val, bool &CanNegate,
|
||||
if (Val->getOperand(0).getValueType() == MVT::f128)
|
||||
return false;
|
||||
CanNegate = true;
|
||||
MustBeFirst = false;
|
||||
return true;
|
||||
}
|
||||
// Protect against exponential runtime and stack overflow.
|
||||
if (Depth > 6)
|
||||
return false;
|
||||
if (Opcode == ISD::AND || Opcode == ISD::OR) {
|
||||
bool IsOR = Opcode == ISD::OR;
|
||||
SDValue O0 = Val->getOperand(0);
|
||||
SDValue O1 = Val->getOperand(1);
|
||||
bool CanNegateL;
|
||||
if (!isConjunctionDisjunctionTree(O0, CanNegateL, Depth+1))
|
||||
bool MustBeFirstL;
|
||||
if (!canEmitConjunction(O0, CanNegateL, MustBeFirstL, IsOR, Depth+1))
|
||||
return false;
|
||||
bool CanNegateR;
|
||||
if (!isConjunctionDisjunctionTree(O1, CanNegateR, Depth+1))
|
||||
bool MustBeFirstR;
|
||||
if (!canEmitConjunction(O1, CanNegateR, MustBeFirstR, IsOR, Depth+1))
|
||||
return false;
|
||||
|
||||
if (Opcode == ISD::OR) {
|
||||
// For an OR expression we need to be able to negate at least one side or
|
||||
// we cannot do the transformation at all.
|
||||
if (MustBeFirstL && MustBeFirstR)
|
||||
return false;
|
||||
|
||||
if (IsOR) {
|
||||
// For an OR expression we need to be able to naturally negate at least
|
||||
// one side or we cannot do the transformation at all.
|
||||
if (!CanNegateL && !CanNegateR)
|
||||
return false;
|
||||
// We can however change a (not (or x y)) to (and (not x) (not y)) if we
|
||||
// can negate the x and y subtrees.
|
||||
CanNegate = CanNegateL && CanNegateR;
|
||||
// If we the result of the OR will be negated and we can naturally negate
|
||||
// the leafs, then this sub-tree as a whole negates naturally.
|
||||
CanNegate = WillNegate && CanNegateL && CanNegateR;
|
||||
// If we cannot naturally negate the whole sub-tree, then this must be
|
||||
// emitted first.
|
||||
MustBeFirst = !CanNegate;
|
||||
} else {
|
||||
// If the operands are OR expressions then we finally need to negate their
|
||||
// outputs, we can only do that for the operand with emitted last by
|
||||
// negating OutCC, not for both operands.
|
||||
bool NeedsNegOutL = O0->getOpcode() == ISD::OR;
|
||||
bool NeedsNegOutR = O1->getOpcode() == ISD::OR;
|
||||
if (NeedsNegOutL && NeedsNegOutR)
|
||||
return false;
|
||||
// We cannot negate an AND operation (it would become an OR),
|
||||
assert(Opcode == ISD::AND && "Must be OR or AND");
|
||||
// We cannot naturally negate an AND operation.
|
||||
CanNegate = false;
|
||||
MustBeFirst = MustBeFirstL || MustBeFirstR;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -1645,11 +1670,9 @@ static bool isConjunctionDisjunctionTree(const SDValue Val, bool &CanNegate,
|
||||
/// and conditional compare operations. @returns an NZCV flags producing node
|
||||
/// and sets @p OutCC to the flags that should be tested or returns SDValue() if
|
||||
/// transformation was not possible.
|
||||
/// On recursive invocations @p PushNegate may be set to true to have negation
|
||||
/// effects pushed to the tree leafs; @p Predicate is an NZCV flag predicate
|
||||
/// for the comparisons in the current subtree; @p Depth limits the search
|
||||
/// depth to avoid stack overflow.
|
||||
static SDValue emitConjunctionDisjunctionTreeRec(SelectionDAG &DAG, SDValue Val,
|
||||
/// \p Negate is true if we want this sub-tree being negated just by changing
|
||||
/// SETCC conditions.
|
||||
static SDValue emitConjunctionRec(SelectionDAG &DAG, SDValue Val,
|
||||
AArch64CC::CondCode &OutCC, bool Negate, SDValue CCOp,
|
||||
AArch64CC::CondCode Predicate) {
|
||||
// We're at a tree leaf, produce a conditional comparison operation.
|
||||
@ -1690,76 +1713,85 @@ static SDValue emitConjunctionDisjunctionTreeRec(SelectionDAG &DAG, SDValue Val,
|
||||
return emitConditionalComparison(LHS, RHS, CC, CCOp, Predicate, OutCC, DL,
|
||||
DAG);
|
||||
}
|
||||
assert((Opcode == ISD::AND || (Opcode == ISD::OR && Val->hasOneUse())) &&
|
||||
"Valid conjunction/disjunction tree");
|
||||
assert(Val->hasOneUse() && "Valid conjunction/disjunction tree");
|
||||
|
||||
bool IsOR = Opcode == ISD::OR;
|
||||
|
||||
// Check if both sides can be transformed.
|
||||
SDValue LHS = Val->getOperand(0);
|
||||
bool CanNegateL;
|
||||
bool MustBeFirstL;
|
||||
bool ValidL = canEmitConjunction(LHS, CanNegateL, MustBeFirstL, IsOR);
|
||||
assert(ValidL && "Valid conjunction/disjunction tree");
|
||||
(void)ValidL;
|
||||
|
||||
SDValue RHS = Val->getOperand(1);
|
||||
bool CanNegateR;
|
||||
bool MustBeFirstR;
|
||||
bool ValidR = canEmitConjunction(RHS, CanNegateR, MustBeFirstR, IsOR);
|
||||
assert(ValidR && "Valid conjunction/disjunction tree");
|
||||
(void)ValidR;
|
||||
|
||||
// In case of an OR we need to negate our operands and the result.
|
||||
// (A v B) <=> not(not(A) ^ not(B))
|
||||
bool NegateOpsAndResult = Opcode == ISD::OR;
|
||||
// We can negate the results of all previous operations by inverting the
|
||||
// predicate flags giving us a free negation for one side. The other side
|
||||
// must be negatable by itself.
|
||||
if (NegateOpsAndResult) {
|
||||
// See which side we can negate.
|
||||
bool CanNegateL;
|
||||
bool isValidL = isConjunctionDisjunctionTree(LHS, CanNegateL);
|
||||
assert(isValidL && "Valid conjunction/disjunction tree");
|
||||
(void)isValidL;
|
||||
|
||||
#ifndef NDEBUG
|
||||
bool CanNegateR;
|
||||
bool isValidR = isConjunctionDisjunctionTree(RHS, CanNegateR);
|
||||
assert(isValidR && "Valid conjunction/disjunction tree");
|
||||
assert((CanNegateL || CanNegateR) && "Valid conjunction/disjunction tree");
|
||||
#endif
|
||||
|
||||
// Order the side which we cannot negate to RHS so we can emit it first.
|
||||
if (!CanNegateL)
|
||||
std::swap(LHS, RHS);
|
||||
} else {
|
||||
bool NeedsNegOutL = LHS->getOpcode() == ISD::OR;
|
||||
assert((!NeedsNegOutL || RHS->getOpcode() != ISD::OR) &&
|
||||
"Valid conjunction/disjunction tree");
|
||||
// Order the side where we need to negate the output flags to RHS so it
|
||||
// gets emitted first.
|
||||
if (NeedsNegOutL)
|
||||
std::swap(LHS, RHS);
|
||||
// Swap sub-tree that must come first to the right side.
|
||||
if (MustBeFirstL) {
|
||||
assert(!MustBeFirstR && "Valid conjunction/disjunction tree");
|
||||
std::swap(LHS, RHS);
|
||||
std::swap(CanNegateL, CanNegateR);
|
||||
std::swap(MustBeFirstL, MustBeFirstR);
|
||||
}
|
||||
|
||||
// Emit RHS. If we want to negate the tree we only need to push a negate
|
||||
// through if we are already in a PushNegate case, otherwise we can negate
|
||||
// the "flags to test" afterwards.
|
||||
bool NegateR;
|
||||
bool NegateAfterR;
|
||||
bool NegateL;
|
||||
bool NegateAfterAll;
|
||||
if (Opcode == ISD::OR) {
|
||||
// Swap the sub-tree that we can negate naturally to the left.
|
||||
if (!CanNegateL) {
|
||||
assert(CanNegateR && "at least one side must be negatable");
|
||||
assert(!MustBeFirstR && "invalid conjunction/disjunction tree");
|
||||
assert(!Negate);
|
||||
std::swap(LHS, RHS);
|
||||
NegateR = false;
|
||||
NegateAfterR = true;
|
||||
} else {
|
||||
// Negate the left sub-tree if possible, otherwise negate the result.
|
||||
NegateR = CanNegateR;
|
||||
NegateAfterR = !CanNegateR;
|
||||
}
|
||||
NegateL = true;
|
||||
NegateAfterAll = !Negate;
|
||||
} else {
|
||||
assert(Opcode == ISD::AND && "Valid conjunction/disjunction tree");
|
||||
assert(!Negate && "Valid conjunction/disjunction tree");
|
||||
|
||||
NegateL = false;
|
||||
NegateR = false;
|
||||
NegateAfterR = false;
|
||||
NegateAfterAll = false;
|
||||
}
|
||||
|
||||
// Emit sub-trees.
|
||||
AArch64CC::CondCode RHSCC;
|
||||
SDValue CmpR = emitConjunctionDisjunctionTreeRec(DAG, RHS, RHSCC, Negate,
|
||||
CCOp, Predicate);
|
||||
if (NegateOpsAndResult && !Negate)
|
||||
SDValue CmpR = emitConjunctionRec(DAG, RHS, RHSCC, NegateR, CCOp, Predicate);
|
||||
if (NegateAfterR)
|
||||
RHSCC = AArch64CC::getInvertedCondCode(RHSCC);
|
||||
// Emit LHS. We may need to negate it.
|
||||
SDValue CmpL = emitConjunctionDisjunctionTreeRec(DAG, LHS, OutCC,
|
||||
NegateOpsAndResult, CmpR,
|
||||
RHSCC);
|
||||
// If we transformed an OR to and AND then we have to negate the result
|
||||
// (or absorb the Negate parameter).
|
||||
if (NegateOpsAndResult && !Negate)
|
||||
SDValue CmpL = emitConjunctionRec(DAG, LHS, OutCC, NegateL, CmpR, RHSCC);
|
||||
if (NegateAfterAll)
|
||||
OutCC = AArch64CC::getInvertedCondCode(OutCC);
|
||||
return CmpL;
|
||||
}
|
||||
|
||||
/// Emit conjunction or disjunction tree with the CMP/FCMP followed by a chain
|
||||
/// of CCMP/CFCMP ops. See @ref AArch64CCMP.
|
||||
/// \see emitConjunctionDisjunctionTreeRec().
|
||||
static SDValue emitConjunctionDisjunctionTree(SelectionDAG &DAG, SDValue Val,
|
||||
AArch64CC::CondCode &OutCC) {
|
||||
bool CanNegate;
|
||||
if (!isConjunctionDisjunctionTree(Val, CanNegate))
|
||||
/// Emit expression as a conjunction (a series of CCMP/CFCMP ops).
|
||||
/// In some cases this is even possible with OR operations in the expression.
|
||||
/// See \ref AArch64CCMP.
|
||||
/// \see emitConjunctionRec().
|
||||
static SDValue emitConjunction(SelectionDAG &DAG, SDValue Val,
|
||||
AArch64CC::CondCode &OutCC) {
|
||||
bool DummyCanNegate;
|
||||
bool DummyMustBeFirst;
|
||||
if (!canEmitConjunction(Val, DummyCanNegate, DummyMustBeFirst, false))
|
||||
return SDValue();
|
||||
|
||||
return emitConjunctionDisjunctionTreeRec(DAG, Val, OutCC, false, SDValue(),
|
||||
AArch64CC::AL);
|
||||
return emitConjunctionRec(DAG, Val, OutCC, false, SDValue(), AArch64CC::AL);
|
||||
}
|
||||
|
||||
/// @}
|
||||
@ -1859,7 +1891,7 @@ static SDValue getAArch64Cmp(SDValue LHS, SDValue RHS, ISD::CondCode CC,
|
||||
}
|
||||
|
||||
if (!Cmp && (RHSC->isNullValue() || RHSC->isOne())) {
|
||||
if ((Cmp = emitConjunctionDisjunctionTree(DAG, LHS, AArch64CC))) {
|
||||
if ((Cmp = emitConjunction(DAG, LHS, AArch64CC))) {
|
||||
if ((CC == ISD::SETNE) ^ RHSC->isNullValue())
|
||||
AArch64CC = AArch64CC::getInvertedCondCode(AArch64CC);
|
||||
}
|
||||
|
@ -90,7 +90,6 @@ class UnmangledFuncInfo {
|
||||
|
||||
public:
|
||||
using ID = AMDGPULibFunc::EFuncId;
|
||||
UnmangledFuncInfo() = default;
|
||||
UnmangledFuncInfo(StringRef _Name, unsigned _NumArgs)
|
||||
: Name(_Name), NumArgs(_NumArgs) {}
|
||||
// Get index to Table by function name.
|
||||
|
@ -2924,12 +2924,20 @@ static Value *foldICmpWithLowBitMaskedVal(ICmpInst &I,
|
||||
// x & (-1 >> y) s>= x -> x s<= (-1 >> y)
|
||||
if (X != I.getOperand(1)) // X must be on RHS of comparison!
|
||||
return nullptr; // Ignore the other case.
|
||||
if (!match(M, m_Constant())) // Can not do this fold with non-constant.
|
||||
return nullptr;
|
||||
if (!match(M, m_NonNegative())) // Must not have any -1 vector elements.
|
||||
return nullptr;
|
||||
DstPred = ICmpInst::Predicate::ICMP_SLE;
|
||||
break;
|
||||
case ICmpInst::Predicate::ICMP_SLT:
|
||||
// x & (-1 >> y) s< x -> x s> (-1 >> y)
|
||||
if (X != I.getOperand(1)) // X must be on RHS of comparison!
|
||||
return nullptr; // Ignore the other case.
|
||||
if (!match(M, m_Constant())) // Can not do this fold with non-constant.
|
||||
return nullptr;
|
||||
if (!match(M, m_NonNegative())) // Must not have any -1 vector elements.
|
||||
return nullptr;
|
||||
DstPred = ICmpInst::Predicate::ICMP_SGT;
|
||||
break;
|
||||
case ICmpInst::Predicate::ICMP_SLE:
|
||||
|
@ -231,17 +231,17 @@ struct TransformedFunction {
|
||||
TransformedFunction& operator=(TransformedFunction&&) = default;
|
||||
|
||||
/// Type of the function before the transformation.
|
||||
FunctionType* const OriginalType;
|
||||
FunctionType *OriginalType;
|
||||
|
||||
/// Type of the function after the transformation.
|
||||
FunctionType* const TransformedType;
|
||||
FunctionType *TransformedType;
|
||||
|
||||
/// Transforming a function may change the position of arguments. This
|
||||
/// member records the mapping from each argument's old position to its new
|
||||
/// position. Argument positions are zero-indexed. If the transformation
|
||||
/// from F to F' made the first argument of F into the third argument of F',
|
||||
/// then ArgumentIndexMapping[0] will equal 2.
|
||||
const std::vector<unsigned> ArgumentIndexMapping;
|
||||
std::vector<unsigned> ArgumentIndexMapping;
|
||||
};
|
||||
|
||||
/// Given function attributes from a call site for the original function,
|
||||
|
@ -526,8 +526,8 @@ define i32 @select_or_olt_one(double %v0, double %v1, double %v2, double %v3, i3
|
||||
; CHECK-LABEL: select_or_one_olt:
|
||||
; CHECK-LABEL: ; %bb.0:
|
||||
; CHECK-NEXT: fcmp d0, d1
|
||||
; CHECK-NEXT: fccmp d0, d1, #1, ne
|
||||
; CHECK-NEXT: fccmp d2, d3, #8, vs
|
||||
; CHECK-NEXT: fccmp d0, d1, #8, le
|
||||
; CHECK-NEXT: fccmp d2, d3, #8, pl
|
||||
; CHECK-NEXT: csel w0, w0, w1, mi
|
||||
; CHECK-NEXT: ret
|
||||
define i32 @select_or_one_olt(double %v0, double %v1, double %v2, double %v3, i32 %a, i32 %b) #0 {
|
||||
@ -556,8 +556,8 @@ define i32 @select_or_olt_ueq(double %v0, double %v1, double %v2, double %v3, i3
|
||||
; CHECK-LABEL: select_or_ueq_olt:
|
||||
; CHECK-LABEL: ; %bb.0:
|
||||
; CHECK-NEXT: fcmp d0, d1
|
||||
; CHECK-NEXT: fccmp d0, d1, #8, le
|
||||
; CHECK-NEXT: fccmp d2, d3, #8, mi
|
||||
; CHECK-NEXT: fccmp d0, d1, #1, ne
|
||||
; CHECK-NEXT: fccmp d2, d3, #8, vc
|
||||
; CHECK-NEXT: csel w0, w0, w1, mi
|
||||
; CHECK-NEXT: ret
|
||||
define i32 @select_or_ueq_olt(double %v0, double %v1, double %v2, double %v3, i32 %a, i32 %b) #0 {
|
||||
@ -656,4 +656,68 @@ define i32 @f128_select_and_olt_oge(fp128 %v0, fp128 %v1, fp128 %v2, fp128 %v3,
|
||||
ret i32 %sel
|
||||
}
|
||||
|
||||
; This testcase resembles the core problem of http://llvm.org/PR39550
|
||||
; (an OR operation is 2 levels deep but needs to be implemented first)
|
||||
; CHECK-LABEL: deep_or
|
||||
; CHECK: cmp w2, #20
|
||||
; CHECK-NEXT: ccmp w2, #15, #4, ne
|
||||
; CHECK-NEXT: ccmp w1, #0, #4, eq
|
||||
; CHECK-NEXT: ccmp w0, #0, #4, ne
|
||||
; CHECK-NEXT: csel w0, w4, w5, ne
|
||||
; CHECK-NEXT: ret
|
||||
define i32 @deep_or(i32 %a0, i32 %a1, i32 %a2, i32 %a3, i32 %x, i32 %y) {
|
||||
%c0 = icmp ne i32 %a0, 0
|
||||
%c1 = icmp ne i32 %a1, 0
|
||||
%c2 = icmp eq i32 %a2, 15
|
||||
%c3 = icmp eq i32 %a2, 20
|
||||
|
||||
%or = or i1 %c2, %c3
|
||||
%and0 = and i1 %or, %c1
|
||||
%and1 = and i1 %and0, %c0
|
||||
%sel = select i1 %and1, i32 %x, i32 %y
|
||||
ret i32 %sel
|
||||
}
|
||||
|
||||
; Variation of deep_or, we still need to implement the OR first though.
|
||||
; CHECK-LABEL: deep_or1
|
||||
; CHECK: cmp w2, #20
|
||||
; CHECK-NEXT: ccmp w2, #15, #4, ne
|
||||
; CHECK-NEXT: ccmp w0, #0, #4, eq
|
||||
; CHECK-NEXT: ccmp w1, #0, #4, ne
|
||||
; CHECK-NEXT: csel w0, w4, w5, ne
|
||||
; CHECK-NEXT: ret
|
||||
define i32 @deep_or1(i32 %a0, i32 %a1, i32 %a2, i32 %a3, i32 %x, i32 %y) {
|
||||
%c0 = icmp ne i32 %a0, 0
|
||||
%c1 = icmp ne i32 %a1, 0
|
||||
%c2 = icmp eq i32 %a2, 15
|
||||
%c3 = icmp eq i32 %a2, 20
|
||||
|
||||
%or = or i1 %c2, %c3
|
||||
%and0 = and i1 %c0, %or
|
||||
%and1 = and i1 %and0, %c1
|
||||
%sel = select i1 %and1, i32 %x, i32 %y
|
||||
ret i32 %sel
|
||||
}
|
||||
|
||||
; Variation of deep_or, we still need to implement the OR first though.
|
||||
; CHECK-LABEL: deep_or2
|
||||
; CHECK: cmp w2, #20
|
||||
; CHECK-NEXT: ccmp w2, #15, #4, ne
|
||||
; CHECK-NEXT: ccmp w1, #0, #4, eq
|
||||
; CHECK-NEXT: ccmp w0, #0, #4, ne
|
||||
; CHECK-NEXT: csel w0, w4, w5, ne
|
||||
; CHECK-NEXT: ret
|
||||
define i32 @deep_or2(i32 %a0, i32 %a1, i32 %a2, i32 %a3, i32 %x, i32 %y) {
|
||||
%c0 = icmp ne i32 %a0, 0
|
||||
%c1 = icmp ne i32 %a1, 0
|
||||
%c2 = icmp eq i32 %a2, 15
|
||||
%c3 = icmp eq i32 %a2, 20
|
||||
|
||||
%or = or i1 %c2, %c3
|
||||
%and0 = and i1 %c0, %c1
|
||||
%and1 = and i1 %and0, %or
|
||||
%sel = select i1 %and1, i32 %x, i32 %y
|
||||
ret i32 %sel
|
||||
}
|
||||
|
||||
attributes #0 = { nounwind }
|
||||
|
@ -23,18 +23,6 @@ define i1 @p0(i8 %x) {
|
||||
ret i1 %ret
|
||||
}
|
||||
|
||||
define i1 @pv(i8 %x, i8 %y) {
|
||||
; CHECK-LABEL: @pv(
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = lshr i8 -1, [[Y:%.*]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = icmp sge i8 [[TMP0]], [[X:%.*]]
|
||||
; CHECK-NEXT: ret i1 [[TMP1]]
|
||||
;
|
||||
%tmp0 = lshr i8 -1, %y
|
||||
%tmp1 = and i8 %tmp0, %x
|
||||
%ret = icmp sge i8 %tmp1, %x
|
||||
ret i1 %ret
|
||||
}
|
||||
|
||||
; ============================================================================ ;
|
||||
; Vector tests
|
||||
; ============================================================================ ;
|
||||
@ -120,8 +108,9 @@ define i1 @cv0(i8 %y) {
|
||||
; CHECK-LABEL: @cv0(
|
||||
; CHECK-NEXT: [[X:%.*]] = call i8 @gen8()
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = lshr i8 -1, [[Y:%.*]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = icmp sle i8 [[X]], [[TMP0]]
|
||||
; CHECK-NEXT: ret i1 [[TMP1]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X]], [[TMP0]]
|
||||
; CHECK-NEXT: [[RET:%.*]] = icmp sge i8 [[TMP1]], [[X]]
|
||||
; CHECK-NEXT: ret i1 [[RET]]
|
||||
;
|
||||
%x = call i8 @gen8()
|
||||
%tmp0 = lshr i8 -1, %y
|
||||
@ -196,3 +185,42 @@ define <2 x i1> @n2(<2 x i8> %x) {
|
||||
%ret = icmp sge <2 x i8> %tmp0, %x
|
||||
ret <2 x i1> %ret
|
||||
}
|
||||
|
||||
; ============================================================================ ;
|
||||
; Potential miscompiles.
|
||||
; ============================================================================ ;
|
||||
|
||||
define i1 @nv(i8 %x, i8 %y) {
|
||||
; CHECK-LABEL: @nv(
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = lshr i8 -1, [[Y:%.*]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[TMP0]], [[X:%.*]]
|
||||
; CHECK-NEXT: [[RET:%.*]] = icmp sge i8 [[TMP1]], [[X]]
|
||||
; CHECK-NEXT: ret i1 [[RET]]
|
||||
;
|
||||
%tmp0 = lshr i8 -1, %y
|
||||
%tmp1 = and i8 %tmp0, %x
|
||||
%ret = icmp sge i8 %tmp1, %x
|
||||
ret i1 %ret
|
||||
}
|
||||
|
||||
define <2 x i1> @n3_vec(<2 x i8> %x) {
|
||||
; CHECK-LABEL: @n3_vec(
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = and <2 x i8> [[X:%.*]], <i8 3, i8 -1>
|
||||
; CHECK-NEXT: [[RET:%.*]] = icmp sge <2 x i8> [[TMP0]], [[X]]
|
||||
; CHECK-NEXT: ret <2 x i1> [[RET]]
|
||||
;
|
||||
%tmp0 = and <2 x i8> %x, <i8 3, i8 -1>
|
||||
%ret = icmp sge <2 x i8> %tmp0, %x
|
||||
ret <2 x i1> %ret
|
||||
}
|
||||
|
||||
define <3 x i1> @n4_vec(<3 x i8> %x) {
|
||||
; CHECK-LABEL: @n4_vec(
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = and <3 x i8> [[X:%.*]], <i8 3, i8 undef, i8 -1>
|
||||
; CHECK-NEXT: [[RET:%.*]] = icmp sge <3 x i8> [[TMP0]], [[X]]
|
||||
; CHECK-NEXT: ret <3 x i1> [[RET]]
|
||||
;
|
||||
%tmp0 = and <3 x i8> %x, <i8 3, i8 undef, i8 -1>
|
||||
%ret = icmp sge <3 x i8> %tmp0, %x
|
||||
ret <3 x i1> %ret
|
||||
}
|
||||
|
@ -23,18 +23,6 @@ define i1 @p0(i8 %x) {
|
||||
ret i1 %ret
|
||||
}
|
||||
|
||||
define i1 @pv(i8 %x, i8 %y) {
|
||||
; CHECK-LABEL: @pv(
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = lshr i8 -1, [[Y:%.*]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i8 [[TMP0]], [[X:%.*]]
|
||||
; CHECK-NEXT: ret i1 [[TMP1]]
|
||||
;
|
||||
%tmp0 = lshr i8 -1, %y
|
||||
%tmp1 = and i8 %tmp0, %x
|
||||
%ret = icmp slt i8 %tmp1, %x
|
||||
ret i1 %ret
|
||||
}
|
||||
|
||||
; ============================================================================ ;
|
||||
; Vector tests
|
||||
; ============================================================================ ;
|
||||
@ -120,8 +108,9 @@ define i1 @cv0(i8 %y) {
|
||||
; CHECK-LABEL: @cv0(
|
||||
; CHECK-NEXT: [[X:%.*]] = call i8 @gen8()
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = lshr i8 -1, [[Y:%.*]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i8 [[X]], [[TMP0]]
|
||||
; CHECK-NEXT: ret i1 [[TMP1]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X]], [[TMP0]]
|
||||
; CHECK-NEXT: [[RET:%.*]] = icmp slt i8 [[TMP1]], [[X]]
|
||||
; CHECK-NEXT: ret i1 [[RET]]
|
||||
;
|
||||
%x = call i8 @gen8()
|
||||
%tmp0 = lshr i8 -1, %y
|
||||
@ -196,3 +185,42 @@ define <2 x i1> @n2(<2 x i8> %x) {
|
||||
%ret = icmp slt <2 x i8> %tmp0, %x
|
||||
ret <2 x i1> %ret
|
||||
}
|
||||
|
||||
; ============================================================================ ;
|
||||
; Potential miscompiles.
|
||||
; ============================================================================ ;
|
||||
|
||||
define i1 @nv(i8 %x, i8 %y) {
|
||||
; CHECK-LABEL: @nv(
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = lshr i8 -1, [[Y:%.*]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[TMP0]], [[X:%.*]]
|
||||
; CHECK-NEXT: [[RET:%.*]] = icmp slt i8 [[TMP1]], [[X]]
|
||||
; CHECK-NEXT: ret i1 [[RET]]
|
||||
;
|
||||
%tmp0 = lshr i8 -1, %y
|
||||
%tmp1 = and i8 %tmp0, %x
|
||||
%ret = icmp slt i8 %tmp1, %x
|
||||
ret i1 %ret
|
||||
}
|
||||
|
||||
define <2 x i1> @n3(<2 x i8> %x) {
|
||||
; CHECK-LABEL: @n3(
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = and <2 x i8> [[X:%.*]], <i8 3, i8 -1>
|
||||
; CHECK-NEXT: [[RET:%.*]] = icmp slt <2 x i8> [[TMP0]], [[X]]
|
||||
; CHECK-NEXT: ret <2 x i1> [[RET]]
|
||||
;
|
||||
%tmp0 = and <2 x i8> %x, <i8 3, i8 -1>
|
||||
%ret = icmp slt <2 x i8> %tmp0, %x
|
||||
ret <2 x i1> %ret
|
||||
}
|
||||
|
||||
define <3 x i1> @n4(<3 x i8> %x) {
|
||||
; CHECK-LABEL: @n4(
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = and <3 x i8> [[X:%.*]], <i8 3, i8 undef, i8 -1>
|
||||
; CHECK-NEXT: [[RET:%.*]] = icmp slt <3 x i8> [[TMP0]], [[X]]
|
||||
; CHECK-NEXT: ret <3 x i1> [[RET]]
|
||||
;
|
||||
%tmp0 = and <3 x i8> %x, <i8 3, i8 undef, i8 -1>
|
||||
%ret = icmp slt <3 x i8> %tmp0, %x
|
||||
ret <3 x i1> %ret
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user