39#define DEBUG_TYPE "evaluator"
62 if (
auto *GV = dyn_cast<GlobalValue>(
C))
63 return !GV->hasDLLImportStorageClass() && !GV->isThreadLocal();
66 if (
C->getNumOperands() == 0 || isa<BlockAddress>(
C))
70 if (isa<ConstantAggregate>(
C)) {
81 switch (CE->getOpcode()) {
82 case Instruction::BitCast:
86 case Instruction::IntToPtr:
87 case Instruction::PtrToInt:
90 if (
DL.getTypeSizeInBits(CE->getType()) !=
91 DL.getTypeSizeInBits(CE->getOperand(0)->getType()))
96 case Instruction::GetElementPtr:
97 for (
unsigned i = 1, e = CE->getNumOperands(); i != e; ++i)
98 if (!isa<ConstantInt>(CE->getOperand(i)))
102 case Instruction::Add:
104 if (!isa<ConstantInt>(CE->getOperand(1)))
116 if (!SimpleConstants.
insert(
C).second)
122void Evaluator::MutableValue::clear() {
123 if (
auto *Agg = dyn_cast_if_present<MutableAggregate *>(Val))
131 const MutableValue *
V =
this;
132 while (
const auto *Agg = dyn_cast_if_present<MutableAggregate *>(
V->Val)) {
133 Type *AggTy = Agg->Ty;
134 std::optional<APInt>
Index =
DL.getGEPIndexForOffset(AggTy,
Offset);
135 if (!Index ||
Index->uge(Agg->Elements.size()) ||
136 !TypeSize::isKnownLE(TySize,
DL.getTypeStoreSize(AggTy)))
139 V = &Agg->Elements[
Index->getZExtValue()];
145bool Evaluator::MutableValue::makeMutable() {
147 Type *Ty =
C->getType();
148 unsigned NumElements;
149 if (
auto *VT = dyn_cast<FixedVectorType>(Ty)) {
150 NumElements = VT->getNumElements();
151 }
else if (
auto *AT = dyn_cast<ArrayType>(Ty))
152 NumElements = AT->getNumElements();
153 else if (
auto *ST = dyn_cast<StructType>(Ty))
154 NumElements =
ST->getNumElements();
158 MutableAggregate *MA =
new MutableAggregate(Ty);
159 MA->Elements.reserve(NumElements);
160 for (
unsigned I = 0;
I < NumElements; ++
I)
161 MA->Elements.push_back(
C->getAggregateElement(
I));
168 Type *Ty =
V->getType();
170 MutableValue *MV =
this;
173 if (isa<Constant *>(MV->Val) && !MV->makeMutable())
176 MutableAggregate *Agg = cast<MutableAggregate *>(MV->Val);
177 Type *AggTy = Agg->Ty;
178 std::optional<APInt>
Index =
DL.getGEPIndexForOffset(AggTy,
Offset);
179 if (!Index ||
Index->uge(Agg->Elements.size()) ||
180 !TypeSize::isKnownLE(TySize,
DL.getTypeStoreSize(AggTy)))
183 MV = &Agg->Elements[
Index->getZExtValue()];
186 Type *MVType = MV->getType();
192 else if (Ty != MVType)
199Constant *Evaluator::MutableAggregate::toConstant()
const {
201 for (
const MutableValue &MV : Elements)
204 if (
auto *ST = dyn_cast<StructType>(Ty))
206 if (
auto *AT = dyn_cast<ArrayType>(Ty))
208 assert(isa<FixedVectorType>(Ty) &&
"Must be vector");
216 P = cast<Constant>(
P->stripAndAccumulateConstantOffsets(
219 if (
auto *GV = dyn_cast<GlobalVariable>(
P))
220 return ComputeLoadResult(GV, Ty,
Offset);
226 auto It = MutatedMemory.find(GV);
227 if (It != MutatedMemory.end())
228 return It->second.read(Ty,
Offset, DL);
236 if (
auto *Fn = dyn_cast<Function>(
C))
239 if (
auto *Alias = dyn_cast<GlobalAlias>(
C))
240 if (
auto *Fn = dyn_cast<Function>(Alias->getAliasee()))
246Evaluator::getCalleeWithFormalArgs(
CallBase &CB,
250 return getFormalParams(CB, Fn, Formals) ? Fn :
nullptr;
256 auto *FTy =
F->getFunctionType();
272 bool &StrippedPointerCastsForAliasAnalysis) {
277 LLVM_DEBUG(
dbgs() <<
"Evaluating Instruction: " << *CurInst <<
"\n");
279 if (
StoreInst *SI = dyn_cast<StoreInst>(CurInst)) {
280 if (
SI->isVolatile()) {
286 if (
Ptr != FoldedPtr) {
293 Ptr = cast<Constant>(
Ptr->stripAndAccumulateConstantOffsets(
296 auto *GV = dyn_cast<GlobalVariable>(
Ptr);
298 LLVM_DEBUG(
dbgs() <<
"Store is not to global with unique initializer: "
307 LLVM_DEBUG(
dbgs() <<
"Store value is too complex to evaluate store. "
313 if (!Res.first->second.write(Val,
Offset, DL))
315 }
else if (
LoadInst *LI = dyn_cast<LoadInst>(CurInst)) {
316 if (LI->isVolatile()) {
318 dbgs() <<
"Found a Load! Volatile load, can not evaluate.\n");
324 if (
Ptr != FoldedPtr) {
326 LLVM_DEBUG(
dbgs() <<
"Found a constant pointer expression, constant "
330 InstResult = ComputeLoadResult(
Ptr, LI->getType());
333 dbgs() <<
"Failed to compute load result. Can not evaluate load."
339 }
else if (
AllocaInst *AI = dyn_cast<AllocaInst>(CurInst)) {
340 if (AI->isArrayAllocation()) {
341 LLVM_DEBUG(
dbgs() <<
"Found an array alloca. Can not evaluate.\n");
344 Type *Ty = AI->getAllocatedType();
345 AllocaTmps.push_back(std::make_unique<GlobalVariable>(
348 AI->getType()->getPointerAddressSpace()));
349 InstResult = AllocaTmps.back().get();
350 LLVM_DEBUG(
dbgs() <<
"Found an alloca. Result: " << *InstResult <<
"\n");
351 }
else if (isa<CallInst>(CurInst) || isa<InvokeInst>(CurInst)) {
352 CallBase &CB = *cast<CallBase>(&*CurInst);
355 if (isa<DbgInfoIntrinsic>(CB)) {
369 if (MSI->isVolatile()) {
375 auto *LenC = dyn_cast<ConstantInt>(getVal(MSI->getLength()));
383 Ptr = cast<Constant>(
Ptr->stripAndAccumulateConstantOffsets(
385 auto *GV = dyn_cast<GlobalVariable>(
Ptr);
391 Constant *Val = getVal(MSI->getValue());
394 if (!Val->
isNullValue() || MutatedMemory.contains(GV) ||
398 if (
Len.ugt(64 * 1024)) {
406 if (DestVal != Val) {
408 <<
Offset <<
" of " << *GV <<
".\n");
421 if (
II->isLifetimeStartOrEnd()) {
427 if (
II->getIntrinsicID() == Intrinsic::invariant_start) {
430 if (!
II->use_empty()) {
432 <<
"Found unused invariant_start. Can't evaluate.\n");
436 Value *PtrArg = getVal(
II->getArgOperand(1));
440 if (!
Size->isMinusOne() &&
441 Size->getValue().getLimitedValue() >=
442 DL.getTypeStoreSize(ElemTy)) {
443 Invariants.insert(GV);
448 <<
"Found a global var, but can not treat it as an "
455 }
else if (
II->getIntrinsicID() == Intrinsic::assume) {
459 }
else if (
II->getIntrinsicID() == Intrinsic::sideeffect) {
463 }
else if (
II->getIntrinsicID() == Intrinsic::pseudoprobe) {
472 if (Stripped != &*CurInst) {
473 InstResult = getVal(Stripped);
477 <<
"Stripped pointer casts for alias analysis for "
478 "intrinsic call.\n");
479 StrippedPointerCastsForAliasAnalysis =
true;
492 if (!Callee ||
Callee->isInterposable()) {
497 if (
Callee->isDeclaration()) {
502 << *InstResult <<
"\n");
508 if (
Callee->getFunctionType()->isVarArg()) {
510 <<
"Can not constant fold vararg function call.\n");
516 ValueStack.emplace_back();
521 ValueStack.pop_back();
525 << *InstResult <<
"\n\n");
528 <<
"Successfully evaluated function. Result: 0\n\n");
532 }
else if (CurInst->isTerminator()) {
535 if (
BranchInst *BI = dyn_cast<BranchInst>(CurInst)) {
536 if (BI->isUnconditional()) {
537 NextBB = BI->getSuccessor(0);
540 dyn_cast<ConstantInt>(getVal(BI->getCondition()));
541 if (!
Cond)
return false;
543 NextBB = BI->getSuccessor(!
Cond->getZExtValue());
545 }
else if (
SwitchInst *SI = dyn_cast<SwitchInst>(CurInst)) {
547 dyn_cast<ConstantInt>(getVal(
SI->getCondition()));
548 if (!Val)
return false;
549 NextBB =
SI->findCaseValue(Val)->getCaseSuccessor();
550 }
else if (
IndirectBrInst *IBI = dyn_cast<IndirectBrInst>(CurInst)) {
553 NextBB = BA->getBasicBlock();
556 }
else if (isa<ReturnInst>(CurInst)) {
569 for (
Value *
Op : CurInst->operands())
573 LLVM_DEBUG(
dbgs() <<
"Cannot fold instruction: " << *CurInst <<
"\n");
577 << *InstResult <<
"\n");
580 if (!CurInst->use_empty()) {
582 setVal(&*CurInst, InstResult);
587 NextBB =
II->getNormalDest();
588 LLVM_DEBUG(
dbgs() <<
"Found an invoke instruction. Finished Block.\n\n");
602 assert(ActualArgs.
size() ==
F->arg_size() &&
"wrong number of arguments");
609 CallStack.push_back(
F);
613 setVal(&Arg, ActualArgs[ArgNo]);
627 LLVM_DEBUG(
dbgs() <<
"Trying to evaluate BB: " << *CurBB <<
"\n");
629 bool StrippedPointerCastsForAliasAnalysis =
false;
631 if (!EvaluateBlock(CurInst, NextBB, StrippedPointerCastsForAliasAnalysis))
644 if (StrippedPointerCastsForAliasAnalysis &&
650 CallStack.pop_back();
657 if (!ExecutedBlocks.
insert(NextBB).second)
664 for (CurInst = NextBB->
begin();
665 (PN = dyn_cast<PHINode>(CurInst)); ++CurInst)
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
This file contains the declarations for the subclasses of Constant, which represent the different fla...
This file defines the DenseMap class.
static bool isSimpleEnoughValueToCommitHelper(Constant *C, SmallPtrSetImpl< Constant * > &SimpleConstants, const DataLayout &DL)
Return true if the specified constant can be handled by the code generator.
static bool isSimpleEnoughValueToCommit(Constant *C, SmallPtrSetImpl< Constant * > &SimpleConstants, const DataLayout &DL)
static Function * getFunction(Constant *C)
uint64_t IntrinsicInst * II
const SmallVectorImpl< MachineOperand > & Cond
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the SmallPtrSet class.
This file defines the SmallVector class.
Class for arbitrary precision integers.
an instruction to allocate memory on the stack
LLVM Basic Block Representation.
iterator begin()
Instruction iterator methods.
InstListType::iterator iterator
Instruction iterators...
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
The address of a basic block.
Conditional or Unconditional Branch instruction.
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
bool isInlineAsm() const
Check if this call is an inline asm statement.
Value * getCalledOperand() const
FunctionType * getFunctionType() const
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
static bool isBitOrNoopPointerCastable(Type *SrcTy, Type *DestTy, const DataLayout &DL)
Check whether a bitcast, inttoptr, or ptrtoint cast between these types is valid and a no-op.
static Constant * get(ArrayType *T, ArrayRef< Constant * > V)
A constant value that is initialized with an expression using other constant values.
static Constant * getIntToPtr(Constant *C, Type *Ty, bool OnlyIfReduced=false)
static Constant * getPtrToInt(Constant *C, Type *Ty, bool OnlyIfReduced=false)
static Constant * getBitCast(Constant *C, Type *Ty, bool OnlyIfReduced=false)
This is the shared class of boolean and integer constants.
static Constant * get(StructType *T, ArrayRef< Constant * > V)
static Constant * get(ArrayRef< Constant * > V)
This is an important base class in LLVM.
const Constant * stripPointerCasts() const
bool isNullValue() const
Return true if this is the value that would be returned by getNullValue.
This class represents an Operation in the Expression.
A parsed version of the target data layout string in and methods for querying it.
bool EvaluateFunction(Function *F, Constant *&RetVal, const SmallVectorImpl< Constant * > &ActualArgs)
Evaluate a call to function F, returning true if successful, false if we can't evaluate it.
@ InternalLinkage
Rename collisions when linking (static functions).
Type * getValueType() const
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
bool hasUniqueInitializer() const
hasUniqueInitializer - Whether the global variable has an initializer, and any changes made to the in...
bool hasDefinitiveInitializer() const
hasDefinitiveInitializer - Whether the global variable has an initializer, and any other instances of...
Indirect Branch Instruction.
A wrapper class for inspecting calls to intrinsic functions.
An instruction for reading from memory.
This class wraps the llvm.memset and llvm.memset.inline intrinsics.
Value * getIncomingValueForBlock(const BasicBlock *BB) const
Return a value (possibly void), from a function.
Value * getReturnValue() const
Convenience accessor. Returns null if there is no return value.
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
The instances of the Type class are immutable: once they are created, they are never changed.
bool isPointerTy() const
True if this is an instance of PointerType.
bool isIntegerTy() const
True if this is an instance of IntegerType.
bool isVoidTy() const
Return true if this is 'void'.
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
Value * getOperand(unsigned i) const
unsigned getNumOperands() const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
const Value * stripPointerCasts() const
Strip off pointer casts, all-zero GEPs and address space casts.
StringRef getName() const
Return a constant reference to the value's name.
const Value * stripPointerCastsForAliasAnalysis() const
Strip off pointer casts, all-zero GEPs, single-argument phi nodes and invariant group info.
@ C
The default llvm calling convention, compatible with C.
This is an optimization pass for GlobalISel generic memory operations.
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Constant * ConstantFoldCall(const CallBase *Call, Function *F, ArrayRef< Constant * > Operands, const TargetLibraryInfo *TLI=nullptr, bool AllowNonDeterministic=true)
ConstantFoldCall - Attempt to constant fold a call to the specified function with the specified argum...
Constant * ConstantFoldConstant(const Constant *C, const DataLayout &DL, const TargetLibraryInfo *TLI=nullptr)
ConstantFoldConstant - Fold the constant using the specified DataLayout.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Constant * ConstantFoldInstOperands(Instruction *I, ArrayRef< Constant * > Ops, const DataLayout &DL, const TargetLibraryInfo *TLI=nullptr, bool AllowNonDeterministic=true)
ConstantFoldInstOperands - Attempt to constant fold an instruction with the specified operands.
Constant * ConstantFoldLoadFromConst(Constant *C, Type *Ty, const APInt &Offset, const DataLayout &DL)
Extract value of C at the given Offset reinterpreted as Ty.
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.