diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -543,10 +543,17 @@ // Evaluate the BinOp on the incoming phi values. Value *CommonValue = nullptr; - for (Value *Incoming : PI->incoming_values()) { + for (unsigned u = 0, e = PI->getNumIncomingValues(); u < e; ++u) { + Value *Incoming = PI->getIncomingValue(u); + Instruction *InTI = PI->getIncomingBlock(u)->getTerminator(); // If the incoming value is the phi node itself, it can safely be skipped. if (Incoming == PI) continue; - Value *V = SimplifyCmpInst(Pred, Incoming, RHS, Q, MaxRecurse); + // Change the context instruction to the "edge" that flows into the phi. + // This is important because that is where incoming is actually "evaluated" + // even though it is used later somewhere else. + Value *V = SimplifyCmpInst( + Pred, Incoming, RHS, + {Q.DL, Q.TLI, Q.DT, Q.AC, InTI, Q.IIQ.UseInstrInfo}, MaxRecurse); // If the operation failed to simplify, or simplified to a different value // to previously, then give up. if (!V || (CommonValue && V != CommonValue)) 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 @@ -1902,8 +1902,8 @@ static bool isKnownNonNullFromDominatingCondition(const Value *V, const Instruction *CtxI, const DominatorTree *DT) { - assert(V->getType()->isPointerTy() && "V must be pointer type"); - assert(!isa(V) && "Did not expect ConstantPointerNull"); + if (isa(V)) + return false; if (!CtxI || !DT) return false; @@ -2078,12 +2078,11 @@ } } + if (isKnownNonNullFromDominatingCondition(V, Q.CxtI, Q.DT)) + return true; // Check for recursive pointer simplifications. if (V->getType()->isPointerTy()) { - if (isKnownNonNullFromDominatingCondition(V, Q.CxtI, Q.DT)) - return true; - // Look through bitcast operations, GEPs, and int2ptr instructions as they // do not alter the value, or at least not the nullness property of the // value, e.g., int2ptr is allowed to zero/sign extend the value. diff --git a/llvm/test/Transforms/InstCombine/known-non-zero.ll b/llvm/test/Transforms/InstCombine/known-non-zero.ll --- a/llvm/test/Transforms/InstCombine/known-non-zero.ll +++ b/llvm/test/Transforms/InstCombine/known-non-zero.ll @@ -13,7 +13,7 @@ ; CHECK-NEXT: [[C:%.*]] = icmp eq i64 [[X:%.*]], 0 ; CHECK-NEXT: br i1 [[C]], label [[EXIT:%.*]], label [[NON_ZERO:%.*]] ; CHECK: non_zero: -; CHECK-NEXT: [[CTZ:%.*]] = call i64 @llvm.cttz.i64(i64 [[X]], i1 false), !range !0 +; CHECK-NEXT: [[CTZ:%.*]] = call i64 @llvm.cttz.i64(i64 [[X]], i1 true), !range !0 ; CHECK-NEXT: [[CTZ32:%.*]] = trunc i64 [[CTZ]] to i32 ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: @@ -40,7 +40,7 @@ ; CHECK-NEXT: [[C:%.*]] = icmp eq i64 [[X:%.*]], 0 ; CHECK-NEXT: br i1 [[C]], label [[EXIT:%.*]], label [[NON_ZERO:%.*]] ; CHECK: non_zero: -; CHECK-NEXT: [[CTZ:%.*]] = call i64 @llvm.ctlz.i64(i64 [[X]], i1 false), !range !0 +; CHECK-NEXT: [[CTZ:%.*]] = call i64 @llvm.ctlz.i64(i64 [[X]], i1 true), !range !0 ; CHECK-NEXT: [[CTZ32:%.*]] = trunc i64 [[CTZ]] to i32 ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: @@ -91,3 +91,45 @@ %res = phi <8 x i64> [ %ctz, %non_zero ], [ zeroinitializer, %start ] ret <8 x i64> %res } + +; Test that exposed a bug in the PHI handling after D60846. +define void @D60846_misompile(i1* %p) { +; CHECK-LABEL: @D60846_misompile( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: [[I:%.*]] = phi i16 [ 0, [[ENTRY:%.*]] ], [ [[I_INC:%.*]], [[COMMON:%.*]] ] +; CHECK-NEXT: [[IS_ZERO:%.*]] = icmp eq i16 [[I]], 0 +; CHECK-NEXT: br i1 [[IS_ZERO]], label [[COMMON]], label [[NON_ZERO:%.*]] +; CHECK: non_zero: +; CHECK-NEXT: [[IS_ONE:%.*]] = icmp eq i16 [[I]], 1 +; CHECK-NEXT: store i1 [[IS_ONE]], i1* [[P:%.*]], align 1 +; CHECK-NEXT: br label [[COMMON]] +; CHECK: common: +; CHECK-NEXT: [[I_INC]] = add i16 [[I]], 1 +; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i16 [[I_INC]], 2 +; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + br label %loop + +loop: ; preds = %common, %entry + %i = phi i16 [ 0, %entry ], [ %i.inc, %common ] + %is_zero = icmp eq i16 %i, 0 + br i1 %is_zero, label %common, label %non_zero + +non_zero: ; preds = %loop + %is_one = icmp eq i16 %i, 1 + store i1 %is_one, i1* %p + br label %common + +common: ; preds = %non_zero, %loop + %i.inc = add i16 %i, 1 + %loop_cond = icmp ult i16 %i.inc, 2 + br i1 %loop_cond, label %loop, label %exit + +exit: ; preds = %common + ret void +} diff --git a/llvm/test/Transforms/InstSimplify/known-non-zero.ll b/llvm/test/Transforms/InstSimplify/known-non-zero.ll --- a/llvm/test/Transforms/InstSimplify/known-non-zero.ll +++ b/llvm/test/Transforms/InstSimplify/known-non-zero.ll @@ -7,8 +7,7 @@ ; CHECK-NEXT: [[A:%.*]] = icmp eq i64 [[X:%.*]], 0 ; CHECK-NEXT: br i1 [[A]], label [[EXIT:%.*]], label [[NON_ZERO:%.*]] ; CHECK: non_zero: -; CHECK-NEXT: [[B:%.*]] = icmp eq i64 [[X]], 0 -; CHECK-NEXT: br i1 [[B]], label [[UNREACHABLE:%.*]], label [[EXIT]] +; CHECK-NEXT: br i1 false, label [[UNREACHABLE:%.*]], label [[EXIT]] ; CHECK: unreachable: ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: @@ -37,8 +36,7 @@ ; CHECK-NEXT: [[A:%.*]] = icmp eq i64 [[X:%.*]], 0 ; CHECK-NEXT: br i1 [[A]], label [[EXIT:%.*]], label [[NON_ZERO:%.*]] ; CHECK: non_zero: -; CHECK-NEXT: [[B:%.*]] = icmp ugt i64 [[X]], 0 -; CHECK-NEXT: br i1 [[B]], label [[EXIT]], label [[UNREACHABLE:%.*]] +; CHECK-NEXT: br i1 true, label [[EXIT]], label [[UNREACHABLE:%.*]] ; CHECK: unreachable: ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: @@ -73,11 +71,9 @@ ; CHECK: two: ; CHECK-NEXT: br label [[MAINBLOCK]] ; CHECK: mainblock: -; CHECK-NEXT: [[P:%.*]] = phi i64 [ [[X]], [[ONE]] ], [ 42, [[TWO]] ] -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[P]], 0 ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: -; CHECK-NEXT: [[RES:%.*]] = phi i1 [ [[CMP]], [[MAINBLOCK]] ], [ true, [[START:%.*]] ] +; CHECK-NEXT: [[RES:%.*]] = phi i1 [ false, [[MAINBLOCK]] ], [ true, [[START:%.*]] ] ; CHECK-NEXT: ret i1 [[RES]] ; start: diff --git a/llvm/test/Transforms/LICM/hoist-mustexec.ll b/llvm/test/Transforms/LICM/hoist-mustexec.ll --- a/llvm/test/Transforms/LICM/hoist-mustexec.ll +++ b/llvm/test/Transforms/LICM/hoist-mustexec.ll @@ -129,8 +129,6 @@ } ; requires fact length is non-zero -; TODO: IsKnownNonNullFromDominatingConditions is currently only be done for -; pointers; should handle integers too define i32 @test4(i32* noalias nocapture readonly %a) nounwind uwtable { ; CHECK-LABEL: @test4( ; CHECK-NEXT: entry: @@ -138,6 +136,7 @@ ; CHECK-NEXT: [[IS_ZERO:%.*]] = icmp eq i32 [[LEN]], 0 ; CHECK-NEXT: br i1 [[IS_ZERO]], label [[FAIL:%.*]], label [[PREHEADER:%.*]] ; CHECK: preheader: +; CHECK-NEXT: [[I1:%.*]] = load i32, i32* [[A]], align 4 ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[PREHEADER]] ], [ [[INC:%.*]], [[CONTINUE:%.*]] ] @@ -145,7 +144,6 @@ ; CHECK-NEXT: [[R_CHK:%.*]] = icmp ult i32 [[IV]], [[LEN]] ; CHECK-NEXT: br i1 [[R_CHK]], label [[CONTINUE]], label [[FAIL_LOOPEXIT:%.*]] ; CHECK: continue: -; CHECK-NEXT: [[I1:%.*]] = load i32, i32* [[A]], align 4 ; CHECK-NEXT: [[ADD]] = add nsw i32 [[I1]], [[ACC]] ; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[IV]], 1 ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC]], 1000