diff --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h index 8cdfa27ece9378d..ca349ec6f9cb962 100644 --- a/llvm/include/llvm/IR/IRBuilder.h +++ b/llvm/include/llvm/IR/IRBuilder.h @@ -2676,6 +2676,8 @@ class IRBuilderBase { CallInst *CreateAlignmentAssumption(const DataLayout &DL, Value *PtrValue, Value *Alignment, Value *OffsetValue = nullptr); + + CallInst *CreateDereferenceableAssumption(Value *PtrValue, unsigned Size); }; /// This provides a uniform API for creating instructions and inserting diff --git a/llvm/include/llvm/Transforms/InstCombine/InstCombine.h b/llvm/include/llvm/Transforms/InstCombine/InstCombine.h index c12d749709cd255..dd9d05cbbcf7c97 100644 --- a/llvm/include/llvm/Transforms/InstCombine/InstCombine.h +++ b/llvm/include/llvm/Transforms/InstCombine/InstCombine.h @@ -31,6 +31,7 @@ struct InstCombineOptions { // Verify that a fix point has been reached after MaxIterations. bool VerifyFixpoint = false; unsigned MaxIterations = InstCombineDefaultMaxIterations; + bool CleanupAssumptions = false; InstCombineOptions() = default; @@ -43,6 +44,11 @@ struct InstCombineOptions { MaxIterations = Value; return *this; } + + InstCombineOptions &setCleanupAssumptions(bool Value) { + CleanupAssumptions = Value; + return *this; + } }; class InstCombinePass : public PassInfoMixin { diff --git a/llvm/lib/IR/IRBuilder.cpp b/llvm/lib/IR/IRBuilder.cpp index f340f7aafdc76f4..11536fa56eee468 100644 --- a/llvm/lib/IR/IRBuilder.cpp +++ b/llvm/lib/IR/IRBuilder.cpp @@ -1273,6 +1273,13 @@ CallInst *IRBuilderBase::CreateAlignmentAssumption(const DataLayout &DL, return CreateAlignmentAssumptionHelper(DL, PtrValue, Alignment, OffsetValue); } +CallInst *IRBuilderBase::CreateDereferenceableAssumption(Value *PtrValue, + unsigned Size) { + SmallVector Vals({PtrValue, getInt64(Size)}); + OperandBundleDefT AlignOpB("dereferenceable", Vals); + return CreateAssumption(ConstantInt::getTrue(getContext()), {AlignOpB}); +} + IRBuilderDefaultInserter::~IRBuilderDefaultInserter() = default; IRBuilderCallbackInserter::~IRBuilderCallbackInserter() = default; IRBuilderFolder::~IRBuilderFolder() = default; diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index a936f5381137c63..6910c7977c296f0 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -915,6 +915,8 @@ Expected parseInstCombineOptions(StringRef Params) { ParamName).str(), inconvertibleErrorCode()); Result.setMaxIterations((unsigned)MaxIterations.getZExtValue()); + } else if (ParamName == "cleanup-assumptions") { + Result.setCleanupAssumptions(Enable); } else { return make_error( formatv("invalid InstCombine pass parameter '{0}' ", ParamName).str(), diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp index d737ea5ab070a90..e0efc2a82971f40 100644 --- a/llvm/lib/Passes/PassBuilderPipelines.cpp +++ b/llvm/lib/Passes/PassBuilderPipelines.cpp @@ -1305,7 +1305,8 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level, FPM.addPass(LoopLoadEliminationPass()); } // Cleanup after the loop optimization passes. - FPM.addPass(InstCombinePass()); + FPM.addPass( + InstCombinePass(InstCombineOptions().setCleanupAssumptions(true))); if (Level.getSpeedupLevel() > 1 && ExtraVectorizerPasses) { ExtraFunctionPassManager ExtraPasses; @@ -1317,7 +1318,8 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level, // dead (or speculatable) control flows or more combining opportunities. ExtraPasses.addPass(EarlyCSEPass()); ExtraPasses.addPass(CorrelatedValuePropagationPass()); - ExtraPasses.addPass(InstCombinePass()); + ExtraPasses.addPass( + InstCombinePass(InstCombineOptions().setCleanupAssumptions(true))); LoopPassManager LPM; LPM.addPass(LICMPass(PTO.LicmMssaOptCap, PTO.LicmMssaNoAccForPromotionCap, /*AllowSpeculation=*/true)); @@ -1328,7 +1330,8 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level, /*UseBlockFrequencyInfo=*/true)); ExtraPasses.addPass( SimplifyCFGPass(SimplifyCFGOptions().convertSwitchRangeToICmp(true))); - ExtraPasses.addPass(InstCombinePass()); + ExtraPasses.addPass( + InstCombinePass(InstCombineOptions().setCleanupAssumptions(true))); FPM.addPass(std::move(ExtraPasses)); } @@ -1351,7 +1354,8 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level, if (IsFullLTO) { FPM.addPass(SCCPPass()); - FPM.addPass(InstCombinePass()); + FPM.addPass( + InstCombinePass(InstCombineOptions().setCleanupAssumptions(true))); FPM.addPass(BDCEPass()); } @@ -1366,7 +1370,8 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level, FPM.addPass(VectorCombinePass()); if (!IsFullLTO) { - FPM.addPass(InstCombinePass()); + FPM.addPass( + InstCombinePass(InstCombineOptions().setCleanupAssumptions(true))); // Unroll small loops to hide loop backedge latency and saturate any // parallel execution resources of an out-of-order processor. We also then // need to clean up redundancies and loop invariant code. @@ -1392,7 +1397,8 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level, } FPM.addPass(InferAlignmentPass()); - FPM.addPass(InstCombinePass()); + FPM.addPass( + InstCombinePass(InstCombineOptions().setCleanupAssumptions(true))); // This is needed for two reasons: // 1. It works around problems that instcombine introduces, such as sinking diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index 9f0b09278edcca9..78cdc3ecbfd69c5 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -540,7 +540,7 @@ FUNCTION_PASS_WITH_PARAMS( [](InstCombineOptions Opts) { return InstCombinePass(Opts); }, parseInstCombineOptions, "no-use-loop-info;use-loop-info;no-verify-fixpoint;verify-fixpoint;" - "max-iterations=N") + "max-iterations=N;cleanup-assumptions") FUNCTION_PASS_WITH_PARAMS( "loop-unroll", "LoopUnrollPass", [](LoopUnrollOptions Opts) { return LoopUnrollPass(Opts); }, diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index fd38738e3be80b7..545bfbbd2e742eb 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -3172,6 +3172,13 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) { MaybeSimplifyHint(OBU.Inputs[0]); MaybeSimplifyHint(OBU.Inputs[1]); } + + // Try to clean up some assumption that are not very useful after this + // point. + if (CleanupAssumptions && OBU.getTagName() == "dereferenceable") { + auto *New = CallBase::removeOperandBundle(II, OBU.getTagID()); + return New; + } } // Convert nonnull assume like: diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h index 3a074ee70dc487a..6cfb703ed58f5cd 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h +++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h @@ -59,6 +59,8 @@ class User; class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final : public InstCombiner, public InstVisitor { + bool CleanupAssumptions = false; + public: InstCombinerImpl(InstructionWorklist &Worklist, BuilderTy &Builder, bool MinimizeSize, AAResults *AA, AssumptionCache &AC, @@ -66,9 +68,11 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final DominatorTree &DT, OptimizationRemarkEmitter &ORE, BlockFrequencyInfo *BFI, BranchProbabilityInfo *BPI, ProfileSummaryInfo *PSI, const DataLayout &DL, - ReversePostOrderTraversal &RPOT) + ReversePostOrderTraversal &RPOT, + bool CleanupAssumptions) : InstCombiner(Worklist, Builder, MinimizeSize, AA, AC, TLI, TTI, DT, ORE, - BFI, BPI, PSI, DL, RPOT) {} + BFI, BPI, PSI, DL, RPOT), + CleanupAssumptions(CleanupAssumptions) {} virtual ~InstCombinerImpl() = default; diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp index 934156f04f7fdd4..76868163ada3bd7 100644 --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -40,6 +40,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/AssumeBundleQueries.h" #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/BasicAliasAnalysis.h" #include "llvm/Analysis/BlockFrequencyInfo.h" @@ -4872,6 +4873,16 @@ bool InstCombinerImpl::tryToSinkInstruction(Instruction *I, /// the new position. BasicBlock::iterator InsertPos = DestBlock->getFirstInsertionPt(); + + if (!CleanupAssumptions && isa(I)) { + // Preserve dereferenceable at original position. + // TODO: Only need to add this extra information if I doesn't always execute + // in the new position. + Builder.SetInsertPoint(I); + Value *Ptr = I->getOperand(0); + Builder.CreateDereferenceableAssumption( + Ptr, I->getType()->getScalarSizeInBits()); + } I->moveBefore(*DestBlock, InsertPos); ++NumSunkInst; @@ -5133,7 +5144,9 @@ bool InstCombinerImpl::run() { for (Use &U : I->uses()) { User *User = U.getUser(); - if (User->isDroppable()) + if (User->isDroppable() && + (!I->getType()->isPointerTy() || + !getKnowledgeForValue(I, Attribute::Dereferenceable, &AC))) continue; if (NumUsers > MaxSinkNumUsers) return std::nullopt; @@ -5524,7 +5537,7 @@ static bool combineInstructionsOverFunction( << F.getName() << "\n"); InstCombinerImpl IC(Worklist, Builder, F.hasMinSize(), AA, AC, TLI, TTI, DT, - ORE, BFI, BPI, PSI, DL, RPOT); + ORE, BFI, BPI, PSI, DL, RPOT, Opts.CleanupAssumptions); IC.MaxArraySizeForCombine = MaxArraySize; bool MadeChangeInThisIteration = IC.prepareWorklist(F); MadeChangeInThisIteration |= IC.run(); @@ -5573,7 +5586,7 @@ PreservedAnalyses InstCombinePass::run(Function &F, FunctionAnalysisManager &AM) { auto &LRT = AM.getResult(F); // No changes since last InstCombine pass, exit early. - if (LRT.shouldSkip(&ID)) + if (LRT.shouldSkip(&ID) && !Options.CleanupAssumptions) return PreservedAnalyses::all(); auto &AC = AM.getResult(F); diff --git a/llvm/test/Transforms/InstCombine/assume.ll b/llvm/test/Transforms/InstCombine/assume.ll index 52f0adf02a39651..bc49c1459a0ebba 100644 --- a/llvm/test/Transforms/InstCombine/assume.ll +++ b/llvm/test/Transforms/InstCombine/assume.ll @@ -316,11 +316,12 @@ define i1 @nonnull3(ptr %a, i1 %control) { ; ; BUNDLES-LABEL: @nonnull3( ; BUNDLES-NEXT: entry: +; BUNDLES-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[A:%.*]], i64 0) ] ; BUNDLES-NEXT: br i1 [[CONTROL:%.*]], label [[TAKEN:%.*]], label [[NOT_TAKEN:%.*]] ; BUNDLES: taken: ; BUNDLES-NEXT: ret i1 false ; BUNDLES: not_taken: -; BUNDLES-NEXT: [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8 +; BUNDLES-NEXT: [[LOAD:%.*]] = load ptr, ptr [[A]], align 8 ; BUNDLES-NEXT: [[RVAL_2:%.*]] = icmp sgt ptr [[LOAD]], null ; BUNDLES-NEXT: ret i1 [[RVAL_2]] ; @@ -454,11 +455,12 @@ define i1 @nonnull3A(ptr %a, i1 %control) { ; ; BUNDLES-LABEL: @nonnull3A( ; BUNDLES-NEXT: entry: +; BUNDLES-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[A:%.*]], i64 0) ] ; BUNDLES-NEXT: br i1 [[CONTROL:%.*]], label [[TAKEN:%.*]], label [[NOT_TAKEN:%.*]] ; BUNDLES: taken: ; BUNDLES-NEXT: ret i1 true ; BUNDLES: not_taken: -; BUNDLES-NEXT: [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8 +; BUNDLES-NEXT: [[LOAD:%.*]] = load ptr, ptr [[A]], align 8 ; BUNDLES-NEXT: [[RVAL_2:%.*]] = icmp sgt ptr [[LOAD]], null ; BUNDLES-NEXT: ret i1 [[RVAL_2]] ; @@ -478,9 +480,10 @@ not_taken: define i1 @nonnull3B(ptr %a, i1 %control) { ; CHECK-LABEL: @nonnull3B( ; CHECK-NEXT: entry: +; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[A:%.*]], i64 0) ] ; CHECK-NEXT: br i1 [[CONTROL:%.*]], label [[TAKEN:%.*]], label [[NOT_TAKEN:%.*]] ; CHECK: taken: -; CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8 +; CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr [[A]], align 8 ; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[LOAD]], null ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) [ "nonnull"(ptr [[LOAD]]) ] ; CHECK-NEXT: ret i1 [[CMP]] @@ -504,9 +507,10 @@ declare i1 @tmp1(i1) define i1 @nonnull3C(ptr %a, i1 %control) { ; CHECK-LABEL: @nonnull3C( ; CHECK-NEXT: entry: +; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[A:%.*]], i64 0) ] ; CHECK-NEXT: br i1 [[CONTROL:%.*]], label [[TAKEN:%.*]], label [[NOT_TAKEN:%.*]] ; CHECK: taken: -; CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8 +; CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr [[A]], align 8 ; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[LOAD]], null ; CHECK-NEXT: [[CMP2:%.*]] = call i1 @tmp1(i1 [[CMP]]) ; CHECK-NEXT: br label [[EXIT:%.*]] @@ -534,9 +538,10 @@ not_taken: define i1 @nonnull3D(ptr %a, i1 %control) { ; CHECK-LABEL: @nonnull3D( ; CHECK-NEXT: entry: +; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[A:%.*]], i64 0) ] ; CHECK-NEXT: br i1 [[CONTROL:%.*]], label [[TAKEN:%.*]], label [[NOT_TAKEN:%.*]] ; CHECK: taken: -; CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr [[A:%.*]], align 8 +; CHECK-NEXT: [[LOAD:%.*]] = load ptr, ptr [[A]], align 8 ; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[LOAD]], null ; CHECK-NEXT: [[CMP2:%.*]] = call i1 @tmp1(i1 [[CMP]]) ; CHECK-NEXT: br label [[EXIT:%.*]] diff --git a/llvm/test/Transforms/InstCombine/select-cmp-br.ll b/llvm/test/Transforms/InstCombine/select-cmp-br.ll index 2a8c19ece4b70a9..98af6f4b4cc8c89 100644 --- a/llvm/test/Transforms/InstCombine/select-cmp-br.ll +++ b/llvm/test/Transforms/InstCombine/select-cmp-br.ll @@ -14,6 +14,8 @@ define void @test1(ptr %arg) { ; CHECK-NEXT: [[M:%.*]] = load ptr, ptr [[ARG:%.*]], align 8 ; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw i8, ptr [[ARG]], i64 16 ; CHECK-NEXT: [[N:%.*]] = load ptr, ptr [[TMP1]], align 8 +; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw i8, ptr [[M]], i64 72 +; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[TMP2]], i64 0) ] ; CHECK-NEXT: [[TMP5_NOT:%.*]] = icmp eq ptr [[M]], [[N]] ; CHECK-NEXT: br i1 [[TMP5_NOT]], label [[BB8:%.*]], label [[BB10:%.*]] ; CHECK: bb: @@ -22,7 +24,6 @@ define void @test1(ptr %arg) { ; CHECK-NEXT: tail call void @bar(ptr nonnull [[ARG]]) ; CHECK-NEXT: br label [[BB:%.*]] ; CHECK: bb10: -; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw i8, ptr [[M]], i64 72 ; CHECK-NEXT: [[TMP4:%.*]] = load ptr, ptr [[TMP2]], align 8 ; CHECK-NEXT: [[TMP11:%.*]] = tail call i64 [[TMP4]](ptr nonnull [[ARG]]) ; CHECK-NEXT: br label [[BB]] @@ -56,6 +57,8 @@ define void @test2(ptr %arg) { ; CHECK-NEXT: [[M:%.*]] = load ptr, ptr [[ARG:%.*]], align 8 ; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw i8, ptr [[ARG]], i64 16 ; CHECK-NEXT: [[N:%.*]] = load ptr, ptr [[TMP1]], align 8 +; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw i8, ptr [[M]], i64 72 +; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[TMP2]], i64 0) ] ; CHECK-NEXT: [[TMP5:%.*]] = icmp eq ptr [[M]], [[N]] ; CHECK-NEXT: br i1 [[TMP5]], label [[BB10:%.*]], label [[BB8:%.*]] ; CHECK: bb: @@ -64,7 +67,6 @@ define void @test2(ptr %arg) { ; CHECK-NEXT: tail call void @bar(ptr nonnull [[ARG]]) ; CHECK-NEXT: br label [[BB:%.*]] ; CHECK: bb10: -; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw i8, ptr [[M]], i64 72 ; CHECK-NEXT: [[TMP4:%.*]] = load ptr, ptr [[TMP2]], align 8 ; CHECK-NEXT: [[TMP11:%.*]] = tail call i64 [[TMP4]](ptr nonnull [[ARG]]) ; CHECK-NEXT: br label [[BB]] @@ -98,6 +100,8 @@ define void @test3(ptr %arg) { ; CHECK-NEXT: [[M:%.*]] = load ptr, ptr [[ARG:%.*]], align 8 ; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw i8, ptr [[ARG]], i64 16 ; CHECK-NEXT: [[N:%.*]] = load ptr, ptr [[TMP1]], align 8 +; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw i8, ptr [[M]], i64 72 +; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[TMP2]], i64 0) ] ; CHECK-NEXT: [[TMP5:%.*]] = icmp eq ptr [[M]], [[N]] ; CHECK-NEXT: br i1 [[TMP5]], label [[BB8:%.*]], label [[BB10:%.*]] ; CHECK: bb: @@ -106,7 +110,6 @@ define void @test3(ptr %arg) { ; CHECK-NEXT: tail call void @bar(ptr nonnull [[ARG]]) ; CHECK-NEXT: br label [[BB:%.*]] ; CHECK: bb10: -; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw i8, ptr [[M]], i64 72 ; CHECK-NEXT: [[TMP4:%.*]] = load ptr, ptr [[TMP2]], align 8 ; CHECK-NEXT: [[TMP11:%.*]] = tail call i64 [[TMP4]](ptr nonnull [[ARG]]) ; CHECK-NEXT: br label [[BB]] @@ -140,6 +143,8 @@ define void @test4(ptr %arg) { ; CHECK-NEXT: [[M:%.*]] = load ptr, ptr [[ARG:%.*]], align 8 ; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw i8, ptr [[ARG]], i64 16 ; CHECK-NEXT: [[N:%.*]] = load ptr, ptr [[TMP1]], align 8 +; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw i8, ptr [[M]], i64 72 +; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[TMP2]], i64 0) ] ; CHECK-NEXT: [[TMP5:%.*]] = icmp eq ptr [[M]], [[N]] ; CHECK-NEXT: br i1 [[TMP5]], label [[BB10:%.*]], label [[BB8:%.*]] ; CHECK: bb: @@ -148,7 +153,6 @@ define void @test4(ptr %arg) { ; CHECK-NEXT: tail call void @bar(ptr nonnull [[ARG]]) ; CHECK-NEXT: br label [[BB:%.*]] ; CHECK: bb10: -; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw i8, ptr [[M]], i64 72 ; CHECK-NEXT: [[TMP4:%.*]] = load ptr, ptr [[TMP2]], align 8 ; CHECK-NEXT: [[TMP11:%.*]] = tail call i64 [[TMP4]](ptr nonnull [[ARG]]) ; CHECK-NEXT: br label [[BB]] diff --git a/llvm/test/Transforms/InstCombine/sink_instruction.ll b/llvm/test/Transforms/InstCombine/sink_instruction.ll index cb9a3069ca5fd4b..bb41080f82f556a 100644 --- a/llvm/test/Transforms/InstCombine/sink_instruction.ll +++ b/llvm/test/Transforms/InstCombine/sink_instruction.ll @@ -44,7 +44,7 @@ define i32 @test2(i32 %x) nounwind ssp "instcombine-no-verify-fixpoint" { ; CHECK: bb1: ; CHECK-NEXT: [[TMP1:%.*]] = add nsw i32 [[X_ADDR_17]], 1 ; CHECK-NEXT: [[TMP2:%.*]] = sdiv i32 [[TMP1]], [[X_ADDR_17]] -; CHECK-NEXT: [[TMP3:%.*]] = tail call i32 @bar() #[[ATTR3:[0-9]+]] +; CHECK-NEXT: [[TMP3:%.*]] = tail call i32 @bar() #[[ATTR4:[0-9]+]] ; CHECK-NEXT: br label [[BB2]] ; CHECK: bb2: ; CHECK-NEXT: [[X_ADDR_0]] = phi i32 [ [[TMP2]], [[BB1]] ], [ [[X_ADDR_17]], [[BB]] ] @@ -84,13 +84,14 @@ declare i32 @bar() define i32 @test3(ptr nocapture readonly %P, i32 %i) { ; CHECK-LABEL: @test3( ; CHECK-NEXT: entry: -; CHECK-NEXT: switch i32 [[I:%.*]], label [[SW_EPILOG:%.*]] [ +; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I:%.*]] to i64 +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 [[IDXPROM]] +; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[ARRAYIDX]], i64 32) ] +; CHECK-NEXT: switch i32 [[I]], label [[SW_EPILOG:%.*]] [ ; CHECK-NEXT: i32 5, label [[SW_BB:%.*]] ; CHECK-NEXT: i32 2, label [[SW_BB]] ; CHECK-NEXT: ] ; CHECK: sw.bb: -; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I]] to i64 -; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 [[IDXPROM]] ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4 ; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP0]], [[I]] ; CHECK-NEXT: br label [[SW_EPILOG]] @@ -182,11 +183,12 @@ sw.epilog: ; preds = %entry, %sw.bb define i32 @test6(ptr nocapture readonly %P, i32 %i, i1 %cond) { ; CHECK-LABEL: @test6( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[ADD:%.*]] = shl nsw i32 [[I:%.*]], 1 +; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I:%.*]] to i64 +; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 [[IDXPROM]] +; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[ARRAYIDX]], i64 32) ] +; CHECK-NEXT: [[ADD:%.*]] = shl nsw i32 [[I]], 1 ; CHECK-NEXT: br label [[DISPATCHBB:%.*]] ; CHECK: dispatchBB: -; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I]] to i64 -; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 [[IDXPROM]] ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4 ; CHECK-NEXT: switch i32 [[I]], label [[SW_BB:%.*]] [ ; CHECK-NEXT: i32 5, label [[SW_EPILOG:%.*]] @@ -277,12 +279,13 @@ abort: define i32 @invariant_load_metadata(ptr %p, i1 %cond) { ; CHECK-LABEL: @invariant_load_metadata( ; CHECK-NEXT: entry: +; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P:%.*]], i64 32) ] ; CHECK-NEXT: br i1 [[COND:%.*]], label [[BLOCK:%.*]], label [[END:%.*]] ; CHECK: block: ; CHECK-NEXT: call void @fn() ; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[P:%.*]], align 4, !invariant.load [[META0:![0-9]+]] +; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[P]], align 4, !invariant.load [[META0:![0-9]+]] ; CHECK-NEXT: ret i32 [[V]] ; entry: @@ -324,12 +327,13 @@ end: define void @invariant_load_use_in_br(ptr %p, i1 %cond) { ; CHECK-LABEL: @invariant_load_use_in_br( ; CHECK-NEXT: entry: +; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P:%.*]], i64 32) ] ; CHECK-NEXT: br i1 [[COND:%.*]], label [[TRUE_BR:%.*]], label [[FALSE_BR:%.*]] ; CHECK: true.br: ; CHECK-NEXT: call void @fn() ; CHECK-NEXT: br label [[EXIT:%.*]] ; CHECK: false.br: -; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[P:%.*]], align 4 +; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[P]], align 4 ; CHECK-NEXT: call void @fn(i32 [[VAL]]) ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: @@ -353,13 +357,14 @@ exit: define void @invariant_load_metadata_call(ptr %p, i1 %cond) { ; CHECK-LABEL: @invariant_load_metadata_call( ; CHECK-NEXT: entry: +; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P:%.*]], i64 32) ] ; CHECK-NEXT: call void @fn() ; CHECK-NEXT: br i1 [[COND:%.*]], label [[TRUE_BR:%.*]], label [[FALSE_BR:%.*]] ; CHECK: true.br: ; CHECK-NEXT: call void @fn() ; CHECK-NEXT: br label [[EXIT:%.*]] ; CHECK: false.br: -; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[P:%.*]], align 4, !invariant.load [[META0]] +; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[P]], align 4, !invariant.load [[META0]] ; CHECK-NEXT: call void @fn(i32 [[VAL]]) ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: