Skip to content

Commit

Permalink
[Analysis] isSafeToLoadUnconditionally(): lifetime intrinsics can…
Browse files Browse the repository at this point in the history
… be ignored

In practice this means that we can speculate more loads in SROA.
This e.g. comes up in https://godbolt.org/z/G8716s6sj,
although we are missing second half of the puzzle to optimize that.
  • Loading branch information
LebedevRI committed Nov 17, 2022
1 parent 6a3561d commit be1f994
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 7 deletions.
25 changes: 25 additions & 0 deletions llvm/include/llvm/IR/IntrinsicInst.h
Expand Up @@ -123,6 +123,31 @@ class IntrinsicInst : public CallInst {
}
};

/// Check if \p ID corresponds to a lifetime intrinsic.
static inline bool isLifetimeIntrinsic(Intrinsic::ID ID) {
switch (ID) {
case Intrinsic::lifetime_start:
case Intrinsic::lifetime_end:
return true;
default:
return false;
}
}

/// This is the common base class for lifetime intrinsics.
class LifetimeIntrinsic : public IntrinsicInst {
public:
/// \name Casting methods
/// @{
static bool classof(const IntrinsicInst *I) {
return isLifetimeIntrinsic(I->getIntrinsicID());
}
static bool classof(const Value *V) {
return isa<IntrinsicInst>(V) && classof(cast<IntrinsicInst>(V));
}
/// @}
};

/// Check if \p ID corresponds to a debug info intrinsic.
static inline bool isDbgInfoIntrinsic(Intrinsic::ID ID) {
switch (ID) {
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Analysis/Loads.cpp
Expand Up @@ -359,7 +359,7 @@ bool llvm::isSafeToLoadUnconditionally(Value *V, Align Alignment, APInt &Size,
// If we see a free or a call which may write to memory (i.e. which might do
// a free) the pointer could be marked invalid.
if (isa<CallInst>(BBI) && BBI->mayWriteToMemory() &&
!isa<DbgInfoIntrinsic>(BBI))
!isa<LifetimeIntrinsic>(BBI) && !isa<DbgInfoIntrinsic>(BBI))
return false;

Value *AccessedPtr;
Expand Down
9 changes: 3 additions & 6 deletions llvm/test/Transforms/SROA/select-load.ll
Expand Up @@ -62,16 +62,13 @@ declare void @foo_i32(ptr)
; Lifetime intrinsics should not prevent dereferenceability inferrence.
define i32 @interfering_lifetime(ptr %data, i64 %indvars.iv) {
; CHECK-LABEL: @interfering_lifetime(
; CHECK-NEXT: [[MIN:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[DATA:%.*]], i64 [[INDVARS_IV:%.*]]
; CHECK-NEXT: [[I1:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[MIN]])
; CHECK-NEXT: store i32 0, ptr [[MIN]], align 4
; CHECK-NEXT: [[CMP_I_I:%.*]] = icmp slt i32 [[I1]], 0
; CHECK-NEXT: [[I2:%.*]] = tail call i32 @llvm.smax.i32(i32 [[I1]], i32 0)
; CHECK-NEXT: [[__B___A_I_I:%.*]] = select i1 [[CMP_I_I]], ptr [[MIN]], ptr [[ARRAYIDX]]
; CHECK-NEXT: [[I3:%.*]] = load i32, ptr [[__B___A_I_I]], align 4
; CHECK-NEXT: ret i32 [[I3]]
; CHECK-NEXT: [[I3_SROA_SPECULATE_LOAD_FALSE:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
; CHECK-NEXT: [[I3_SROA_SPECULATED:%.*]] = select i1 [[CMP_I_I]], i32 0, i32 [[I3_SROA_SPECULATE_LOAD_FALSE]]
; CHECK-NEXT: ret i32 [[I3_SROA_SPECULATED]]
;
%min = alloca i32, align 4
%arrayidx = getelementptr inbounds i32, ptr %data, i64 %indvars.iv
Expand Down

0 comments on commit be1f994

Please sign in to comment.