Skip to content

Commit 6dd18a6

Browse files
committed
Fix address_is_null inference
1 parent 69d729b commit 6dd18a6

File tree

5 files changed

+68
-12
lines changed

5 files changed

+68
-12
lines changed

llvm/include/llvm/Analysis/CaptureTracking.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,11 @@ namespace llvm {
130130
/// which components may be captured by following uses of the user of \p U.
131131
/// The \p IsDereferenceableOrNull callback is used to rule out capturing for
132132
/// certain comparisons.
133+
///
134+
/// \p Base is the starting value of the capture analysis, which is
135+
/// relevant for address_is_null captures.
133136
CaptureInfo
134-
DetermineUseCaptureKind(const Use &U,
137+
DetermineUseCaptureKind(const Use &U, const Value *Base,
135138
llvm::function_ref<bool(Value *, const DataLayout &)>
136139
IsDereferenceableOrNull);
137140

llvm/lib/Analysis/CaptureTracking.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ Instruction *llvm::FindEarliestCapture(const Value *V, Function &F,
280280
}
281281

282282
CaptureInfo llvm::DetermineUseCaptureKind(
283-
const Use &U,
283+
const Use &U, const Value *Base,
284284
function_ref<bool(Value *, const DataLayout &)> IsDereferenceableOrNull) {
285285
Instruction *I = dyn_cast<Instruction>(U.getUser());
286286

@@ -378,14 +378,15 @@ CaptureInfo llvm::DetermineUseCaptureKind(
378378
case Instruction::ICmp: {
379379
unsigned Idx = U.getOperandNo();
380380
unsigned OtherIdx = 1 - Idx;
381-
if (auto *CPN = dyn_cast<ConstantPointerNull>(I->getOperand(OtherIdx))) {
381+
if (isa<ConstantPointerNull>(I->getOperand(OtherIdx)) &&
382+
cast<ICmpInst>(I)->isEquality()) {
382383
// TODO(captures): Remove these special cases once we make use of
383384
// captures(address_is_null).
384385

385386
// Don't count comparisons of a no-alias return value against null as
386387
// captures. This allows us to ignore comparisons of malloc results
387388
// with null, for example.
388-
if (CPN->getType()->getAddressSpace() == 0)
389+
if (U->getType()->getPointerAddressSpace() == 0)
389390
if (isNoAliasCall(U.get()->stripPointerCasts()))
390391
return CaptureInfo::none();
391392
if (!I->getFunction()->nullPointerIsDefined()) {
@@ -397,7 +398,16 @@ CaptureInfo llvm::DetermineUseCaptureKind(
397398
if (IsDereferenceableOrNull && IsDereferenceableOrNull(O, DL))
398399
return CaptureInfo::none();
399400
}
400-
return CaptureInfo::otherOnly(CaptureComponents::AddressIsNull);
401+
402+
// Check whether this is a comparison of the base pointer against
403+
// null. We can also strip inbounds GEPs, as inbounds preserves
404+
// the null-ness of the pointer.
405+
Value *Stripped = U.get();
406+
if (!NullPointerIsDefined(I->getFunction(),
407+
U->getType()->getPointerAddressSpace()))
408+
Stripped = Stripped->stripInBoundsOffsets();
409+
if (Stripped == Base)
410+
return CaptureInfo::otherOnly(CaptureComponents::AddressIsNull);
401411
}
402412

403413
// Otherwise, be conservative. There are crazy ways to capture pointers
@@ -445,7 +455,7 @@ void llvm::PointerMayBeCaptured(const Value *V, CaptureTracker *Tracker,
445455
};
446456
while (!Worklist.empty()) {
447457
const Use *U = Worklist.pop_back_val();
448-
CaptureInfo CI = DetermineUseCaptureKind(*U, IsDereferenceableOrNull);
458+
CaptureInfo CI = DetermineUseCaptureKind(*U, V, IsDereferenceableOrNull);
449459
if (capturesNothing(CI))
450460
continue;
451461
CaptureComponents OtherCC = CI.getOtherComponents();

llvm/lib/Transforms/IPO/AttributorAttributes.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3971,7 +3971,8 @@ struct AANoAliasCallSiteArgument final : AANoAliasImpl {
39713971
// is CGSCC runs. For those we would need to "allow" AANoCapture for
39723972
// a value in the module slice.
39733973
// TODO(captures): Make this more precise.
3974-
CaptureInfo CI = DetermineUseCaptureKind(U, IsDereferenceableOrNull);
3974+
CaptureInfo CI =
3975+
DetermineUseCaptureKind(U, /*Base=*/nullptr, IsDereferenceableOrNull);
39753976
if (capturesNothing(CI))
39763977
return true;
39773978
if (CI.isRetOnly()) {
@@ -6018,7 +6019,8 @@ ChangeStatus AANoCaptureImpl::updateImpl(Attributor &A) {
60186019

60196020
auto UseCheck = [&](const Use &U, bool &Follow) -> bool {
60206021
// TODO(captures): Make this more precise.
6021-
CaptureInfo CI = DetermineUseCaptureKind(U, IsDereferenceableOrNull);
6022+
CaptureInfo CI =
6023+
DetermineUseCaptureKind(U, /*Base=*/nullptr, IsDereferenceableOrNull);
60226024
if (capturesNothing(CI))
60236025
return true;
60246026
if (CI.isRetOnly()) {
@@ -12149,7 +12151,7 @@ struct AAGlobalValueInfoFloating : public AAGlobalValueInfo {
1214912151
auto UsePred = [&](const Use &U, bool &Follow) -> bool {
1215012152
Uses.insert(&U);
1215112153
// TODO(captures): Make this more precise.
12152-
CaptureInfo CI = DetermineUseCaptureKind(U, nullptr);
12154+
CaptureInfo CI = DetermineUseCaptureKind(U, /*Base=*/nullptr, nullptr);
1215312155
if (capturesAnything(CI) && CI.isRetOnly()) {
1215412156
Follow = true;
1215512157
return true;

llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1550,7 +1550,8 @@ bool MemCpyOptPass::performStackMoveOptzn(Instruction *Load, Instruction *Store,
15501550
}
15511551
if (!Visited.insert(&U).second)
15521552
continue;
1553-
CaptureInfo CI = DetermineUseCaptureKind(U, IsDereferenceableOrNull);
1553+
CaptureInfo CI =
1554+
DetermineUseCaptureKind(U, AI, IsDereferenceableOrNull);
15541555
// TODO(captures): Make this more precise.
15551556
if (capturesAnything(CI)) {
15561557
if (CI.isRetOnly()) {

llvm/test/Transforms/FunctionAttrs/nocapture.ll

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,46 @@ define i1 @nocaptureInboundsGEPICmpRev(ptr %x) {
811811
ret i1 %2
812812
}
813813

814+
define i1 @notInboundsGEPICmp(ptr %x) {
815+
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
816+
; FNATTRS-LABEL: define i1 @notInboundsGEPICmp
817+
; FNATTRS-SAME: (ptr readnone captures(address) [[X:%.*]]) #[[ATTR0]] {
818+
; FNATTRS-NEXT: [[TMP1:%.*]] = getelementptr i32, ptr [[X]], i32 5
819+
; FNATTRS-NEXT: [[TMP2:%.*]] = icmp eq ptr [[TMP1]], null
820+
; FNATTRS-NEXT: ret i1 [[TMP2]]
821+
;
822+
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
823+
; ATTRIBUTOR-LABEL: define i1 @notInboundsGEPICmp
824+
; ATTRIBUTOR-SAME: (ptr nofree readnone [[X:%.*]]) #[[ATTR0]] {
825+
; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = getelementptr i32, ptr [[X]], i32 5
826+
; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = icmp eq ptr [[TMP1]], null
827+
; ATTRIBUTOR-NEXT: ret i1 [[TMP2]]
828+
;
829+
%1 = getelementptr i32, ptr %x, i32 5
830+
%2 = icmp eq ptr %1, null
831+
ret i1 %2
832+
}
833+
834+
define i1 @inboundsGEPICmpNullPointerDefined(ptr %x) null_pointer_is_valid {
835+
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind null_pointer_is_valid willreturn memory(none)
836+
; FNATTRS-LABEL: define i1 @inboundsGEPICmpNullPointerDefined
837+
; FNATTRS-SAME: (ptr readnone captures(address) [[X:%.*]]) #[[ATTR16:[0-9]+]] {
838+
; FNATTRS-NEXT: [[TMP1:%.*]] = getelementptr i32, ptr [[X]], i32 5
839+
; FNATTRS-NEXT: [[TMP2:%.*]] = icmp eq ptr [[TMP1]], null
840+
; FNATTRS-NEXT: ret i1 [[TMP2]]
841+
;
842+
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind null_pointer_is_valid willreturn memory(none)
843+
; ATTRIBUTOR-LABEL: define i1 @inboundsGEPICmpNullPointerDefined
844+
; ATTRIBUTOR-SAME: (ptr nofree readnone [[X:%.*]]) #[[ATTR12:[0-9]+]] {
845+
; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = getelementptr i32, ptr [[X]], i32 5
846+
; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = icmp eq ptr [[TMP1]], null
847+
; ATTRIBUTOR-NEXT: ret i1 [[TMP2]]
848+
;
849+
%1 = getelementptr i32, ptr %x, i32 5
850+
%2 = icmp eq ptr %1, null
851+
ret i1 %2
852+
}
853+
814854
define i1 @nocaptureDereferenceableOrNullICmp(ptr dereferenceable_or_null(4) %x) {
815855
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
816856
; FNATTRS-LABEL: define noundef i1 @nocaptureDereferenceableOrNullICmp
@@ -831,13 +871,13 @@ define i1 @nocaptureDereferenceableOrNullICmp(ptr dereferenceable_or_null(4) %x)
831871
define i1 @captureDereferenceableOrNullICmp(ptr dereferenceable_or_null(4) %x) null_pointer_is_valid {
832872
; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind null_pointer_is_valid willreturn memory(none)
833873
; FNATTRS-LABEL: define noundef i1 @captureDereferenceableOrNullICmp
834-
; FNATTRS-SAME: (ptr readnone captures(address_is_null) dereferenceable_or_null(4) [[X:%.*]]) #[[ATTR16:[0-9]+]] {
874+
; FNATTRS-SAME: (ptr readnone captures(address_is_null) dereferenceable_or_null(4) [[X:%.*]]) #[[ATTR16]] {
835875
; FNATTRS-NEXT: [[TMP1:%.*]] = icmp eq ptr [[X]], null
836876
; FNATTRS-NEXT: ret i1 [[TMP1]]
837877
;
838878
; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind null_pointer_is_valid willreturn memory(none)
839879
; ATTRIBUTOR-LABEL: define i1 @captureDereferenceableOrNullICmp
840-
; ATTRIBUTOR-SAME: (ptr nofree readnone dereferenceable_or_null(4) [[X:%.*]]) #[[ATTR12:[0-9]+]] {
880+
; ATTRIBUTOR-SAME: (ptr nofree readnone dereferenceable_or_null(4) [[X:%.*]]) #[[ATTR12]] {
841881
; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = icmp eq ptr [[X]], null
842882
; ATTRIBUTOR-NEXT: ret i1 [[TMP1]]
843883
;

0 commit comments

Comments
 (0)