aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/Analysis/ConstantFolding.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2022-07-04 19:20:19 +0000
committerDimitry Andric <dim@FreeBSD.org>2023-02-08 19:02:26 +0000
commit81ad626541db97eb356e2c1d4a20eb2a26a766ab (patch)
tree311b6a8987c32b1e1dcbab65c54cfac3fdb56175 /contrib/llvm-project/llvm/lib/Analysis/ConstantFolding.cpp
parent5fff09660e06a66bed6482da9c70df328e16bbb6 (diff)
parent145449b1e420787bb99721a429341fa6be3adfb6 (diff)
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Analysis/ConstantFolding.cpp')
-rw-r--r--contrib/llvm-project/llvm/lib/Analysis/ConstantFolding.cpp257
1 files changed, 198 insertions, 59 deletions
diff --git a/contrib/llvm-project/llvm/lib/Analysis/ConstantFolding.cpp b/contrib/llvm-project/llvm/lib/Analysis/ConstantFolding.cpp
index f6b955162fa5..a81041845052 100644
--- a/contrib/llvm-project/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/contrib/llvm-project/llvm/lib/Analysis/ConstantFolding.cpp
@@ -57,7 +57,6 @@
#include <cerrno>
#include <cfenv>
#include <cmath>
-#include <cstddef>
#include <cstdint>
using namespace llvm;
@@ -92,7 +91,7 @@ static Constant *foldConstVectorToAPInt(APInt &Result, Type *DestTy,
return ConstantExpr::getBitCast(C, DestTy);
Result <<= BitShift;
- Result |= ElementCI->getValue().zextOrSelf(Result.getBitWidth());
+ Result |= ElementCI->getValue().zext(Result.getBitWidth());
}
return nullptr;
@@ -634,6 +633,39 @@ Constant *FoldReinterpretLoadFromConst(Constant *C, Type *LoadTy,
return ConstantInt::get(IntType->getContext(), ResultVal);
}
+} // anonymous namespace
+
+// If GV is a constant with an initializer read its representation starting
+// at Offset and return it as a constant array of unsigned char. Otherwise
+// return null.
+Constant *llvm::ReadByteArrayFromGlobal(const GlobalVariable *GV,
+ uint64_t Offset) {
+ if (!GV->isConstant() || !GV->hasDefinitiveInitializer())
+ return nullptr;
+
+ const DataLayout &DL = GV->getParent()->getDataLayout();
+ Constant *Init = const_cast<Constant *>(GV->getInitializer());
+ TypeSize InitSize = DL.getTypeAllocSize(Init->getType());
+ if (InitSize < Offset)
+ return nullptr;
+
+ uint64_t NBytes = InitSize - Offset;
+ if (NBytes > UINT16_MAX)
+ // Bail for large initializers in excess of 64K to avoid allocating
+ // too much memory.
+ // Offset is assumed to be less than or equal than InitSize (this
+ // is enforced in ReadDataFromGlobal).
+ return nullptr;
+
+ SmallVector<unsigned char, 256> RawBytes(static_cast<size_t>(NBytes));
+ unsigned char *CurPtr = RawBytes.data();
+
+ if (!ReadDataFromGlobal(Init, Offset, CurPtr, NBytes, DL))
+ return nullptr;
+
+ return ConstantDataArray::get(GV->getContext(), RawBytes);
+}
+
/// If this Offset points exactly to the start of an aggregate element, return
/// that element, otherwise return nullptr.
Constant *getConstantAtOffset(Constant *Base, APInt Offset,
@@ -662,8 +694,6 @@ Constant *getConstantAtOffset(Constant *Base, APInt Offset,
return C;
}
-} // end anonymous namespace
-
Constant *llvm::ConstantFoldLoadFromConst(Constant *C, Type *Ty,
const APInt &Offset,
const DataLayout &DL) {
@@ -867,21 +897,6 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP,
Type *IntIdxTy = DL.getIndexType(Ptr->getType());
- // If this is "gep i8* Ptr, (sub 0, V)", fold this as:
- // "inttoptr (sub (ptrtoint Ptr), V)"
- if (Ops.size() == 2 && ResElemTy->isIntegerTy(8)) {
- auto *CE = dyn_cast<ConstantExpr>(Ops[1]);
- assert((!CE || CE->getType() == IntIdxTy) &&
- "CastGEPIndices didn't canonicalize index types!");
- if (CE && CE->getOpcode() == Instruction::Sub &&
- CE->getOperand(0)->isNullValue()) {
- Constant *Res = ConstantExpr::getPtrToInt(Ptr, CE->getType());
- Res = ConstantExpr::getSub(Res, CE->getOperand(1));
- Res = ConstantExpr::getIntToPtr(Res, ResTy);
- return ConstantFoldConstant(Res, DL, TLI);
- }
- }
-
for (unsigned i = 1, e = Ops.size(); i != e; ++i)
if (!isa<ConstantInt>(Ops[i]))
return nullptr;
@@ -1015,8 +1030,24 @@ Constant *ConstantFoldInstOperandsImpl(const Value *InstOrCE, unsigned Opcode,
if (Instruction::isUnaryOp(Opcode))
return ConstantFoldUnaryOpOperand(Opcode, Ops[0], DL);
- if (Instruction::isBinaryOp(Opcode))
+ if (Instruction::isBinaryOp(Opcode)) {
+ switch (Opcode) {
+ default:
+ break;
+ case Instruction::FAdd:
+ case Instruction::FSub:
+ case Instruction::FMul:
+ case Instruction::FDiv:
+ case Instruction::FRem:
+ // Handle floating point instructions separately to account for denormals
+ // TODO: If a constant expression is being folded rather than an
+ // instruction, denormals will not be flushed/treated as zero
+ if (const auto *I = dyn_cast<Instruction>(InstOrCE)) {
+ return ConstantFoldFPInstOperands(Opcode, Ops[0], Ops[1], DL, I);
+ }
+ }
return ConstantFoldBinaryOpOperands(Opcode, Ops[0], Ops[1], DL);
+ }
if (Instruction::isCast(Opcode))
return ConstantFoldCastOperand(Opcode, Ops[0], DestTy, DL);
@@ -1030,13 +1061,21 @@ Constant *ConstantFoldInstOperandsImpl(const Value *InstOrCE, unsigned Opcode,
GEP->getInRangeIndex());
}
- if (auto *CE = dyn_cast<ConstantExpr>(InstOrCE))
+ if (auto *CE = dyn_cast<ConstantExpr>(InstOrCE)) {
+ if (CE->isCompare())
+ return ConstantFoldCompareInstOperands(CE->getPredicate(), Ops[0], Ops[1],
+ DL, TLI);
return CE->getWithOperands(Ops);
+ }
switch (Opcode) {
default: return nullptr;
case Instruction::ICmp:
- case Instruction::FCmp: llvm_unreachable("Invalid for compares");
+ case Instruction::FCmp: {
+ auto *C = cast<CmpInst>(InstOrCE);
+ return ConstantFoldCompareInstOperands(C->getPredicate(), Ops[0], Ops[1],
+ DL, TLI, C);
+ }
case Instruction::Freeze:
return isGuaranteedNotToBeUndefOrPoison(Ops[0]) ? Ops[0] : nullptr;
case Instruction::Call:
@@ -1051,13 +1090,22 @@ Constant *ConstantFoldInstOperandsImpl(const Value *InstOrCE, unsigned Opcode,
case Instruction::ExtractElement:
return ConstantExpr::getExtractElement(Ops[0], Ops[1]);
case Instruction::ExtractValue:
- return ConstantExpr::getExtractValue(
+ return ConstantFoldExtractValueInstruction(
Ops[0], cast<ExtractValueInst>(InstOrCE)->getIndices());
case Instruction::InsertElement:
return ConstantExpr::getInsertElement(Ops[0], Ops[1], Ops[2]);
+ case Instruction::InsertValue:
+ return ConstantFoldInsertValueInstruction(
+ Ops[0], Ops[1], cast<InsertValueInst>(InstOrCE)->getIndices());
case Instruction::ShuffleVector:
return ConstantExpr::getShuffleVector(
Ops[0], Ops[1], cast<ShuffleVectorInst>(InstOrCE)->getShuffleMask());
+ case Instruction::Load: {
+ const auto *LI = dyn_cast<LoadInst>(InstOrCE);
+ if (LI->isVolatile())
+ return nullptr;
+ return ConstantFoldLoadFromConstPtr(Ops[0], LI->getType(), DL);
+ }
}
}
@@ -1094,13 +1142,8 @@ ConstantFoldConstantImpl(const Constant *C, const DataLayout &DL,
Ops.push_back(NewC);
}
- if (auto *CE = dyn_cast<ConstantExpr>(C)) {
- if (CE->isCompare())
- return ConstantFoldCompareInstOperands(CE->getPredicate(), Ops[0], Ops[1],
- DL, TLI);
-
+ if (auto *CE = dyn_cast<ConstantExpr>(C))
return ConstantFoldInstOperandsImpl(CE, CE->getOpcode(), Ops, DL, TLI);
- }
assert(isa<ConstantVector>(C));
return ConstantVector::get(Ops);
@@ -1153,22 +1196,6 @@ Constant *llvm::ConstantFoldInstruction(Instruction *I, const DataLayout &DL,
Ops.push_back(Op);
}
- if (const auto *CI = dyn_cast<CmpInst>(I))
- return ConstantFoldCompareInstOperands(CI->getPredicate(), Ops[0], Ops[1],
- DL, TLI);
-
- if (const auto *LI = dyn_cast<LoadInst>(I)) {
- if (LI->isVolatile())
- return nullptr;
- return ConstantFoldLoadFromConstPtr(Ops[0], LI->getType(), DL);
- }
-
- if (auto *IVI = dyn_cast<InsertValueInst>(I))
- return ConstantExpr::getInsertValue(Ops[0], Ops[1], IVI->getIndices());
-
- if (auto *EVI = dyn_cast<ExtractValueInst>(I))
- return ConstantExpr::getExtractValue(Ops[0], EVI->getIndices());
-
return ConstantFoldInstOperands(I, Ops, DL, TLI);
}
@@ -1185,10 +1212,9 @@ Constant *llvm::ConstantFoldInstOperands(Instruction *I,
return ConstantFoldInstOperandsImpl(I, I->getOpcode(), Ops, DL, TLI);
}
-Constant *llvm::ConstantFoldCompareInstOperands(unsigned IntPredicate,
- Constant *Ops0, Constant *Ops1,
- const DataLayout &DL,
- const TargetLibraryInfo *TLI) {
+Constant *llvm::ConstantFoldCompareInstOperands(
+ unsigned IntPredicate, Constant *Ops0, Constant *Ops1, const DataLayout &DL,
+ const TargetLibraryInfo *TLI, const Instruction *I) {
CmpInst::Predicate Predicate = (CmpInst::Predicate)IntPredicate;
// fold: icmp (inttoptr x), null -> icmp x, 0
// fold: icmp null, (inttoptr x) -> icmp 0, x
@@ -1290,6 +1316,11 @@ Constant *llvm::ConstantFoldCompareInstOperands(unsigned IntPredicate,
return ConstantFoldCompareInstOperands(Predicate, Ops1, Ops0, DL, TLI);
}
+ // Flush any denormal constant float input according to denormal handling
+ // mode.
+ Ops0 = FlushFPConstant(Ops0, I, /* IsOutput */ false);
+ Ops1 = FlushFPConstant(Ops1, I, /* IsOutput */ false);
+
return ConstantExpr::getCompare(Predicate, Ops0, Ops1);
}
@@ -1311,6 +1342,63 @@ Constant *llvm::ConstantFoldBinaryOpOperands(unsigned Opcode, Constant *LHS,
return ConstantExpr::get(Opcode, LHS, RHS);
}
+Constant *llvm::FlushFPConstant(Constant *Operand, const Instruction *I,
+ bool IsOutput) {
+ if (!I || !I->getParent() || !I->getFunction())
+ return Operand;
+
+ ConstantFP *CFP = dyn_cast<ConstantFP>(Operand);
+ if (!CFP)
+ return Operand;
+
+ const APFloat &APF = CFP->getValueAPF();
+ Type *Ty = CFP->getType();
+ DenormalMode DenormMode =
+ I->getFunction()->getDenormalMode(Ty->getFltSemantics());
+ DenormalMode::DenormalModeKind Mode =
+ IsOutput ? DenormMode.Output : DenormMode.Input;
+ switch (Mode) {
+ default:
+ llvm_unreachable("unknown denormal mode");
+ return Operand;
+ case DenormalMode::IEEE:
+ return Operand;
+ case DenormalMode::PreserveSign:
+ if (APF.isDenormal()) {
+ return ConstantFP::get(
+ Ty->getContext(),
+ APFloat::getZero(Ty->getFltSemantics(), APF.isNegative()));
+ }
+ return Operand;
+ case DenormalMode::PositiveZero:
+ if (APF.isDenormal()) {
+ return ConstantFP::get(Ty->getContext(),
+ APFloat::getZero(Ty->getFltSemantics(), false));
+ }
+ return Operand;
+ }
+ return Operand;
+}
+
+Constant *llvm::ConstantFoldFPInstOperands(unsigned Opcode, Constant *LHS,
+ Constant *RHS, const DataLayout &DL,
+ const Instruction *I) {
+ if (Instruction::isBinaryOp(Opcode)) {
+ // Flush denormal inputs if needed.
+ Constant *Op0 = FlushFPConstant(LHS, I, /* IsOutput */ false);
+ Constant *Op1 = FlushFPConstant(RHS, I, /* IsOutput */ false);
+
+ // Calculate constant result.
+ Constant *C = ConstantFoldBinaryOpOperands(Opcode, Op0, Op1, DL);
+
+ // Flush denormal output if needed.
+ return FlushFPConstant(C, I, /* IsOutput */ true);
+ }
+ // If instruction lacks a parent/function and the denormal mode cannot be
+ // determined, use the default (IEEE).
+ return ConstantFoldBinaryOpOperands(Opcode, LHS, RHS, DL);
+}
+
Constant *llvm::ConstantFoldCastOperand(unsigned Opcode, Constant *C,
Type *DestTy, const DataLayout &DL) {
assert(Instruction::isCast(Opcode));
@@ -1337,6 +1425,19 @@ Constant *llvm::ConstantFoldCastOperand(unsigned Opcode, Constant *C,
DL, BaseOffset, /*AllowNonInbounds=*/true));
if (Base->isNullValue()) {
FoldedValue = ConstantInt::get(CE->getContext(), BaseOffset);
+ } else {
+ // ptrtoint (gep i8, Ptr, (sub 0, V)) -> sub (ptrtoint Ptr), V
+ if (GEP->getNumIndices() == 1 &&
+ GEP->getSourceElementType()->isIntegerTy(8)) {
+ auto *Ptr = cast<Constant>(GEP->getPointerOperand());
+ auto *Sub = dyn_cast<ConstantExpr>(GEP->getOperand(1));
+ Type *IntIdxTy = DL.getIndexType(Ptr->getType());
+ if (Sub && Sub->getType() == IntIdxTy &&
+ Sub->getOpcode() == Instruction::Sub &&
+ Sub->getOperand(0)->isNullValue())
+ FoldedValue = ConstantExpr::getSub(
+ ConstantExpr::getPtrToInt(Ptr, IntIdxTy), Sub->getOperand(1));
+ }
}
}
if (FoldedValue) {
@@ -1389,6 +1490,8 @@ Constant *llvm::ConstantFoldCastOperand(unsigned Opcode, Constant *C,
bool llvm::canConstantFoldCallTo(const CallBase *Call, const Function *F) {
if (Call->isNoBuiltin())
return false;
+ if (Call->getFunctionType() != F->getFunctionType())
+ return false;
switch (F->getIntrinsicID()) {
// Operations that do not operate floating-point numbers and do not depend on
// FP environment can be folded even in strictfp functions.
@@ -1530,6 +1633,8 @@ bool llvm::canConstantFoldCallTo(const CallBase *Call, const Function *F) {
case Intrinsic::experimental_constrained_trunc:
case Intrinsic::experimental_constrained_nearbyint:
case Intrinsic::experimental_constrained_rint:
+ case Intrinsic::experimental_constrained_fcmp:
+ case Intrinsic::experimental_constrained_fcmps:
return true;
default:
return false;
@@ -1801,12 +1906,12 @@ static bool mayFoldConstrained(ConstrainedFPIntrinsic *CI,
// If evaluation raised FP exception, the result can depend on rounding
// mode. If the latter is unknown, folding is not possible.
- if (!ORM || *ORM == RoundingMode::Dynamic)
+ if (ORM && *ORM == RoundingMode::Dynamic)
return false;
// If FP exceptions are ignored, fold the call, even if such exception is
// raised.
- if (!EB || *EB != fp::ExceptionBehavior::ebStrict)
+ if (EB && *EB != fp::ExceptionBehavior::ebStrict)
return true;
// Leave the calculation for runtime so that exception flags be correctly set
@@ -1982,7 +2087,7 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
case Intrinsic::experimental_constrained_rint: {
auto CI = cast<ConstrainedFPIntrinsic>(Call);
RM = CI->getRoundingMode();
- if (!RM || RM.getValue() == RoundingMode::Dynamic)
+ if (!RM || *RM == RoundingMode::Dynamic)
return nullptr;
break;
}
@@ -2304,6 +2409,24 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
return nullptr;
}
+static Constant *evaluateCompare(const APFloat &Op1, const APFloat &Op2,
+ const ConstrainedFPIntrinsic *Call) {
+ APFloat::opStatus St = APFloat::opOK;
+ auto *FCmp = cast<ConstrainedFPCmpIntrinsic>(Call);
+ FCmpInst::Predicate Cond = FCmp->getPredicate();
+ if (FCmp->isSignaling()) {
+ if (Op1.isNaN() || Op2.isNaN())
+ St = APFloat::opInvalidOp;
+ } else {
+ if (Op1.isSignaling() || Op2.isSignaling())
+ St = APFloat::opInvalidOp;
+ }
+ bool Result = FCmpInst::compare(Op1, Op2, Cond);
+ if (mayFoldConstrained(const_cast<ConstrainedFPCmpIntrinsic *>(FCmp), St))
+ return ConstantInt::get(Call->getType()->getScalarType(), Result);
+ return nullptr;
+}
+
static Constant *ConstantFoldScalarCall2(StringRef Name,
Intrinsic::ID IntrinsicID,
Type *Ty,
@@ -2332,8 +2455,6 @@ static Constant *ConstantFoldScalarCall2(StringRef Name,
}
if (const auto *Op1 = dyn_cast<ConstantFP>(Operands[0])) {
- if (!Ty->isFloatingPointTy())
- return nullptr;
const APFloat &Op1V = Op1->getValueAPF();
if (const auto *Op2 = dyn_cast<ConstantFP>(Operands[1])) {
@@ -2363,6 +2484,9 @@ static Constant *ConstantFoldScalarCall2(StringRef Name,
case Intrinsic::experimental_constrained_frem:
St = Res.mod(Op2V);
break;
+ case Intrinsic::experimental_constrained_fcmp:
+ case Intrinsic::experimental_constrained_fcmps:
+ return evaluateCompare(Op1V, Op2V, ConstrIntr);
}
if (mayFoldConstrained(const_cast<ConstrainedFPIntrinsic *>(ConstrIntr),
St))
@@ -2487,6 +2611,11 @@ static Constant *ConstantFoldScalarCall2(StringRef Name,
case Intrinsic::smin:
case Intrinsic::umax:
case Intrinsic::umin:
+ // This is the same as for binary ops - poison propagates.
+ // TODO: Poison handling should be consolidated.
+ if (isa<PoisonValue>(Operands[0]) || isa<PoisonValue>(Operands[1]))
+ return PoisonValue::get(Ty);
+
if (!C0 && !C1)
return UndefValue::get(Ty);
if (!C0 || !C1)
@@ -2553,6 +2682,11 @@ static Constant *ConstantFoldScalarCall2(StringRef Name,
}
case Intrinsic::uadd_sat:
case Intrinsic::sadd_sat:
+ // This is the same as for binary ops - poison propagates.
+ // TODO: Poison handling should be consolidated.
+ if (isa<PoisonValue>(Operands[0]) || isa<PoisonValue>(Operands[1]))
+ return PoisonValue::get(Ty);
+
if (!C0 && !C1)
return UndefValue::get(Ty);
if (!C0 || !C1)
@@ -2563,6 +2697,11 @@ static Constant *ConstantFoldScalarCall2(StringRef Name,
return ConstantInt::get(Ty, C0->sadd_sat(*C1));
case Intrinsic::usub_sat:
case Intrinsic::ssub_sat:
+ // This is the same as for binary ops - poison propagates.
+ // TODO: Poison handling should be consolidated.
+ if (isa<PoisonValue>(Operands[0]) || isa<PoisonValue>(Operands[1]))
+ return PoisonValue::get(Ty);
+
if (!C0 && !C1)
return UndefValue::get(Ty);
if (!C0 || !C1)
@@ -2843,11 +2982,11 @@ static Constant *ConstantFoldScalarCall3(StringRef Name,
unsigned Width = C0->getBitWidth();
assert(Scale < Width && "Illegal scale.");
unsigned ExtendedWidth = Width * 2;
- APInt Product = (C0->sextOrSelf(ExtendedWidth) *
- C1->sextOrSelf(ExtendedWidth)).ashr(Scale);
+ APInt Product =
+ (C0->sext(ExtendedWidth) * C1->sext(ExtendedWidth)).ashr(Scale);
if (IntrinsicID == Intrinsic::smul_fix_sat) {
- APInt Max = APInt::getSignedMaxValue(Width).sextOrSelf(ExtendedWidth);
- APInt Min = APInt::getSignedMinValue(Width).sextOrSelf(ExtendedWidth);
+ APInt Max = APInt::getSignedMaxValue(Width).sext(ExtendedWidth);
+ APInt Min = APInt::getSignedMinValue(Width).sext(ExtendedWidth);
Product = APIntOps::smin(Product, Max);
Product = APIntOps::smax(Product, Min);
}
@@ -3001,7 +3140,7 @@ static Constant *ConstantFoldFixedVectorCall(
// Gather a column of constants.
for (unsigned J = 0, JE = Operands.size(); J != JE; ++J) {
// Some intrinsics use a scalar type for certain arguments.
- if (hasVectorInstrinsicScalarOpd(IntrinsicID, J)) {
+ if (isVectorIntrinsicWithScalarOpAtArg(IntrinsicID, J)) {
Lane[J] = Operands[J];
continue;
}