diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2022-07-04 19:20:19 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2023-02-08 19:02:26 +0000 |
commit | 81ad626541db97eb356e2c1d4a20eb2a26a766ab (patch) | |
tree | 311b6a8987c32b1e1dcbab65c54cfac3fdb56175 /contrib/llvm-project/llvm/lib/Analysis/ConstantFolding.cpp | |
parent | 5fff09660e06a66bed6482da9c70df328e16bbb6 (diff) | |
parent | 145449b1e420787bb99721a429341fa6be3adfb6 (diff) |
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Analysis/ConstantFolding.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/lib/Analysis/ConstantFolding.cpp | 257 |
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; } |