Index: lib/Analysis/CaptureTracking.cpp =================================================================== --- lib/Analysis/CaptureTracking.cpp +++ lib/Analysis/CaptureTracking.cpp @@ -331,14 +331,29 @@ 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; + auto *O = I->getOperand(0)->stripPointerCasts(); + // 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(O)) + 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(O)) + 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,26 @@ ret void } +; CHECK: define i1 @captureICmp(i32* readnone %x) +define i1 @captureICmp(i32* %x) { + %1 = icmp eq i32* %x, null + ret i1 %1 +} + +; CHECK: define i1 @nocaptureInboundsGEPICmp(i32* nocapture readnone %x) +define i1 @nocaptureInboundsGEPICmp(i32* %x) { + %1 = getelementptr inbounds i32, i32* %x, i32 5 + %2 = bitcast i32* %1 to i8* + %3 = icmp eq i8* %2, null + ret i1 %3 +} + +; CHECK: define i1 @nocaptureDereferenceableOrNullICmp(i32* nocapture readnone dereferenceable_or_null(4) %x) +define i1 @nocaptureDereferenceableOrNullICmp(i32* dereferenceable_or_null(4) %x) { + %1 = bitcast i32* %x to i8* + %2 = icmp eq i8* %1, null + ret i1 %2 +} + declare i8* @llvm.launder.invariant.group.p0i8(i8*) declare i8* @llvm.strip.invariant.group.p0i8(i8*)