diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -1480,7 +1480,17 @@ Pred = CmpInst::getInversePredicate(Pred); // Get the knownbits implied by the incoming phi condition. auto CR = ConstantRange::makeExactICmpRegion(Pred, *RHSC); - Known2 = Known2.unionWith(CR.toKnownBits()); + KnownBits KnownUnion = Known2.unionWith(CR.toKnownBits()); + // We can have conflicts here if we are analyzing deadcode (its + // impossible for us reach this BB based the icmp). + if (KnownUnion.hasConflict()) { + // No reason to continue analyzing in a known dead region, so + // just resetAll and break. This will cause us to also exit the + // outer loop. + Known.resetAll(); + break; + } + Known2 = KnownUnion; } } } diff --git a/llvm/test/Analysis/ValueTracking/knownbits-phi-deadcode.ll b/llvm/test/Analysis/ValueTracking/knownbits-phi-deadcode.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Analysis/ValueTracking/knownbits-phi-deadcode.ll @@ -0,0 +1,107 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 +; RUN: opt -passes=loop-deletion -S < %s | FileCheck %s +; This reduced testcase from pr65022. We are only testing that is doesn't crash. + +@b = internal unnamed_addr global i1 false + +define void @f(i32 %spec.select, ptr nocapture writeonly %c, i1 %tobool.not) local_unnamed_addr { +; CHECK-LABEL: define void @f +; CHECK-SAME: (i32 [[SPEC_SELECT:%.*]], ptr nocapture writeonly [[C:%.*]], i1 [[TOBOOL_NOT:%.*]]) local_unnamed_addr { +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TOBOOL2_NOT:%.*]] = icmp eq i32 [[SPEC_SELECT]], 0 +; CHECK-NEXT: br label [[L_OUTER:%.*]] +; CHECK: L.outer: +; CHECK-NEXT: [[I_0_PH:%.*]] = phi i32 [ 1, [[WHILE_COND:%.*]] ], [ 0, [[ENTRY:%.*]] ] +; CHECK-NEXT: br label [[L:%.*]] +; CHECK: L: +; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[IF_END:%.*]], label [[IF_THEN:%.*]] +; CHECK: if.then: +; CHECK-NEXT: store i32 0, ptr [[C]], align 4 +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: [[DOTB:%.*]] = load i1, ptr @b, align 1 +; CHECK-NEXT: [[TMP0:%.*]] = select i1 [[DOTB]], i32 0, i32 1 +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP0]], -1 +; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN1:%.*]], label [[WHILE_COND_SPLIT_LOOP_EXIT1:%.*]] +; CHECK: if.then1: +; CHECK-NEXT: br i1 [[TOBOOL2_NOT]], label [[WHILE_COND_LOOPEXIT:%.*]], label [[IF_THEN3:%.*]] +; CHECK: if.then3: +; CHECK-NEXT: call void (...) @e() +; CHECK-NEXT: br label [[L]] +; CHECK: while.cond.split.loop.exit1: +; CHECK-NEXT: [[DOTLCSSA:%.*]] = phi i32 [ [[TMP0]], [[IF_END]] ] +; CHECK-NEXT: [[NOT_LE:%.*]] = xor i32 [[DOTLCSSA]], 1 +; CHECK-NEXT: br label [[WHILE_COND]] +; CHECK: while.cond.loopexit: +; CHECK-NEXT: br label [[WHILE_COND]] +; CHECK: while.cond: +; CHECK-NEXT: [[H_02:%.*]] = phi i32 [ [[NOT_LE]], [[WHILE_COND_SPLIT_LOOP_EXIT1]] ], [ 0, [[WHILE_COND_LOOPEXIT]] ] +; CHECK-NEXT: [[TOBOOL7_NOT:%.*]] = icmp eq i32 [[H_02]], 0 +; CHECK-NEXT: [[SPEC_SELECT3:%.*]] = select i1 [[TOBOOL7_NOT]], i32 [[I_0_PH]], i32 [[SPEC_SELECT]] +; CHECK-NEXT: [[TOBOOL10_NOT:%.*]] = icmp eq i32 [[SPEC_SELECT3]], 0 +; CHECK-NEXT: br i1 [[TOBOOL10_NOT]], label [[FOR_COND_PREHEADER:%.*]], label [[L_OUTER]] +; CHECK: for.cond.preheader: +; CHECK-NEXT: [[TOBOOL13_NOT3:%.*]] = icmp eq i32 [[SPEC_SELECT]], 0 +; CHECK-NEXT: br i1 [[TOBOOL13_NOT3]], label [[FOR_END:%.*]], label [[FOR_COND_FOR_END_CRIT_EDGE:%.*]] +; CHECK: for.cond.for.end_crit_edge: +; CHECK-NEXT: store i1 true, ptr @b, align 1 +; CHECK-NEXT: br label [[FOR_END]] +; CHECK: for.end: +; CHECK-NEXT: ret void +; +entry: + %tobool2.not = icmp eq i32 %spec.select, 0 + br label %L.outer + +L.outer: ; preds = %while.cond, %entry + %i.0.ph = phi i32 [ 1, %while.cond ], [ 0, %entry ] + br label %L + +L: ; preds = %if.then3, %L.outer + br i1 %tobool.not, label %if.end, label %if.then + +if.then: ; preds = %L + store i32 0, ptr %c, align 4 + br label %if.end + +if.end: ; preds = %if.then, %L + %.b = load i1, ptr @b, align 1 + %0 = select i1 %.b, i32 0, i32 1 + %cmp = icmp sgt i32 %0, -1 + br i1 %cmp, label %if.then1, label %while.cond.split.loop.exit1 + +if.then1: ; preds = %if.end + br i1 %tobool2.not, label %while.cond.loopexit, label %if.then3 + +if.then3: ; preds = %if.then1 + call void(...) @e() + br label %L + +while.cond.split.loop.exit1: ; preds = %if.end + %.lcssa = phi i32 [ %0, %if.end ] + %not.le = xor i32 %.lcssa, 1 + br label %while.cond + +while.cond.loopexit: ; preds = %if.then1 + br label %while.cond + +while.cond: ; preds = %while.cond.loopexit, %while.cond.split.loop.exit1 + %h.02 = phi i32 [ %not.le, %while.cond.split.loop.exit1 ], [ 0, %while.cond.loopexit ] + %tobool7.not = icmp eq i32 %h.02, 0 + %spec.select3 = select i1 %tobool7.not, i32 %i.0.ph, i32 %spec.select + %tobool10.not = icmp eq i32 %spec.select3, 0 + br i1 %tobool10.not, label %for.cond.preheader, label %L.outer + +for.cond.preheader: ; preds = %while.cond + %tobool13.not3 = icmp eq i32 %spec.select, 0 + br i1 %tobool13.not3, label %for.end, label %for.cond.for.end_crit_edge + +for.cond.for.end_crit_edge: ; preds = %for.cond.preheader + store i1 true, ptr @b, align 1 + br label %for.end + +for.end: ; preds = %for.cond.for.end_crit_edge, %for.cond.preheader + ret void +} + +declare void @e(...) local_unnamed_addr