diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp --- a/llvm/lib/Transforms/Scalar/LICM.cpp +++ b/llvm/lib/Transforms/Scalar/LICM.cpp @@ -69,6 +69,7 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Scalar/LoopPassManager.h" +#include "llvm/Transforms/Utils/AssumeBundleBuilder.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/Local.h" #include "llvm/Transforms/Utils/LoopUtils.h" @@ -481,6 +482,7 @@ // used in the loop, instead, just delete it. if (isInstructionTriviallyDead(&I, TLI)) { LLVM_DEBUG(dbgs() << "LICM deleting dead inst: " << I << '\n'); + salvageKnowledge(&I); salvageDebugInfo(I); ++II; eraseInstruction(I, *SafetyInfo, CurAST, MSSAU); diff --git a/llvm/test/Transforms/LICM/pr23608.ll b/llvm/test/Transforms/LICM/pr23608.ll --- a/llvm/test/Transforms/LICM/pr23608.ll +++ b/llvm/test/Transforms/LICM/pr23608.ll @@ -1,4 +1,6 @@ -; RUN: opt -S -licm %s | FileCheck %s +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -licm %s | FileCheck %s --check-prefixes=CHECK,NO_ASSUME +; RUN: opt -S -licm --enable-knowledge-retention %s | FileCheck %s --check-prefixes=CHECK,USE_ASSUME ; ModuleID = '../pr23608.ll' target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" @@ -9,6 +11,63 @@ @__msan_origin_tls = external thread_local(initialexec) global i32 define void @fn1() { +; NO_ASSUME-LABEL: @fn1( +; NO_ASSUME-NEXT: entry: +; NO_ASSUME-NEXT: br label [[INDIRECTGOTO:%.*]] +; NO_ASSUME: while.cond: +; NO_ASSUME-NEXT: [[TMP:%.*]] = load %struct.PyFrameObject*, %struct.PyFrameObject** @a, align 8 +; NO_ASSUME-NEXT: [[F_IBLOCK:%.*]] = getelementptr inbounds [[STRUCT_PYFRAMEOBJECT:%.*]], %struct.PyFrameObject* [[TMP]], i64 0, i32 0 +; NO_ASSUME-NEXT: br label [[BB2:%.*]] +; NO_ASSUME: bb: +; NO_ASSUME-NEXT: call void @__msan_warning_noreturn() +; NO_ASSUME-NEXT: unreachable +; NO_ASSUME: bb2: +; NO_ASSUME-NEXT: [[TMP4:%.*]] = ptrtoint i32* [[F_IBLOCK]] to i64 +; NO_ASSUME-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[TMP4]], 0 +; NO_ASSUME-NEXT: br i1 [[TOBOOL]], label [[BB13:%.*]], label [[BB15:%.*]] +; NO_ASSUME: bb13: +; NO_ASSUME-NEXT: [[F_IBLOCK_LCSSA:%.*]] = phi i32* [ [[F_IBLOCK]], [[BB2]] ] +; NO_ASSUME-NEXT: [[TMP4_LE:%.*]] = ptrtoint i32* [[F_IBLOCK_LCSSA]] to i64 +; NO_ASSUME-NEXT: [[TMP8_LE:%.*]] = inttoptr i64 [[TMP4_LE]] to i32* +; NO_ASSUME-NEXT: call void @__msan_warning_noreturn() +; NO_ASSUME-NEXT: unreachable +; NO_ASSUME: bb15: +; NO_ASSUME-NEXT: br i1 [[TOBOOL]], label [[WHILE_END:%.*]], label [[WHILE_COND:%.*]] +; NO_ASSUME: while.end: +; NO_ASSUME-NEXT: ret void +; NO_ASSUME: indirectgoto: +; NO_ASSUME-NEXT: indirectbr i8* null, [label [[INDIRECTGOTO]], label %while.cond] +; +; USE_ASSUME-LABEL: @fn1( +; USE_ASSUME-NEXT: entry: +; USE_ASSUME-NEXT: br label [[INDIRECTGOTO:%.*]] +; USE_ASSUME: while.cond: +; USE_ASSUME-NEXT: [[TMP:%.*]] = load %struct.PyFrameObject*, %struct.PyFrameObject** @a, align 8 +; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "align"(i64* inttoptr (i64 and (i64 ptrtoint (%struct.PyFrameObject** @a to i64), i64 -70368744177665) to i64*), i64 8), "dereferenceable"(i64* inttoptr (i64 and (i64 ptrtoint (%struct.PyFrameObject** @a to i64), i64 -70368744177665) to i64*), i64 8), "nonnull"(i64* inttoptr (i64 and (i64 ptrtoint (%struct.PyFrameObject** @a to i64), i64 -70368744177665) to i64*)) ] +; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "align"(i32* inttoptr (i64 add (i64 and (i64 ptrtoint (%struct.PyFrameObject** @a to i64), i64 -70368744177665), i64 35184372088832) to i32*), i64 8), "dereferenceable"(i32* inttoptr (i64 add (i64 and (i64 ptrtoint (%struct.PyFrameObject** @a to i64), i64 -70368744177665), i64 35184372088832) to i32*), i64 4), "nonnull"(i32* inttoptr (i64 add (i64 and (i64 ptrtoint (%struct.PyFrameObject** @a to i64), i64 -70368744177665), i64 35184372088832) to i32*)) ] +; USE_ASSUME-NEXT: [[F_IBLOCK:%.*]] = getelementptr inbounds [[STRUCT_PYFRAMEOBJECT:%.*]], %struct.PyFrameObject* [[TMP]], i64 0, i32 0 +; USE_ASSUME-NEXT: br label [[BB2:%.*]] +; USE_ASSUME: bb: +; USE_ASSUME-NEXT: call void @__msan_warning_noreturn() +; USE_ASSUME-NEXT: unreachable +; USE_ASSUME: bb2: +; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "align"(i32* [[F_IBLOCK]], i64 4), "dereferenceable"(i32* [[F_IBLOCK]], i64 4), "nonnull"(i32* [[F_IBLOCK]]) ] +; USE_ASSUME-NEXT: [[TMP4:%.*]] = ptrtoint i32* [[F_IBLOCK]] to i64 +; USE_ASSUME-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[TMP4]], 0 +; USE_ASSUME-NEXT: br i1 [[TOBOOL]], label [[BB13:%.*]], label [[BB15:%.*]] +; USE_ASSUME: bb13: +; USE_ASSUME-NEXT: [[F_IBLOCK_LCSSA:%.*]] = phi i32* [ [[F_IBLOCK]], [[BB2]] ] +; USE_ASSUME-NEXT: [[TMP4_LE:%.*]] = ptrtoint i32* [[F_IBLOCK_LCSSA]] to i64 +; USE_ASSUME-NEXT: [[TMP8_LE:%.*]] = inttoptr i64 [[TMP4_LE]] to i32* +; USE_ASSUME-NEXT: call void @__msan_warning_noreturn() +; USE_ASSUME-NEXT: unreachable +; USE_ASSUME: bb15: +; USE_ASSUME-NEXT: br i1 [[TOBOOL]], label [[WHILE_END:%.*]], label [[WHILE_COND:%.*]] +; USE_ASSUME: while.end: +; USE_ASSUME-NEXT: ret void +; USE_ASSUME: indirectgoto: +; USE_ASSUME-NEXT: indirectbr i8* null, [label [[INDIRECTGOTO]], label %while.cond] +; entry: br label %indirectgoto @@ -31,8 +90,6 @@ br i1 %tobool, label %bb13, label %bb15 bb13: ; preds = %bb2 -; CHECK-LABEL: bb13: -; CHECK: %tmp8.le = inttoptr %.lcssa7 = phi i32* [ %tmp8, %bb2 ] call void @__msan_warning_noreturn() unreachable