diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index 33b66aeaffe60..11bac7bdb6eb2 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -3385,12 +3385,13 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) { // TODO: apply range metadata for range check patterns? } - // Separate storage assumptions apply to the underlying allocations, not any - // particular pointer within them. When evaluating the hints for AA purposes - // we getUnderlyingObject them; by precomputing the answers here we can - // avoid having to do so repeatedly there. for (unsigned Idx = 0; Idx < II->getNumOperandBundles(); Idx++) { OperandBundleUse OBU = II->getOperandBundleAt(Idx); + + // Separate storage assumptions apply to the underlying allocations, not + // any particular pointer within them. When evaluating the hints for AA + // purposes we getUnderlyingObject them; by precomputing the answers here + // we can avoid having to do so repeatedly there. if (OBU.getTagName() == "separate_storage") { assert(OBU.Inputs.size() == 2); auto MaybeSimplifyHint = [&](const Use &U) { @@ -3404,6 +3405,32 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) { MaybeSimplifyHint(OBU.Inputs[0]); MaybeSimplifyHint(OBU.Inputs[1]); } + + // Try to remove redundant alignment assumptions. + if (OBU.getTagName() == "align" && OBU.Inputs.size() == 2) { + RetainedKnowledge RK = getKnowledgeFromOperandInAssume( + *cast(II), II->arg_size() + Idx); + if (!RK || RK.AttrKind != Attribute::Alignment || + !isPowerOf2_64(RK.ArgValue) || !isa(RK.IRArgValue)) + continue; + + // Don't try to remove align assumptions for pointers derived from + // arguments. We might lose information if the function gets inline and + // the align argument attribute disappears. + Value *UO = getUnderlyingObject(RK.WasOn); + if (!UO || isa(UO)) + continue; + + // Compute known bits for the pointer, passing nullptr as context to + // avoid computeKnownBits using the assumption we are about to remove + // for reasoning. + KnownBits Known = computeKnownBits(RK.WasOn, /*CtxI=*/nullptr); + unsigned TZ = std::min(Known.countMinTrailingZeros(), + Value::MaxAlignmentExponent); + if ((1ULL << TZ) < RK.ArgValue) + continue; + return CallBase::removeOperandBundle(II, OBU.getTagID()); + } } // Convert nonnull assume like: diff --git a/llvm/test/Analysis/BasicAA/featuretest.ll b/llvm/test/Analysis/BasicAA/featuretest.ll index e4cb009f0c633..04c4725d26c1d 100644 --- a/llvm/test/Analysis/BasicAA/featuretest.ll +++ b/llvm/test/Analysis/BasicAA/featuretest.ll @@ -15,24 +15,14 @@ declare void @llvm.assume(i1) ; operations on another array. Important for scientific codes. ; define i32 @different_array_test(i64 %A, i64 %B) { -; NO_ASSUME-LABEL: @different_array_test( -; NO_ASSUME-NEXT: [[ARRAY11:%.*]] = alloca [100 x i32], align 4 -; NO_ASSUME-NEXT: [[ARRAY22:%.*]] = alloca [200 x i32], align 4 -; NO_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[ARRAY11]], i32 4) ] -; NO_ASSUME-NEXT: call void @external(ptr nonnull [[ARRAY11]]) -; NO_ASSUME-NEXT: call void @external(ptr nonnull [[ARRAY22]]) -; NO_ASSUME-NEXT: [[POINTER2:%.*]] = getelementptr i32, ptr [[ARRAY22]], i64 [[B:%.*]] -; NO_ASSUME-NEXT: store i32 7, ptr [[POINTER2]], align 4 -; NO_ASSUME-NEXT: ret i32 0 -; -; USE_ASSUME-LABEL: @different_array_test( -; USE_ASSUME-NEXT: [[ARRAY11:%.*]] = alloca [100 x i32], align 4 -; USE_ASSUME-NEXT: [[ARRAY22:%.*]] = alloca [200 x i32], align 4 -; USE_ASSUME-NEXT: call void @external(ptr nonnull [[ARRAY11]]) -; USE_ASSUME-NEXT: call void @external(ptr nonnull [[ARRAY22]]) -; USE_ASSUME-NEXT: [[POINTER2:%.*]] = getelementptr i32, ptr [[ARRAY22]], i64 [[B:%.*]] -; USE_ASSUME-NEXT: store i32 7, ptr [[POINTER2]], align 4 -; USE_ASSUME-NEXT: ret i32 0 +; CHECK-LABEL: @different_array_test( +; CHECK-NEXT: [[ARRAY11:%.*]] = alloca [100 x i32], align 4 +; CHECK-NEXT: [[ARRAY22:%.*]] = alloca [200 x i32], align 4 +; CHECK-NEXT: call void @external(ptr nonnull [[ARRAY11]]) +; CHECK-NEXT: call void @external(ptr nonnull [[ARRAY22]]) +; CHECK-NEXT: [[POINTER2:%.*]] = getelementptr i32, ptr [[ARRAY22]], i64 [[B:%.*]] +; CHECK-NEXT: store i32 7, ptr [[POINTER2]], align 4 +; CHECK-NEXT: ret i32 0 ; %Array1 = alloca i32, i32 100 %Array2 = alloca i32, i32 200 diff --git a/llvm/test/Transforms/InstCombine/assume-align.ll b/llvm/test/Transforms/InstCombine/assume-align.ll index f0e0257433086..274632658496b 100644 --- a/llvm/test/Transforms/InstCombine/assume-align.ll +++ b/llvm/test/Transforms/InstCombine/assume-align.ll @@ -175,7 +175,6 @@ define ptr @dont_fold_assume_align_zero_of_loaded_pointer_into_align_metadata(pt define ptr @redundant_assume_align_1(ptr %p) { ; CHECK-LABEL: @redundant_assume_align_1( ; CHECK-NEXT: [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8 -; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i32 1) ] ; CHECK-NEXT: call void @foo(ptr [[P2]]) ; CHECK-NEXT: ret ptr [[P2]] ; @@ -189,7 +188,6 @@ define ptr @redundant_assume_align_1(ptr %p) { define ptr @redundant_assume_align_8_via_align_metadata(ptr %p) { ; CHECK-LABEL: @redundant_assume_align_8_via_align_metadata( ; CHECK-NEXT: [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8, !align [[META0:![0-9]+]] -; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i32 8) ] ; CHECK-NEXT: call void @foo(ptr [[P2]]) ; CHECK-NEXT: ret ptr [[P2]] ; @@ -250,6 +248,19 @@ define ptr @redundant_assume_align_8_via_asume(ptr %p) { } declare void @foo(ptr) + +; !align must have a constant integer alignment. +define ptr @assume_load_pointer_result(ptr %p, i64 %align) { +; CHECK-LABEL: @assume_load_pointer_result( +; CHECK-NEXT: [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8 +; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i64 [[ALIGN:%.*]]) ] +; CHECK-NEXT: ret ptr [[P2]] +; + %p2 = load ptr, ptr %p + call void @llvm.assume(i1 true) [ "align"(ptr %p2, i64 %align) ] + ret ptr %p2 +} + ;. ; CHECK: [[META0]] = !{i64 8} ;.