1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 20:51:52 +01:00

[SROA] Teach promote to register about droppable instructions

This is the second of two patches to address PR46753. We basically allow
SROA to promote allocas that are used in doppable instructions, for
now that means `llvm.assume`. The (transitive) uses are replaced by
`undef` in the droppable instructions.

See also D83976.

Reviewed By: Tyker

Differential Revision: https://reviews.llvm.org/D83978
This commit is contained in:
Johannes Doerfert 2020-07-24 14:06:27 -05:00
parent ac3ceab3a2
commit b8680170b1
2 changed files with 104 additions and 5 deletions

View File

@ -920,6 +920,9 @@ private:
// 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 @@ static bool isVectorPromotionViableForSlice(Partition &P, const Slice &S,
if (!S.isSplittable())
return false; // Skip any unsplittable intrinsics.
} else if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(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 @@ static bool isIntegerWideningViableForSlice(const Slice &S,
if (!S.isSplittable())
return false; // Skip any unsplittable intrinsics.
} else if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(U->getUser())) {
if (!II->isLifetimeStartOrEnd())
if (!II->isLifetimeStartOrEnd() && !II->isDroppable())
return false;
} else {
return false;
@ -2778,7 +2781,7 @@ private:
Type *AllocaTy = NewAI.getAllocatedType();
Type *ScalarTy = AllocaTy->getScalarType();
const bool CanContinue = [&]() {
if (VecTy || IntTy)
return true;
@ -3074,13 +3077,21 @@ private:
}
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.

View File

@ -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
}