diff --git a/llvm/lib/Transforms/Scalar/SROA.cpp b/llvm/lib/Transforms/Scalar/SROA.cpp --- a/llvm/lib/Transforms/Scalar/SROA.cpp +++ b/llvm/lib/Transforms/Scalar/SROA.cpp @@ -920,6 +920,9 @@ // FIXME: What about debug intrinsics? This matches old behavior, but // doesn't make sense. void visitIntrinsicInst(IntrinsicInst &II) { + if (II.isDroppable()) + return; + if (!IsOffsetKnown) return PI.setAborted(&II); @@ -1825,7 +1828,7 @@ if (!S.isSplittable()) return false; // Skip any unsplittable intrinsics. } else if (IntrinsicInst *II = dyn_cast(U->getUser())) { - if (!II->isLifetimeStartOrEnd()) + if (!II->isLifetimeStartOrEnd() && !II->isDroppable()) return false; } else if (U->get()->getType()->getPointerElementType()->isStructTy()) { // Disable vector promotion when there are loads or stores of an FCA. @@ -2058,7 +2061,7 @@ if (!S.isSplittable()) return false; // Skip any unsplittable intrinsics. } else if (IntrinsicInst *II = dyn_cast(U->getUser())) { - if (!II->isLifetimeStartOrEnd()) + if (!II->isLifetimeStartOrEnd() && !II->isDroppable()) return false; } else { return false; @@ -2778,7 +2781,7 @@ Type *AllocaTy = NewAI.getAllocatedType(); Type *ScalarTy = AllocaTy->getScalarType(); - + const bool CanContinue = [&]() { if (VecTy || IntTy) return true; @@ -3074,13 +3077,21 @@ } bool visitIntrinsicInst(IntrinsicInst &II) { - assert(II.isLifetimeStartOrEnd()); + assert((II.isLifetimeStartOrEnd() || II.isDroppable()) && + "Unexpected intrinsic!"); LLVM_DEBUG(dbgs() << " original: " << II << "\n"); - assert(II.getArgOperand(1) == OldPtr); // Record this instruction for deletion. Pass.DeadInsts.insert(&II); + if (II.isDroppable()) { + assert(II.getIntrinsicID() == Intrinsic::assume && "Expected assume"); + // TODO For now we forget assumed information, this can be improved. + OldPtr->dropDroppableUsesByUser(II); + return true; + } + + assert(II.getArgOperand(1) == OldPtr); // Lifetime intrinsics are only promotable if they cover the whole alloca. // Therefore, we drop lifetime intrinsics which don't cover the whole // alloca. diff --git a/llvm/test/Transforms/SROA/ignore-droppable.ll b/llvm/test/Transforms/SROA/ignore-droppable.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/SROA/ignore-droppable.ll @@ -0,0 +1,88 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -sroa -S -o - < %s | FileCheck %s +; RUN: opt -passes=sroa -S -o - < %s | FileCheck %s + +declare void @llvm.assume(i1) +declare void @llvm.lifetime.start.p0i8(i64 %size, i8* nocapture %ptr) +declare void @llvm.lifetime.end.p0i8(i64 %size, i8* nocapture %ptr) + +define void @positive_assume_uses(i32* %arg) { +; CHECK-LABEL: @positive_assume_uses( +; CHECK-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(i32* [[ARG:%.*]]), "ignore"(i32* undef, i64 2) ] +; CHECK-NEXT: call void @llvm.assume(i1 true) [ "ignore"(i32* undef, i64 8), "nonnull"(i32* [[ARG]]) ] +; CHECK-NEXT: ret void +; + %A = alloca i32 + call void @llvm.assume(i1 true) ["nonnull"(i32* %arg), "align"(i32* %A, i64 2)] + store i32 1, i32* %A + call void @llvm.assume(i1 true) ["align"(i32* %A, i64 8), "nonnull"(i32* %arg)] + ret void +} + +define void @negative_assume_condition_use() { +; CHECK-LABEL: @negative_assume_condition_use( +; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 +; CHECK-NEXT: [[B:%.*]] = bitcast i32* [[A]] to i8* +; CHECK-NEXT: [[CND:%.*]] = icmp eq i8* [[B]], null +; CHECK-NEXT: call void @llvm.assume(i1 [[CND]]) +; CHECK-NEXT: store i32 1, i32* [[A]], align 4 +; CHECK-NEXT: ret void +; + %A = alloca i32 + %B = bitcast i32* %A to i8* + %cnd = icmp eq i8* %B, null + call void @llvm.assume(i1 %cnd) + store i32 1, i32* %A + ret void +} + +define void @positive_multiple_assume_uses() { +; CHECK-LABEL: @positive_multiple_assume_uses( +; CHECK-NEXT: [[A:%.*]] = alloca { i8, i16 }, align 8 +; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"({ i8, i16 }* [[A]], i64 8), "align"({ i8, i16 }* [[A]], i64 16) ] +; CHECK-NEXT: call void @llvm.assume(i1 true) [ "nonnull"({ i8, i16 }* [[A]]), "align"({ i8, i16 }* [[A]], i64 2) ] +; CHECK-NEXT: ret void +; + %A = alloca {i8, i16} + call void @llvm.assume(i1 true) ["align"({i8, i16}* %A, i64 8), "align"({i8, i16}* %A, i64 16)] + store {i8, i16} zeroinitializer, {i8, i16}* %A + call void @llvm.assume(i1 true) ["nonnull"({i8, i16}* %A), "align"({i8, i16}* %A, i64 2)] + ret void +} + +define void @positive_gep_assume_uses() { +; CHECK-LABEL: @positive_gep_assume_uses( +; CHECK-NEXT: [[A:%.*]] = alloca { i8, i16 }, align 8 +; CHECK-NEXT: [[B:%.*]] = getelementptr { i8, i16 }, { i8, i16 }* [[A]], i32 0, i32 0 +; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(i8* [[B]], i64 8), "align"(i8* [[B]], i64 16) ] +; CHECK-NEXT: call void @llvm.assume(i1 true) [ "nonnull"(i8* [[B]]), "align"(i8* [[B]], i64 2) ] +; CHECK-NEXT: ret void +; + %A = alloca {i8, i16} + %B = getelementptr {i8, i16}, {i8, i16}* %A, i32 0, i32 0 + call void @llvm.lifetime.start.p0i8(i64 2, i8* %B) + call void @llvm.assume(i1 true) ["align"(i8* %B, i64 8), "align"(i8* %B, i64 16)] + store {i8, i16} zeroinitializer, {i8, i16}* %A + call void @llvm.lifetime.end.p0i8(i64 2, i8* %B) + call void @llvm.assume(i1 true) ["nonnull"(i8* %B), "align"(i8* %B, i64 2)] + ret void +} + +define void @positive_mixed_assume_uses() { +; CHECK-LABEL: @positive_mixed_assume_uses( +; CHECK-NEXT: call void @llvm.assume(i1 true) [ "ignore"(i8* undef), "ignore"(i8* undef, i64 8), "ignore"(i8* undef, i64 16) ] +; CHECK-NEXT: call void @llvm.assume(i1 true) [ "ignore"(i8* undef), "ignore"(i8* undef, i64 2), "ignore"(i8* undef) ] +; CHECK-NEXT: call void @llvm.assume(i1 true) [ "ignore"(i32* undef), "ignore"(i32* undef, i64 2), "ignore"(i8* undef) ] +; CHECK-NEXT: ret void +; + %A = alloca i8 + %B = getelementptr i8, i8* %A, i32 0 + %C = bitcast i8* %A to i32* + call void @llvm.lifetime.start.p0i8(i64 2, i8* %B) + call void @llvm.assume(i1 true) ["nonnull"(i8* %B), "align"(i8* %A, i64 8), "align"(i8* %B, i64 16)] + store i8 1, i8* %A + call void @llvm.lifetime.end.p0i8(i64 2, i8* %B) + call void @llvm.assume(i1 true) ["nonnull"(i8* %B), "align"(i8* %A, i64 2), "nonnull"(i8* %A)] + call void @llvm.assume(i1 true) ["nonnull"(i32* %C), "align"(i32* %C, i64 2), "nonnull"(i8* %A)] + ret void +}