summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Analysis
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Analysis')
-rw-r--r--llvm/lib/Analysis/ConstantFolding.cpp177
1 files changed, 114 insertions, 63 deletions
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index 61808862674..5da29d6d237 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -1629,6 +1629,18 @@ static bool isManifestConstant(const Constant *c) {
return false;
}
+static bool getConstIntOrUndef(Value *Op, const APInt *&C) {
+ if (auto *CI = dyn_cast<ConstantInt>(Op)) {
+ C = &CI->getValue();
+ return true;
+ }
+ if (isa<UndefValue>(Op)) {
+ C = nullptr;
+ return true;
+ }
+ return false;
+}
+
Constant *ConstantFoldScalarCall(StringRef Name, unsigned IntrinsicID, Type *Ty,
ArrayRef<Constant *> Operands,
const TargetLibraryInfo *TLI,
@@ -1643,8 +1655,10 @@ Constant *ConstantFoldScalarCall(StringRef Name, unsigned IntrinsicID, Type *Ty,
return nullptr;
}
if (isa<UndefValue>(Operands[0])) {
- // cosine(arg) is between -1 and 1. cosine(invalid arg) is NaN
- if (IntrinsicID == Intrinsic::cos)
+ // cosine(arg) is between -1 and 1. cosine(invalid arg) is NaN.
+ // ctpop() is between 0 and bitwidth, pick 0 for undef.
+ if (IntrinsicID == Intrinsic::cos ||
+ IntrinsicID == Intrinsic::ctpop)
return Constant::getNullValue(Ty);
if (IntrinsicID == Intrinsic::bswap ||
IntrinsicID == Intrinsic::bitreverse ||
@@ -1995,62 +2009,92 @@ Constant *ConstantFoldScalarCall(StringRef Name, unsigned IntrinsicID, Type *Ty,
return nullptr;
}
- if (auto *Op1 = dyn_cast<ConstantInt>(Operands[0])) {
- if (auto *Op2 = dyn_cast<ConstantInt>(Operands[1])) {
+ if (Operands[0]->getType()->isIntegerTy() &&
+ Operands[1]->getType()->isIntegerTy()) {
+ const APInt *C0, *C1;
+ if (!getConstIntOrUndef(Operands[0], C0) ||
+ !getConstIntOrUndef(Operands[1], C1))
+ return nullptr;
+
+ switch (IntrinsicID) {
+ default: break;
+ case Intrinsic::smul_with_overflow:
+ case Intrinsic::umul_with_overflow:
+ // Even if both operands are undef, we cannot fold muls to undef
+ // in the general case. For example, on i2 there are no inputs
+ // that would produce { i2 -1, i1 true } as the result.
+ if (!C0 || !C1)
+ return Constant::getNullValue(Ty);
+ LLVM_FALLTHROUGH;
+ case Intrinsic::sadd_with_overflow:
+ case Intrinsic::uadd_with_overflow:
+ case Intrinsic::ssub_with_overflow:
+ case Intrinsic::usub_with_overflow: {
+ if (!C0 || !C1)
+ return UndefValue::get(Ty);
+
+ APInt Res;
+ bool Overflow;
switch (IntrinsicID) {
- default: break;
+ default: llvm_unreachable("Invalid case");
case Intrinsic::sadd_with_overflow:
+ Res = C0->sadd_ov(*C1, Overflow);
+ break;
case Intrinsic::uadd_with_overflow:
+ Res = C0->uadd_ov(*C1, Overflow);
+ break;
case Intrinsic::ssub_with_overflow:
+ Res = C0->ssub_ov(*C1, Overflow);
+ break;
case Intrinsic::usub_with_overflow:
+ Res = C0->usub_ov(*C1, Overflow);
+ break;
case Intrinsic::smul_with_overflow:
- case Intrinsic::umul_with_overflow: {
- APInt Res;
- bool Overflow;
- switch (IntrinsicID) {
- default: llvm_unreachable("Invalid case");
- case Intrinsic::sadd_with_overflow:
- Res = Op1->getValue().sadd_ov(Op2->getValue(), Overflow);
- break;
- case Intrinsic::uadd_with_overflow:
- Res = Op1->getValue().uadd_ov(Op2->getValue(), Overflow);
- break;
- case Intrinsic::ssub_with_overflow:
- Res = Op1->getValue().ssub_ov(Op2->getValue(), Overflow);
- break;
- case Intrinsic::usub_with_overflow:
- Res = Op1->getValue().usub_ov(Op2->getValue(), Overflow);
- break;
- case Intrinsic::smul_with_overflow:
- Res = Op1->getValue().smul_ov(Op2->getValue(), Overflow);
- break;
- case Intrinsic::umul_with_overflow:
- Res = Op1->getValue().umul_ov(Op2->getValue(), Overflow);
- break;
- }
- Constant *Ops[] = {
- ConstantInt::get(Ty->getContext(), Res),
- ConstantInt::get(Type::getInt1Ty(Ty->getContext()), Overflow)
- };
- return ConstantStruct::get(cast<StructType>(Ty), Ops);
- }
- case Intrinsic::uadd_sat:
- return ConstantInt::get(Ty, Op1->getValue().uadd_sat(Op2->getValue()));
- case Intrinsic::sadd_sat:
- return ConstantInt::get(Ty, Op1->getValue().sadd_sat(Op2->getValue()));
- case Intrinsic::usub_sat:
- return ConstantInt::get(Ty, Op1->getValue().usub_sat(Op2->getValue()));
- case Intrinsic::ssub_sat:
- return ConstantInt::get(Ty, Op1->getValue().ssub_sat(Op2->getValue()));
- case Intrinsic::cttz:
- if (Op2->isOne() && Op1->isZero()) // cttz(0, 1) is undef.
- return UndefValue::get(Ty);
- return ConstantInt::get(Ty, Op1->getValue().countTrailingZeros());
- case Intrinsic::ctlz:
- if (Op2->isOne() && Op1->isZero()) // ctlz(0, 1) is undef.
- return UndefValue::get(Ty);
- return ConstantInt::get(Ty, Op1->getValue().countLeadingZeros());
+ Res = C0->smul_ov(*C1, Overflow);
+ break;
+ case Intrinsic::umul_with_overflow:
+ Res = C0->umul_ov(*C1, Overflow);
+ break;
}
+ Constant *Ops[] = {
+ ConstantInt::get(Ty->getContext(), Res),
+ ConstantInt::get(Type::getInt1Ty(Ty->getContext()), Overflow)
+ };
+ return ConstantStruct::get(cast<StructType>(Ty), Ops);
+ }
+ case Intrinsic::uadd_sat:
+ case Intrinsic::sadd_sat:
+ if (!C0 && !C1)
+ return UndefValue::get(Ty);
+ if (!C0 || !C1)
+ return Constant::getAllOnesValue(Ty);
+ if (IntrinsicID == Intrinsic::uadd_sat)
+ return ConstantInt::get(Ty, C0->uadd_sat(*C1));
+ else
+ return ConstantInt::get(Ty, C0->sadd_sat(*C1));
+ case Intrinsic::usub_sat:
+ case Intrinsic::ssub_sat:
+ if (!C0 && !C1)
+ return UndefValue::get(Ty);
+ if (!C0 || !C1)
+ return Constant::getNullValue(Ty);
+ if (IntrinsicID == Intrinsic::usub_sat)
+ return ConstantInt::get(Ty, C0->usub_sat(*C1));
+ else
+ return ConstantInt::get(Ty, C0->ssub_sat(*C1));
+ case Intrinsic::cttz:
+ case Intrinsic::ctlz:
+ assert(C1 && "Must be constant int");
+
+ // cttz(0, 1) and ctlz(0, 1) are undef.
+ if (C1->isOneValue() && (!C0 || C0->isNullValue()))
+ return UndefValue::get(Ty);
+ if (!C0)
+ return Constant::getNullValue(Ty);
+ if (IntrinsicID == Intrinsic::cttz)
+ return ConstantInt::get(Ty, C0->countTrailingZeros());
+ else
+ return ConstantInt::get(Ty, C0->countLeadingZeros());
}
return nullptr;
@@ -2136,26 +2180,33 @@ Constant *ConstantFoldScalarCall(StringRef Name, unsigned IntrinsicID, Type *Ty,
}
if (IntrinsicID == Intrinsic::fshl || IntrinsicID == Intrinsic::fshr) {
- auto *C0 = dyn_cast<ConstantInt>(Operands[0]);
- auto *C1 = dyn_cast<ConstantInt>(Operands[1]);
- auto *C2 = dyn_cast<ConstantInt>(Operands[2]);
- if (!(C0 && C1 && C2))
+ const APInt *C0, *C1, *C2;
+ if (!getConstIntOrUndef(Operands[0], C0) ||
+ !getConstIntOrUndef(Operands[1], C1) ||
+ !getConstIntOrUndef(Operands[2], C2))
return nullptr;
+ bool IsRight = IntrinsicID == Intrinsic::fshr;
+ if (!C2)
+ return Operands[IsRight ? 1 : 0];
+ if (!C0 && !C1)
+ return UndefValue::get(Ty);
+
// The shift amount is interpreted as modulo the bitwidth. If the shift
// amount is effectively 0, avoid UB due to oversized inverse shift below.
- unsigned BitWidth = C0->getBitWidth();
- unsigned ShAmt = C2->getValue().urem(BitWidth);
- bool IsRight = IntrinsicID == Intrinsic::fshr;
+ unsigned BitWidth = C2->getBitWidth();
+ unsigned ShAmt = C2->urem(BitWidth);
if (!ShAmt)
- return IsRight ? C1 : C0;
+ return Operands[IsRight ? 1 : 0];
- // (X << ShlAmt) | (Y >> LshrAmt)
- const APInt &X = C0->getValue();
- const APInt &Y = C1->getValue();
+ // (C0 << ShlAmt) | (C1 >> LshrAmt)
unsigned LshrAmt = IsRight ? ShAmt : BitWidth - ShAmt;
unsigned ShlAmt = !IsRight ? ShAmt : BitWidth - ShAmt;
- return ConstantInt::get(Ty->getContext(), X.shl(ShlAmt) | Y.lshr(LshrAmt));
+ if (!C0)
+ return ConstantInt::get(Ty, C1->lshr(LshrAmt));
+ if (!C1)
+ return ConstantInt::get(Ty, C0->shl(ShlAmt));
+ return ConstantInt::get(Ty, C0->shl(ShlAmt) | C1->lshr(LshrAmt));
}
return nullptr;
OpenPOWER on IntegriCloud