/// This is very similar to GetPointerBaseWithConstantOffset except it doesn't
/// follow non-inbounds geps. This allows it to remain usable for icmp ult/etc.
/// folding.
-static ConstantInt *stripAndComputeConstantOffsets(const DataLayout *TD,
- Value *&V) {
- assert(V->getType()->isPointerTy());
+static Constant *stripAndComputeConstantOffsets(const DataLayout *TD,
+ Value *&V) {
+ assert(V->getType()->getScalarType()->isPointerTy());
// Without DataLayout, just be conservative for now. Theoretically, more could
// be done in this case.
} else {
break;
}
- assert(V->getType()->isPointerTy() && "Unexpected operand type!");
+ assert(V->getType()->getScalarType()->isPointerTy() &&
+ "Unexpected operand type!");
} while (Visited.insert(V));
Type *IntPtrTy = TD->getIntPtrType(V->getContext());
- return cast<ConstantInt>(ConstantInt::get(IntPtrTy, Offset));
+ Constant *OffsetIntPtr = ConstantInt::get(IntPtrTy, Offset);
+ if (V->getType()->isVectorTy())
+ return ConstantVector::getSplat(V->getType()->getVectorNumElements(),
+ OffsetIntPtr);
+ return OffsetIntPtr;
}
/// \brief Compute the constant difference between two pointer values.
if (Value *V = SimplifyShift(Instruction::LShr, Op0, Op1, Q, MaxRecurse))
return V;
+ // X >> X -> 0
+ if (Op0 == Op1)
+ return Constant::getNullValue(Op0->getType());
+
// undef >>l X -> 0
if (match(Op0, m_Undef()))
return Constant::getNullValue(Op0->getType());
if (Value *V = SimplifyShift(Instruction::AShr, Op0, Op1, Q, MaxRecurse))
return V;
+ // X >> X -> 0
+ if (Op0 == Op1)
+ return Constant::getNullValue(Op0->getType());
+
// all ones >>a X -> all ones
if (match(Op0, m_AllOnes()))
return Op0;
// subobject at its beginning) or function, both are pointers to one past the
// last element of the same array object, or one is a pointer to one past the
// end of one array object and the other is a pointer to the start of a
-// different array object that happens to immediately follow the first array
+// different array object that happens to immediately follow the first array
// object in the address space.)
//
// C11's version is more restrictive, however there's no reason why an argument
// numerous hazards. AliasAnalysis and its utilities rely on special rules
// governing loads and stores which don't apply to icmps. Also, AliasAnalysis
// doesn't need to guarantee pointer inequality when it says NoAlias.
- ConstantInt *LHSOffset = stripAndComputeConstantOffsets(TD, LHS);
- ConstantInt *RHSOffset = stripAndComputeConstantOffsets(TD, RHS);
+ Constant *LHSOffset = stripAndComputeConstantOffsets(TD, LHS);
+ Constant *RHSOffset = stripAndComputeConstantOffsets(TD, RHS);
// If LHS and RHS are related via constant offsets to the same base
// value, we can replace it with an icmp which just compares the offsets.
// address, due to canonicalization and constant folding.
if (isa<AllocaInst>(LHS) &&
(isa<AllocaInst>(RHS) || isa<GlobalVariable>(RHS))) {
+ ConstantInt *LHSOffsetCI = dyn_cast<ConstantInt>(LHSOffset);
+ ConstantInt *RHSOffsetCI = dyn_cast<ConstantInt>(RHSOffset);
uint64_t LHSSize, RHSSize;
- if (getObjectSize(LHS, LHSSize, TD, TLI) &&
+ if (LHSOffsetCI && RHSOffsetCI &&
+ getObjectSize(LHS, LHSSize, TD, TLI) &&
getObjectSize(RHS, RHSSize, TD, TLI)) {
- const APInt &LHSOffsetValue = LHSOffset->getValue();
- const APInt &RHSOffsetValue = RHSOffset->getValue();
+ const APInt &LHSOffsetValue = LHSOffsetCI->getValue();
+ const APInt &RHSOffsetValue = RHSOffsetCI->getValue();
if (!LHSOffsetValue.isNegative() &&
!RHSOffsetValue.isNegative() &&
LHSOffsetValue.ult(LHSSize) &&
}
}
+ // icmp pred (urem X, Y), Y
if (LBO && match(LBO, m_URem(m_Value(), m_Specific(RHS)))) {
bool KnownNonNegative, KnownNegative;
switch (Pred) {
break;
case ICmpInst::ICMP_SGT:
case ICmpInst::ICMP_SGE:
- ComputeSignBit(LHS, KnownNonNegative, KnownNegative, Q.TD);
+ ComputeSignBit(RHS, KnownNonNegative, KnownNegative, Q.TD);
if (!KnownNonNegative)
break;
// fall-through
return getFalse(ITy);
case ICmpInst::ICMP_SLT:
case ICmpInst::ICMP_SLE:
- ComputeSignBit(LHS, KnownNonNegative, KnownNegative, Q.TD);
+ ComputeSignBit(RHS, KnownNonNegative, KnownNegative, Q.TD);
if (!KnownNonNegative)
break;
// fall-through
return getTrue(ITy);
}
}
+
+ // icmp pred X, (urem Y, X)
if (RBO && match(RBO, m_URem(m_Value(), m_Specific(LHS)))) {
bool KnownNonNegative, KnownNegative;
switch (Pred) {
break;
case ICmpInst::ICMP_SGT:
case ICmpInst::ICMP_SGE:
- ComputeSignBit(RHS, KnownNonNegative, KnownNegative, Q.TD);
+ ComputeSignBit(LHS, KnownNonNegative, KnownNegative, Q.TD);
if (!KnownNonNegative)
break;
// fall-through
return getTrue(ITy);
case ICmpInst::ICMP_SLT:
case ICmpInst::ICMP_SLE:
- ComputeSignBit(RHS, KnownNonNegative, KnownNegative, Q.TD);
+ ComputeSignBit(LHS, KnownNonNegative, KnownNegative, Q.TD);
if (!KnownNonNegative)
break;
// fall-through
RecursionLimit);
}
+static bool IsIdempotent(Intrinsic::ID ID) {
+ switch (ID) {
+ default: return false;
+
+ // Unary idempotent: f(f(x)) = f(x)
+ case Intrinsic::fabs:
+ case Intrinsic::floor:
+ case Intrinsic::ceil:
+ case Intrinsic::trunc:
+ case Intrinsic::rint:
+ case Intrinsic::nearbyint:
+ return true;
+ }
+}
+
+template <typename IterTy>
+static Value *SimplifyIntrinsic(Intrinsic::ID IID, IterTy ArgBegin, IterTy ArgEnd,
+ const Query &Q, unsigned MaxRecurse) {
+ // Perform idempotent optimizations
+ if (!IsIdempotent(IID))
+ return 0;
+
+ // Unary Ops
+ if (std::distance(ArgBegin, ArgEnd) == 1)
+ if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(*ArgBegin))
+ if (II->getIntrinsicID() == IID)
+ return II;
+
+ return 0;
+}
+
template <typename IterTy>
static Value *SimplifyCall(Value *V, IterTy ArgBegin, IterTy ArgEnd,
const Query &Q, unsigned MaxRecurse) {
if (!F)
return 0;
+ if (unsigned IID = F->getIntrinsicID())
+ if (Value *Ret =
+ SimplifyIntrinsic((Intrinsic::ID) IID, ArgBegin, ArgEnd, Q, MaxRecurse))
+ return Ret;
+
if (!canConstantFoldCallTo(F))
return 0;