Index: lib/Analysis/CaptureTracking.cpp =================================================================== --- lib/Analysis/CaptureTracking.cpp +++ lib/Analysis/CaptureTracking.cpp @@ -331,14 +331,28 @@ AddUses(I); break; case Instruction::ICmp: { - // Don't count comparisons of a no-alias return value against null as - // captures. This allows us to ignore comparisons of malloc results - // with null, for example. if (ConstantPointerNull *CPN = - dyn_cast(I->getOperand(1))) + dyn_cast(I->getOperand(1))) { + // Don't count comparisons of a no-alias return value against null as + // captures. This allows us to ignore comparisons of malloc results + // with null, for example. if (CPN->getType()->getAddressSpace() == 0) if (isNoAliasCall(V->stripPointerCasts())) break; + // A getelementptr inbounds is either null or an in-bounds GEP, which + // means that there is no way to let a pointer escape using clever GEP + // hacking. + if (GetElementPtrInst *GEP = + dyn_cast(I->getOperand(0))) + if (GEP->isInBounds()) + break; + // Comparing a dereferenceable_or_null argument against null cannot lead + // to pointer escapes, because if it is not null it must be a valid + // (in-bounds) pointer. + if (Argument *A = dyn_cast(I->getOperand(0))) + if (A->getDereferenceableOrNullBytes()) + break; + } // Comparison against value stored in global variable. Given the pointer // does not escape, its value cannot be guessed and stored separately in a // global variable. Index: test/Transforms/FunctionAttrs/nocapture.ll =================================================================== --- test/Transforms/FunctionAttrs/nocapture.ll +++ test/Transforms/FunctionAttrs/nocapture.ll @@ -253,5 +253,28 @@ ret void } +; CHECK: define i1 @captureICmp(i32* readnone %x) +define i1 @captureICmp(i32* %x) { +entry: + %0 = getelementptr i32, i32* %x, i32 5 + %1 = icmp eq i32* %0, null + ret i1 %1 +} + +; CHECK: define i1 @nocaptureInboundsGEPICmp(i32* nocapture readnone %x) +define i1 @nocaptureInboundsGEPICmp(i32* %x) { +entry: + %0 = getelementptr inbounds i32, i32* %x, i32 5 + %1 = icmp eq i32* %0, null + ret i1 %1 +} + +; CHECK: define i1 @nocaptureDereferenceableOrNullICmp(i32* nocapture readnone dereferenceable_or_null(4) %x) +define i1 @nocaptureDereferenceableOrNullICmp(i32* dereferenceable_or_null(4) %x) { +entry: + %0 = icmp eq i32* %x, null + ret i1 %0 +} + declare i8* @llvm.launder.invariant.group.p0i8(i8*) declare i8* @llvm.strip.invariant.group.p0i8(i8*)