Skip to content

Commit 59d3bc0

Browse files
committed
Remove redundant assumes
1 parent 4233a15 commit 59d3bc0

File tree

4 files changed

+173
-31
lines changed

4 files changed

+173
-31
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp

Lines changed: 94 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3199,12 +3199,13 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
31993199
// TODO: apply range metadata for range check patterns?
32003200
}
32013201

3202-
// Separate storage assumptions apply to the underlying allocations, not any
3203-
// particular pointer within them. When evaluating the hints for AA purposes
3204-
// we getUnderlyingObject them; by precomputing the answers here we can
3205-
// avoid having to do so repeatedly there.
32063202
for (unsigned Idx = 0; Idx < II->getNumOperandBundles(); Idx++) {
32073203
OperandBundleUse OBU = II->getOperandBundleAt(Idx);
3204+
3205+
// Separate storage assumptions apply to the underlying allocations, not
3206+
// any particular pointer within them. When evaluating the hints for AA
3207+
// purposes we getUnderlyingObject them; by precomputing the answers here
3208+
// we can avoid having to do so repeatedly there.
32083209
if (OBU.getTagName() == "separate_storage") {
32093210
assert(OBU.Inputs.size() == 2);
32103211
auto MaybeSimplifyHint = [&](const Use &U) {
@@ -3218,6 +3219,95 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
32183219
MaybeSimplifyHint(OBU.Inputs[0]);
32193220
MaybeSimplifyHint(OBU.Inputs[1]);
32203221
}
3222+
3223+
// Try to fold alignment assumption into a load's !align metadata, if the
3224+
// assumption is valid in the load's context and remove redundant ones.
3225+
if (OBU.getTagName() == "align" && OBU.Inputs.size() == 2) {
3226+
RetainedKnowledge RK = getKnowledgeFromBundle(
3227+
*cast<AssumeInst>(II), II->bundle_op_info_begin()[Idx]);
3228+
if (!RK || RK.AttrKind != Attribute::Alignment ||
3229+
!isPowerOf2_64(RK.ArgValue))
3230+
continue;
3231+
auto *C = dyn_cast<Constant>(RK.WasOn);
3232+
if (C && C->isNullValue()) {
3233+
} else {
3234+
Value *UO = getUnderlyingObject(RK.WasOn);
3235+
3236+
bool CanUseAlign = false;
3237+
SetVector<const Instruction *> WorkList;
3238+
for (const User *U : RK.WasOn->users())
3239+
if (auto *I = dyn_cast<Instruction>(U))
3240+
WorkList.insert(I);
3241+
3242+
for (unsigned I = 0; I != WorkList.size(); ++I) {
3243+
auto *Curr = WorkList[I];
3244+
if (!DT.dominates(II, Curr))
3245+
continue;
3246+
if (auto *LI = dyn_cast<LoadInst>(Curr)) {
3247+
if (LI->getAlign().value() < RK.ArgValue) {
3248+
CanUseAlign = true;
3249+
break;
3250+
}
3251+
continue;
3252+
}
3253+
if (auto *SI = dyn_cast<StoreInst>(Curr)) {
3254+
auto *PtrOpI = dyn_cast<Instruction>(SI->getPointerOperand());
3255+
if ((SI->getPointerOperand() == RK.WasOn || (PtrOpI && WorkList.contains(PtrOpI))) &&
3256+
SI->getAlign().value() < RK.ArgValue) {
3257+
CanUseAlign = true;
3258+
break;
3259+
}
3260+
continue;
3261+
}
3262+
if (auto *II = dyn_cast<IntrinsicInst>(Curr)) {
3263+
for (const auto &[Idx, Arg] : enumerate(II->args())) {
3264+
if (Arg != RK.WasOn)
3265+
continue;
3266+
if (II->getParamAlign(Idx) >= RK.ArgValue)
3267+
continue;
3268+
CanUseAlign = true;
3269+
break;
3270+
}
3271+
if (CanUseAlign)
3272+
break;
3273+
continue;
3274+
}
3275+
if (isa<ReturnInst, CallBase>(Curr)) {
3276+
CanUseAlign = true;
3277+
break;
3278+
}
3279+
if (isa<ICmpInst>(Curr) &&
3280+
!isa<Constant>(cast<Instruction>(Curr)->getOperand(0)) &&
3281+
!isa<Constant>(cast<Instruction>(Curr)->getOperand(1))) {
3282+
CanUseAlign = true;
3283+
break;
3284+
}
3285+
if (!Curr->getType()->isPointerTy())
3286+
continue;
3287+
3288+
if (WorkList.size() > 16) {
3289+
CanUseAlign = true;
3290+
break;
3291+
}
3292+
for (const User *U : Curr->users())
3293+
WorkList.insert(cast<Instruction>(U));
3294+
}
3295+
if (CanUseAlign && (!UO || isa<Argument>(UO)))
3296+
continue;
3297+
// Try to get the instruction before the assumption to use as
3298+
// context.
3299+
Instruction *CtxI = nullptr;
3300+
if (CtxI && II->getParent()->begin() != II->getIterator())
3301+
CtxI = II->getPrevNode();
3302+
3303+
auto Known = computeKnownBits(RK.WasOn, 1, CtxI);
3304+
unsigned KnownAlign = 1 << Known.countMinTrailingZeros();
3305+
if (CanUseAlign && KnownAlign < RK.ArgValue)
3306+
continue;
3307+
}
3308+
auto *New = CallBase::removeOperandBundle(II, OBU.getTagID());
3309+
return New;
3310+
}
32213311
}
32223312

32233313
// Convert nonnull assume like:

llvm/test/Transforms/InstCombine/assume-align.ll

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals smart
2-
; RUN: opt -S -passes=instcombine,simplifycfg < %s 2>&1 | FileCheck %s
2+
; RUN: opt -S -passes='instcombine<no-verify-fixpoint>,simplifycfg' < %s 2>&1 | FileCheck %s
33

44
declare void @llvm.assume(i1 noundef)
55

@@ -87,7 +87,6 @@ if.end: ; preds = %if.else, %if.then
8787
define void @f3(i64 %a, ptr %b) {
8888
; CHECK-LABEL: @f3(
8989
; CHECK-NEXT: [[C:%.*]] = ptrtoint ptr [[B:%.*]] to i64
90-
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[B]], i64 4294967296) ]
9190
; CHECK-NEXT: [[D:%.*]] = add i64 [[A:%.*]], [[C]]
9291
; CHECK-NEXT: call void @g(i64 [[D]])
9392
; CHECK-NEXT: ret void
@@ -135,6 +134,17 @@ define ptr @fold_assume_align_pow2_of_loaded_pointer_into_align_metadata(ptr %p)
135134
ret ptr %p2
136135
}
137136

137+
define ptr @fold_assume_align_i32_pow2_of_loaded_pointer_into_align_metadata(ptr %p) {
138+
; CHECK-LABEL: @fold_assume_align_i32_pow2_of_loaded_pointer_into_align_metadata(
139+
; CHECK-NEXT: [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8
140+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i32 8) ]
141+
; CHECK-NEXT: ret ptr [[P2]]
142+
;
143+
%p2 = load ptr, ptr %p
144+
call void @llvm.assume(i1 true) [ "align"(ptr %p2, i32 8) ]
145+
ret ptr %p2
146+
}
147+
138148
define ptr @dont_fold_assume_align_pow2_of_loaded_pointer_into_align_metadata_due_to_call(ptr %p) {
139149
; CHECK-LABEL: @dont_fold_assume_align_pow2_of_loaded_pointer_into_align_metadata_due_to_call(
140150
; CHECK-NEXT: [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8
@@ -175,7 +185,6 @@ define ptr @dont_fold_assume_align_zero_of_loaded_pointer_into_align_metadata(pt
175185
define ptr @redundant_assume_align_1(ptr %p) {
176186
; CHECK-LABEL: @redundant_assume_align_1(
177187
; CHECK-NEXT: [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8
178-
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i32 1) ]
179188
; CHECK-NEXT: call void @foo(ptr [[P2]])
180189
; CHECK-NEXT: ret ptr [[P2]]
181190
;
@@ -189,7 +198,6 @@ define ptr @redundant_assume_align_1(ptr %p) {
189198
define ptr @redundant_assume_align_8_via_align_metadata(ptr %p) {
190199
; CHECK-LABEL: @redundant_assume_align_8_via_align_metadata(
191200
; CHECK-NEXT: [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8, !align [[META0:![0-9]+]]
192-
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i32 8) ]
193201
; CHECK-NEXT: call void @foo(ptr [[P2]])
194202
; CHECK-NEXT: ret ptr [[P2]]
195203
;
@@ -249,7 +257,47 @@ define ptr @redundant_assume_align_8_via_asume(ptr %p) {
249257
ret ptr %p
250258
}
251259

260+
define void @redundant_arg_passed_to_intrinsic(ptr %dst, ptr %src) {
261+
; CHECK-LABEL: @redundant_arg_passed_to_intrinsic(
262+
; CHECK-NEXT: call void @bar()
263+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[SRC:%.*]], i32 8) ]
264+
; CHECK-NEXT: call void @llvm.memmove.p0.p0.i64(ptr noundef nonnull align 8 dereferenceable(16) [[DST:%.*]], ptr noundef nonnull align 8 dereferenceable(16) [[SRC]], i64 16, i1 false)
265+
; CHECK-NEXT: ret void
266+
;
267+
call void @llvm.assume(i1 true) [ "align"(ptr %dst, i32 8) ]
268+
call void @bar()
269+
call void @llvm.assume(i1 true) [ "align"(ptr %src, i32 8) ]
270+
call void @llvm.memmove.p0.p0.i64(ptr align 8 %dst, ptr %src, i64 16, i1 false)
271+
ret void
272+
}
273+
274+
define void @test_store(ptr %ptr) {
275+
; CHECK-LABEL: @test_store(
276+
; CHECK-NEXT: entry:
277+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[PTR:%.*]], i64 2) ]
278+
; CHECK-NEXT: store i16 0, ptr [[PTR]], align 1
279+
; CHECK-NEXT: ret void
280+
;
281+
entry:
282+
call void @llvm.assume(i1 true) [ "align"(ptr %ptr, i64 2) ]
283+
store i16 0, ptr %ptr, align 1
284+
ret void
285+
}
286+
252287
declare void @foo(ptr)
288+
declare void @bar()
289+
290+
; !align must have a constant integer alignment.
291+
define ptr @dont_fold_assume_align_not_constant_of_loaded_pointer_into_align_metadata(ptr %p, i64 %align) {
292+
; CHECK-LABEL: @dont_fold_assume_align_not_constant_of_loaded_pointer_into_align_metadata(
293+
; CHECK-NEXT: [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8
294+
; CHECK-NEXT: ret ptr [[P2]]
295+
;
296+
%p2 = load ptr, ptr %p
297+
call void @llvm.assume(i1 true) [ "align"(ptr %p2, i64 %align) ]
298+
ret ptr %p2
299+
}
300+
253301
;.
254302
; CHECK: [[META0]] = !{i64 8}
255303
;.

llvm/test/Transforms/InstCombine/assume.ll

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2-
; RUN: opt < %s -passes=instcombine -S | FileCheck --check-prefixes=CHECK,DEFAULT %s
3-
; RUN: opt < %s -passes=instcombine --enable-knowledge-retention -S | FileCheck --check-prefixes=CHECK,BUNDLES %s
2+
; RUN: opt < %s -passes='instcombine<no-verify-fixpoint>' -S | FileCheck --check-prefixes=CHECK,DEFAULT %s
3+
; RUN: opt < %s -passes='instcombine<no-verify-fixpoint>' --enable-knowledge-retention -S | FileCheck --check-prefixes=CHECK,BUNDLES %s
44

5-
; RUN: opt < %s -passes=instcombine -S --try-experimental-debuginfo-iterators | FileCheck --check-prefixes=CHECK,DEFAULT %s
6-
; RUN: opt < %s -passes=instcombine --enable-knowledge-retention -S --try-experimental-debuginfo-iterators | FileCheck --check-prefixes=CHECK,BUNDLES %s
5+
; RUN: opt < %s -passes='instcombine<no-verify-fixpoint>' -S --try-experimental-debuginfo-iterators | FileCheck --check-prefixes=CHECK,DEFAULT %s
6+
; RUN: opt < %s -passes='instcombine<no-verify-fixpoint>' --enable-knowledge-retention -S --try-experimental-debuginfo-iterators | FileCheck --check-prefixes=CHECK,BUNDLES %s
77

88
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
99
target triple = "x86_64-unknown-linux-gnu"
@@ -795,14 +795,8 @@ exit:
795795
}
796796

797797
define void @canonicalize_assume(ptr %0) {
798-
; DEFAULT-LABEL: @canonicalize_assume(
799-
; DEFAULT-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP0:%.*]], i64 8
800-
; DEFAULT-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[TMP2]], i64 16) ]
801-
; DEFAULT-NEXT: ret void
802-
;
803-
; BUNDLES-LABEL: @canonicalize_assume(
804-
; BUNDLES-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[TMP0:%.*]], i64 8) ]
805-
; BUNDLES-NEXT: ret void
798+
; CHECK-LABEL: @canonicalize_assume(
799+
; CHECK-NEXT: ret void
806800
;
807801
%2 = getelementptr inbounds i32, ptr %0, i64 2
808802
call void @llvm.assume(i1 true) [ "align"(ptr %2, i64 16) ]

llvm/test/Transforms/PhaseOrdering/AArch64/infer-align-from-assumption.ll

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ define i32 @earlycse_entry(ptr %p) {
1515
; CHECK-NEXT: [[L_2_I:%.*]] = load ptr, ptr [[P]], align 8
1616
; CHECK-NEXT: [[GEP_I:%.*]] = getelementptr i8, ptr [[L_2_I]], i64 4
1717
; CHECK-NEXT: store ptr [[GEP_I]], ptr [[P]], align 8
18-
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[GEP_I]], i64 4) ]
1918
; CHECK-NEXT: [[L_ASSUME_ALIGNED_I_I2:%.*]] = load i32, ptr [[GEP_I]], align 4
2019
; CHECK-NEXT: [[R_I_I3:%.*]] = tail call i32 @swap(i32 [[L_ASSUME_ALIGNED_I_I2]])
2120
; CHECK-NEXT: [[L_2_I4:%.*]] = load ptr, ptr [[P]], align 8
@@ -51,7 +50,6 @@ define i32 @earlycse_fn1(ptr %p) {
5150
define i32 @load_assume_aligned(ptr %p) {
5251
; CHECK-LABEL: define i32 @load_assume_aligned(
5352
; CHECK-SAME: ptr [[P:%.*]]) local_unnamed_addr {
54-
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P]], i64 4) ]
5553
; CHECK-NEXT: [[DOT0_COPYLOAD:%.*]] = load i32, ptr [[P]], align 4
5654
; CHECK-NEXT: [[TMP2:%.*]] = tail call i32 @swap(i32 [[DOT0_COPYLOAD]])
5755
; CHECK-NEXT: ret i32 [[TMP2]]
@@ -66,8 +64,7 @@ declare i32 @swap(i32)
6664

6765
define void @sroa_align_entry(ptr %p) {
6866
; CHECK-LABEL: define void @sroa_align_entry(
69-
; CHECK-SAME: ptr [[P:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] {
70-
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P]], i64 8) ]
67+
; CHECK-SAME: ptr [[P:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
7168
; CHECK-NEXT: [[DOT0_COPYLOAD_I_I_I:%.*]] = load i64, ptr [[P]], align 8
7269
; CHECK-NEXT: [[TMP2:%.*]] = inttoptr i64 [[DOT0_COPYLOAD_I_I_I]] to ptr
7370
; CHECK-NEXT: store i32 0, ptr [[TMP2]], align 4
@@ -82,9 +79,6 @@ define void @sroa_align_entry(ptr %p) {
8279

8380
define ptr @sroa_fn1(ptr %p) {
8481
; CHECK-LABEL: define ptr @sroa_fn1(
85-
; CHECK-SAME: ptr nocapture readonly [[P:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
86-
; CHECK-NEXT: [[L:%.*]] = load ptr, ptr [[P]], align 8
87-
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[L]], i64 8) ]
8882
; CHECK-NEXT: [[L_FN3_I_I:%.*]] = load i64, ptr [[L]], align 8
8983
; CHECK-NEXT: [[I_I:%.*]] = inttoptr i64 [[L_FN3_I_I]] to ptr
9084
; CHECK-NEXT: ret ptr [[I_I]]
@@ -96,8 +90,7 @@ define ptr @sroa_fn1(ptr %p) {
9690

9791
define ptr @sroa_fn2(ptr %p) {
9892
; CHECK-LABEL: define ptr @sroa_fn2(
99-
; CHECK-SAME: ptr [[P:%.*]]) local_unnamed_addr #[[ATTR3:[0-9]+]] {
100-
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P]], i64 8) ]
93+
; CHECK-SAME: ptr [[P:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
10194
; CHECK-NEXT: [[DOT0_COPYLOAD_I_I:%.*]] = load i64, ptr [[P]], align 8
10295
; CHECK-NEXT: [[TMP3:%.*]] = inttoptr i64 [[DOT0_COPYLOAD_I_I]] to ptr
10396
; CHECK-NEXT: ret ptr [[TMP3]]
@@ -109,12 +102,29 @@ define ptr @sroa_fn2(ptr %p) {
109102

110103
define i64 @sroa_fn3(ptr %0) {
111104
; CHECK-LABEL: define i64 @sroa_fn3(
112-
; CHECK-SAME: ptr [[TMP0:%.*]]) local_unnamed_addr #[[ATTR3]] {
113-
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[TMP0]], i64 8) ]
105+
; CHECK-SAME: ptr [[TMP0:%.*]]) local_unnamed_addr #[[ATTR2]] {
114106
; CHECK-NEXT: [[DOT0_COPYLOAD_I:%.*]] = load i64, ptr [[TMP0]], align 8
115107
; CHECK-NEXT: ret i64 [[DOT0_COPYLOAD_I]]
116108
;
117109
call void @llvm.assume(i1 true) [ "align"(ptr %0, i64 8) ]
118110
%l.fn3 = load i64, ptr %0, align 1
119111
ret i64 %l.fn3
120112
}
113+
114+
define void @test_store(ptr %ptr) {
115+
; CHECK-LABEL: define void @test_store(
116+
; CHECK-SAME: ptr [[PTR:%.*]]) local_unnamed_addr #[[ATTR3:[0-9]+]] {
117+
; CHECK-NEXT: [[ENTRY:.*:]]
118+
; CHECK-NEXT: store i16 0, ptr [[PTR]], align 2
119+
; CHECK-NEXT: ret void
120+
;
121+
entry:
122+
call void @llvm.assume(i1 true) [ "align"(ptr %ptr, i64 2) ]
123+
store i16 0, ptr %ptr, align 1
124+
ret void
125+
}
126+
;.
127+
; CHECK: [[META0]] = !{i64 4}
128+
; CHECK: [[META1]] = !{}
129+
; CHECK: [[META2]] = !{i64 8}
130+
;.

0 commit comments

Comments
 (0)