diff --git a/llvm/include/llvm/Analysis/ConstantFolding.h b/llvm/include/llvm/Analysis/ConstantFolding.h --- a/llvm/include/llvm/Analysis/ConstantFolding.h +++ b/llvm/include/llvm/Analysis/ConstantFolding.h @@ -136,7 +136,9 @@ /// ConstantFoldLoadThroughGEPConstantExpr - Given a constant and a /// getelementptr constantexpr, return the constant value being addressed by the /// constant expression, or null if something is funny and we can't decide. -Constant *ConstantFoldLoadThroughGEPConstantExpr(Constant *C, ConstantExpr *CE); +Constant *ConstantFoldLoadThroughGEPConstantExpr(Constant *C, ConstantExpr *CE, + Type *Ty, + const DataLayout &DL); /// ConstantFoldLoadThroughGEPIndices - Given a constant and getelementptr /// indices (with an *implied* zero pointer index that is not in the list), diff --git a/llvm/include/llvm/Transforms/Utils/Evaluator.h b/llvm/include/llvm/Transforms/Utils/Evaluator.h --- a/llvm/include/llvm/Transforms/Utils/Evaluator.h +++ b/llvm/include/llvm/Transforms/Utils/Evaluator.h @@ -92,7 +92,7 @@ bool getFormalParams(CallBase &CB, Function *F, SmallVectorImpl &Formals); - Constant *ComputeLoadResult(Constant *P); + Constant *ComputeLoadResult(Constant *P, Type *Ty); /// As we compute SSA register values, we store their contents here. The back /// of the deque contains the current function and the stack contains the diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -658,16 +658,10 @@ Constant *ConstantFoldLoadThroughBitcastExpr(ConstantExpr *CE, Type *DestTy, const DataLayout &DL) { auto *SrcPtr = CE->getOperand(0); - auto *SrcPtrTy = dyn_cast(SrcPtr->getType()); - if (!SrcPtrTy) + if (!SrcPtr->getType()->isPointerTy()) return nullptr; - Type *SrcTy = SrcPtrTy->getPointerElementType(); - Constant *C = ConstantFoldLoadFromConstPtr(SrcPtr, SrcTy, DL); - if (!C) - return nullptr; - - return llvm::ConstantFoldLoadThroughBitcast(C, DestTy, DL); + return ConstantFoldLoadFromConstPtr(SrcPtr, DestTy, DL); } } // end anonymous namespace @@ -677,7 +671,7 @@ // First, try the easy cases: if (auto *GV = dyn_cast(C)) if (GV->isConstant() && GV->hasDefinitiveInitializer()) - return GV->getInitializer(); + return ConstantFoldLoadThroughBitcast(GV->getInitializer(), Ty, DL); if (auto *GA = dyn_cast(C)) if (GA->getAliasee() && !GA->isInterposable()) @@ -691,8 +685,8 @@ if (CE->getOpcode() == Instruction::GetElementPtr) { if (auto *GV = dyn_cast(CE->getOperand(0))) { if (GV->isConstant() && GV->hasDefinitiveInitializer()) { - if (Constant *V = - ConstantFoldLoadThroughGEPConstantExpr(GV->getInitializer(), CE)) + if (Constant *V = ConstantFoldLoadThroughGEPConstantExpr( + GV->getInitializer(), CE, Ty, DL)) return V; } } @@ -1410,7 +1404,9 @@ } Constant *llvm::ConstantFoldLoadThroughGEPConstantExpr(Constant *C, - ConstantExpr *CE) { + ConstantExpr *CE, + Type *Ty, + const DataLayout &DL) { if (!CE->getOperand(1)->isNullValue()) return nullptr; // Do not allow stepping over the value! @@ -1421,7 +1417,7 @@ if (!C) return nullptr; } - return C; + return ConstantFoldLoadThroughBitcast(C, Ty, DL); } Constant * diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp --- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp +++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp @@ -296,10 +296,13 @@ if (LoadInst *LI = dyn_cast(U)) { if (Init) { - // Replace the load with the initializer. - LI->replaceAllUsesWith(Init); - LI->eraseFromParent(); - Changed = true; + if (auto *Casted = + ConstantFoldLoadThroughBitcast(Init, LI->getType(), DL)) { + // Replace the load with the initializer. + LI->replaceAllUsesWith(Casted); + LI->eraseFromParent(); + Changed = true; + } } } else if (StoreInst *SI = dyn_cast(U)) { // Store must be unreachable or storing Init into the global. @@ -309,7 +312,8 @@ if (CE->getOpcode() == Instruction::GetElementPtr) { Constant *SubInit = nullptr; if (Init) - SubInit = ConstantFoldLoadThroughGEPConstantExpr(Init, CE); + SubInit = ConstantFoldLoadThroughGEPConstantExpr( + Init, CE, V->getType()->getPointerElementType(), DL); Changed |= CleanupConstantGlobalUsers(CE, SubInit, DL, GetTLI); } else if ((CE->getOpcode() == Instruction::BitCast && CE->getType()->isPointerTy()) || @@ -331,7 +335,8 @@ ConstantExpr *CE = dyn_cast_or_null( ConstantFoldInstruction(GEP, DL, &GetTLI(*GEP->getFunction()))); if (Init && CE && CE->getOpcode() == Instruction::GetElementPtr) - SubInit = ConstantFoldLoadThroughGEPConstantExpr(Init, CE); + SubInit = ConstantFoldLoadThroughGEPConstantExpr( + Init, CE, V->getType()->getPointerElementType(), DL); // If the initializer is an all-null value and we have an inbounds GEP, // we already know what the result of any load from that GEP is. diff --git a/llvm/lib/Transforms/Utils/Evaluator.cpp b/llvm/lib/Transforms/Utils/Evaluator.cpp --- a/llvm/lib/Transforms/Utils/Evaluator.cpp +++ b/llvm/lib/Transforms/Utils/Evaluator.cpp @@ -127,7 +127,7 @@ /// another pointer type, we punt. We basically just support direct accesses to /// globals and GEP's of globals. This should be kept up to date with /// CommitValueTo. -static bool isSimpleEnoughPointerToCommit(Constant *C) { +static bool isSimpleEnoughPointerToCommit(Constant *C, const DataLayout &DL) { // Conservatively, avoid aggregate types. This is because we don't // want to worry about them partially overlapping other stores. if (!cast(C->getType())->getElementType()->isSingleValueType()) @@ -157,13 +157,14 @@ if (!CE->isGEPWithNoNotionalOverIndexing()) return false; - return ConstantFoldLoadThroughGEPConstantExpr(GV->getInitializer(), CE); - - // A constantexpr bitcast from a pointer to another pointer is a no-op, - // and we know how to evaluate it by moving the bitcast from the pointer - // operand to the value operand. + return ConstantFoldLoadThroughGEPConstantExpr( + GV->getInitializer(), CE, + cast(CE)->getResultElementType(), DL); } else if (CE->getOpcode() == Instruction::BitCast && isa(CE->getOperand(0))) { + // A constantexpr bitcast from a pointer to another pointer is a no-op, + // and we know how to evaluate it by moving the bitcast from the pointer + // operand to the value operand. // Do not allow weak/*_odr/linkonce/dllimport/dllexport linkage or // external globals. return cast(CE->getOperand(0))->hasUniqueInitializer(); @@ -207,7 +208,7 @@ /// Return the value that would be computed by a load from P after the stores /// reflected by 'memory' have been performed. If we can't decide, return null. -Constant *Evaluator::ComputeLoadResult(Constant *P) { +Constant *Evaluator::ComputeLoadResult(Constant *P, Type *Ty) { // If this memory location has been recently stored, use the stored value: it // is the most up-to-date. auto findMemLoc = [this](Constant *Ptr) { return MutatedMemory.lookup(Ptr); }; @@ -227,7 +228,7 @@ // Handle a constantexpr getelementptr. case Instruction::GetElementPtr: if (auto *I = getInitializer(CE->getOperand(0))) - return ConstantFoldLoadThroughGEPConstantExpr(I, CE); + return ConstantFoldLoadThroughGEPConstantExpr(I, CE, Ty, DL); break; // Handle a constantexpr bitcast. case Instruction::BitCast: @@ -340,7 +341,7 @@ Ptr = FoldedPtr; LLVM_DEBUG(dbgs() << "; To: " << *Ptr << "\n"); } - if (!isSimpleEnoughPointerToCommit(Ptr)) { + if (!isSimpleEnoughPointerToCommit(Ptr, DL)) { // If this is too complex for us to commit, reject it. LLVM_DEBUG( dbgs() << "Pointer is too complex for us to evaluate store."); @@ -450,7 +451,7 @@ "folding: " << *Ptr << "\n"); } - InstResult = ComputeLoadResult(Ptr); + InstResult = ComputeLoadResult(Ptr, LI->getType()); if (!InstResult) { LLVM_DEBUG( dbgs() << "Failed to compute load result. Can not evaluate load." @@ -496,7 +497,8 @@ } Constant *Ptr = getVal(MSI->getDest()); Constant *Val = getVal(MSI->getValue()); - Constant *DestVal = ComputeLoadResult(getVal(Ptr)); + Constant *DestVal = + ComputeLoadResult(getVal(Ptr), MSI->getValue()->getType()); if (Val->isNullValue() && DestVal && DestVal->isNullValue()) { // This memset is a no-op. LLVM_DEBUG(dbgs() << "Ignoring no-op memset.\n");