diff options
| author | Manoj Gupta <manojgupta@google.com> | 2018-07-09 22:27:23 +0000 |
|---|---|---|
| committer | Manoj Gupta <manojgupta@google.com> | 2018-07-09 22:27:23 +0000 |
| commit | 77eeac3d9e9418ac0aea131d20ac84b656977814 (patch) | |
| tree | 0ca98362b1ae59875a26b0df269bf09a1854d982 /llvm/lib/Transforms | |
| parent | 0230f7c763c5b5f988f629506f0ce050fbacaed4 (diff) | |
| download | bcm5719-llvm-77eeac3d9e9418ac0aea131d20ac84b656977814.tar.gz bcm5719-llvm-77eeac3d9e9418ac0aea131d20ac84b656977814.zip | |
llvm: Add support for "-fno-delete-null-pointer-checks"
Summary:
Support for this option is needed for building Linux kernel.
This is a very frequently requested feature by kernel developers.
More details : https://lkml.org/lkml/2018/4/4/601
GCC option description for -fdelete-null-pointer-checks:
This Assume that programs cannot safely dereference null pointers,
and that no code or data element resides at address zero.
-fno-delete-null-pointer-checks is the inverse of this implying that
null pointer dereferencing is not undefined.
This feature is implemented in LLVM IR in this CL as the function attribute
"null-pointer-is-valid"="true" in IR (Under review at D47894).
The CL updates several passes that assumed null pointer dereferencing is
undefined to not optimize when the "null-pointer-is-valid"="true"
attribute is present.
Reviewers: t.p.northover, efriedma, jyknight, chandlerc, rnk, srhines, void, george.burgess.iv
Reviewed By: efriedma, george.burgess.iv
Subscribers: eraman, haicheng, george.burgess.iv, drinkcat, theraven, reames, sanjoy, xbolva00, llvm-commits
Differential Revision: https://reviews.llvm.org/D47895
llvm-svn: 336613
Diffstat (limited to 'llvm/lib/Transforms')
| -rw-r--r-- | llvm/lib/Transforms/IPO/GlobalOpt.cpp | 19 | ||||
| -rw-r--r-- | llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp | 4 | ||||
| -rw-r--r-- | llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp | 17 | ||||
| -rw-r--r-- | llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp | 26 | ||||
| -rw-r--r-- | llvm/lib/Transforms/Scalar/SCCP.cpp | 8 | ||||
| -rw-r--r-- | llvm/lib/Transforms/Utils/Local.cpp | 11 | ||||
| -rw-r--r-- | llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 9 |
7 files changed, 67 insertions, 27 deletions
diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp index 6f3796f4a80..1af7e689477 100644 --- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp +++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp @@ -636,7 +636,13 @@ static GlobalVariable *SRAGlobal(GlobalVariable *GV, const DataLayout &DL) { /// reprocessing them. static bool AllUsesOfValueWillTrapIfNull(const Value *V, SmallPtrSetImpl<const PHINode*> &PHIs) { - for (const User *U : V->users()) + for (const User *U : V->users()) { + if (const Instruction *I = dyn_cast<Instruction>(U)) { + // If null pointer is considered valid, then all uses are non-trapping. + // Non address-space 0 globals have already been pruned by the caller. + if (NullPointerIsDefined(I->getFunction())) + return false; + } if (isa<LoadInst>(U)) { // Will trap. } else if (const StoreInst *SI = dyn_cast<StoreInst>(U)) { @@ -670,7 +676,7 @@ static bool AllUsesOfValueWillTrapIfNull(const Value *V, //cerr << "NONTRAPPING USE: " << *U; return false; } - + } return true; } @@ -697,6 +703,10 @@ static bool OptimizeAwayTrappingUsesOfValue(Value *V, Constant *NewV) { bool Changed = false; for (auto UI = V->user_begin(), E = V->user_end(); UI != E; ) { Instruction *I = cast<Instruction>(*UI++); + // Uses are non-trapping if null pointer is considered valid. + // Non address-space 0 globals are already pruned by the caller. + if (NullPointerIsDefined(I->getFunction())) + return false; if (LoadInst *LI = dyn_cast<LoadInst>(I)) { LI->setOperand(0, NewV); Changed = true; @@ -1584,7 +1594,10 @@ static bool optimizeOnceStoredGlobal(GlobalVariable *GV, Value *StoredOnceVal, // users of the loaded value (often calls and loads) that would trap if the // value was null. if (GV->getInitializer()->getType()->isPointerTy() && - GV->getInitializer()->isNullValue()) { + GV->getInitializer()->isNullValue() && + !NullPointerIsDefined( + nullptr /* F */, + GV->getInitializer()->getType()->getPointerAddressSpace())) { if (Constant *SOVC = dyn_cast<Constant>(StoredOnceVal)) { if (GV->getInitializer()->getType() != SOVC->getType()) SOVC = ConstantExpr::getBitCast(SOVC, GV->getInitializer()->getType()); diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index 78c2d312939..29ae67af7b7 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -4020,7 +4020,9 @@ Instruction *InstCombiner::visitCallSite(CallSite CS) { } } - if (isa<ConstantPointerNull>(Callee) || isa<UndefValue>(Callee)) { + if ((isa<ConstantPointerNull>(Callee) && + !NullPointerIsDefined(CS.getInstruction()->getFunction())) || + isa<UndefValue>(Callee)) { // If CS does not return void then replaceAllUsesWith undef. // This allows ValueHandlers and custom metadata to adjust itself. if (!CS.getInstruction()->getType()->isVoidTy()) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp index 473d88e416a..742caf64900 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp @@ -964,23 +964,26 @@ static Instruction *replaceGEPIdxWithZero(InstCombiner &IC, Value *Ptr, } static bool canSimplifyNullStoreOrGEP(StoreInst &SI) { - if (SI.getPointerAddressSpace() != 0) + if (NullPointerIsDefined(SI.getFunction(), SI.getPointerAddressSpace())) return false; auto *Ptr = SI.getPointerOperand(); if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(Ptr)) Ptr = GEPI->getOperand(0); - return isa<ConstantPointerNull>(Ptr); + return (isa<ConstantPointerNull>(Ptr) && + !NullPointerIsDefined(SI.getFunction(), SI.getPointerAddressSpace())); } static bool canSimplifyNullLoadOrGEP(LoadInst &LI, Value *Op) { if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(Op)) { const Value *GEPI0 = GEPI->getOperand(0); - if (isa<ConstantPointerNull>(GEPI0) && GEPI->getPointerAddressSpace() == 0) + if (isa<ConstantPointerNull>(GEPI0) && + !NullPointerIsDefined(LI.getFunction(), GEPI->getPointerAddressSpace())) return true; } if (isa<UndefValue>(Op) || - (isa<ConstantPointerNull>(Op) && LI.getPointerAddressSpace() == 0)) + (isa<ConstantPointerNull>(Op) && + !NullPointerIsDefined(LI.getFunction(), LI.getPointerAddressSpace()))) return true; return false; } @@ -1076,14 +1079,16 @@ Instruction *InstCombiner::visitLoadInst(LoadInst &LI) { // load (select (cond, null, P)) -> load P if (isa<ConstantPointerNull>(SI->getOperand(1)) && - LI.getPointerAddressSpace() == 0) { + !NullPointerIsDefined(SI->getFunction(), + LI.getPointerAddressSpace())) { LI.setOperand(0, SI->getOperand(2)); return &LI; } // load (select (cond, P, null)) -> load P if (isa<ConstantPointerNull>(SI->getOperand(2)) && - LI.getPointerAddressSpace() == 0) { + !NullPointerIsDefined(SI->getFunction(), + LI.getPointerAddressSpace())) { LI.setOperand(0, SI->getOperand(1)); return &LI; } diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp index f99941210e9..dd1a2a6adb8 100644 --- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp +++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp @@ -310,9 +310,13 @@ static Value *getStoredPointerOperand(Instruction *I) { } static uint64_t getPointerSize(const Value *V, const DataLayout &DL, - const TargetLibraryInfo &TLI) { + const TargetLibraryInfo &TLI, + const Function *F) { uint64_t Size; - if (getObjectSize(V, Size, DL, &TLI)) + ObjectSizeOpts Opts; + Opts.NullIsUnknownSize = NullPointerIsDefined(F); + + if (getObjectSize(V, Size, DL, &TLI, Opts)) return Size; return MemoryLocation::UnknownSize; } @@ -343,7 +347,8 @@ static OverwriteResult isOverwrite(const MemoryLocation &Later, int64_t &EarlierOff, int64_t &LaterOff, Instruction *DepWrite, InstOverlapIntervalsTy &IOL, - AliasAnalysis &AA) { + AliasAnalysis &AA, + const Function *F) { // If we don't know the sizes of either access, then we can't do a comparison. if (Later.Size == MemoryLocation::UnknownSize || Earlier.Size == MemoryLocation::UnknownSize) @@ -372,7 +377,7 @@ static OverwriteResult isOverwrite(const MemoryLocation &Later, return OW_Unknown; // If the "Later" store is to a recognizable object, get its size. - uint64_t ObjectSize = getPointerSize(UO2, DL, TLI); + uint64_t ObjectSize = getPointerSize(UO2, DL, TLI, F); if (ObjectSize != MemoryLocation::UnknownSize) if (ObjectSize == Later.Size && ObjectSize >= Earlier.Size) return OW_Complete; @@ -710,7 +715,8 @@ static bool handleFree(CallInst *F, AliasAnalysis *AA, static void removeAccessedObjects(const MemoryLocation &LoadedLoc, SmallSetVector<Value *, 16> &DeadStackObjects, const DataLayout &DL, AliasAnalysis *AA, - const TargetLibraryInfo *TLI) { + const TargetLibraryInfo *TLI, + const Function *F) { const Value *UnderlyingPointer = GetUnderlyingObject(LoadedLoc.Ptr, DL); // A constant can't be in the dead pointer set. @@ -727,7 +733,7 @@ static void removeAccessedObjects(const MemoryLocation &LoadedLoc, // Remove objects that could alias LoadedLoc. DeadStackObjects.remove_if([&](Value *I) { // See if the loaded location could alias the stack location. - MemoryLocation StackLoc(I, getPointerSize(I, DL, *TLI)); + MemoryLocation StackLoc(I, getPointerSize(I, DL, *TLI, F)); return !AA->isNoAlias(StackLoc, LoadedLoc); }); } @@ -841,7 +847,8 @@ static bool handleEndBlock(BasicBlock &BB, AliasAnalysis *AA, // the call is live. DeadStackObjects.remove_if([&](Value *I) { // See if the call site touches the value. - return isRefSet(AA->getModRefInfo(CS, I, getPointerSize(I, DL, *TLI))); + return isRefSet(AA->getModRefInfo(CS, I, getPointerSize(I, DL, *TLI, + BB.getParent()))); }); // If all of the allocas were clobbered by the call then we're not going @@ -880,7 +887,7 @@ static bool handleEndBlock(BasicBlock &BB, AliasAnalysis *AA, // Remove any allocas from the DeadPointer set that are loaded, as this // makes any stores above the access live. - removeAccessedObjects(LoadedLoc, DeadStackObjects, DL, AA, TLI); + removeAccessedObjects(LoadedLoc, DeadStackObjects, DL, AA, TLI, BB.getParent()); // If all of the allocas were clobbered by the access then we're not going // to find anything else to process. @@ -1176,7 +1183,8 @@ static bool eliminateDeadStores(BasicBlock &BB, AliasAnalysis *AA, !isPossibleSelfRead(Inst, Loc, DepWrite, *TLI, *AA)) { int64_t InstWriteOffset, DepWriteOffset; OverwriteResult OR = isOverwrite(Loc, DepLoc, DL, *TLI, DepWriteOffset, - InstWriteOffset, DepWrite, IOL, *AA); + InstWriteOffset, DepWrite, IOL, *AA, + BB.getParent()); if (OR == OW_Complete) { LLVM_DEBUG(dbgs() << "DSE: Remove Dead Store:\n DEAD: " << *DepWrite << "\n KILLER: " << *Inst << '\n'); diff --git a/llvm/lib/Transforms/Scalar/SCCP.cpp b/llvm/lib/Transforms/Scalar/SCCP.cpp index 81a429fe618..6f3d798f704 100644 --- a/llvm/lib/Transforms/Scalar/SCCP.cpp +++ b/llvm/lib/Transforms/Scalar/SCCP.cpp @@ -1133,8 +1133,12 @@ void SCCPSolver::visitLoadInst(LoadInst &I) { Constant *Ptr = PtrVal.getConstant(); // load null is undefined. - if (isa<ConstantPointerNull>(Ptr) && I.getPointerAddressSpace() == 0) - return; + if (isa<ConstantPointerNull>(Ptr)) { + if (NullPointerIsDefined(I.getFunction(), I.getPointerAddressSpace())) + return (void)markOverdefined(IV, &I); + else + return; + } // Transform load (constant global) into the value loaded. if (auto *GV = dyn_cast<GlobalVariable>(Ptr)) { diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp index 4081e0465da..ff5f77c6098 100644 --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -2050,7 +2050,9 @@ static bool markAliveBlocks(Function &F, if (auto *CI = dyn_cast<CallInst>(&I)) { Value *Callee = CI->getCalledValue(); - if (isa<ConstantPointerNull>(Callee) || isa<UndefValue>(Callee)) { + if ((isa<ConstantPointerNull>(Callee) && + !NullPointerIsDefined(CI->getFunction())) || + isa<UndefValue>(Callee)) { changeToUnreachable(CI, /*UseLLVMTrap=*/false, false, DDT); Changed = true; break; @@ -2079,7 +2081,8 @@ static bool markAliveBlocks(Function &F, if (isa<UndefValue>(Ptr) || (isa<ConstantPointerNull>(Ptr) && - SI->getPointerAddressSpace() == 0)) { + !NullPointerIsDefined(SI->getFunction(), + SI->getPointerAddressSpace()))) { changeToUnreachable(SI, true, false, DDT); Changed = true; break; @@ -2091,7 +2094,9 @@ static bool markAliveBlocks(Function &F, if (auto *II = dyn_cast<InvokeInst>(Terminator)) { // Turn invokes that call 'nounwind' functions into ordinary calls. Value *Callee = II->getCalledValue(); - if (isa<ConstantPointerNull>(Callee) || isa<UndefValue>(Callee)) { + if ((isa<ConstantPointerNull>(Callee) && + !NullPointerIsDefined(BB->getParent())) || + isa<UndefValue>(Callee)) { changeToUnreachable(II, true, false, DDT); Changed = true; } else if (II->doesNotThrow() && canSimplifyInvokeNoUnwind(&F)) { diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index 083e83fdb7d..c87b5c16ffc 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -5950,17 +5950,20 @@ static bool passingValueIsAlwaysUndefined(Value *V, Instruction *I) { // Load from null is undefined. if (LoadInst *LI = dyn_cast<LoadInst>(Use)) if (!LI->isVolatile()) - return LI->getPointerAddressSpace() == 0; + return !NullPointerIsDefined(LI->getFunction(), + LI->getPointerAddressSpace()); // Store to null is undefined. if (StoreInst *SI = dyn_cast<StoreInst>(Use)) if (!SI->isVolatile()) - return SI->getPointerAddressSpace() == 0 && + return (!NullPointerIsDefined(SI->getFunction(), + SI->getPointerAddressSpace())) && SI->getPointerOperand() == I; // A call to null is undefined. if (auto CS = CallSite(Use)) - return CS.getCalledValue() == I; + return !NullPointerIsDefined(CS->getFunction()) && + CS.getCalledValue() == I; } return false; } |

