diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index f510f6a42f08c..c303d261107eb 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -3122,6 +3122,25 @@ static bool isNonEqualPHIs(const PHINode *PN1, const PHINode *PN2, return true; } +static bool isNonEqualSelect(const Value *V1, const Value *V2, unsigned Depth, + const SimplifyQuery &Q) { + const SelectInst *SI1 = dyn_cast(V1); + if (!SI1) + return false; + + if (const SelectInst *SI2 = dyn_cast(V2)) { + const Value *Cond1 = SI1->getCondition(); + const Value *Cond2 = SI2->getCondition(); + if (Cond1 == Cond2) + return isKnownNonEqual(SI1->getTrueValue(), SI2->getTrueValue(), + Depth + 1, Q) && + isKnownNonEqual(SI1->getFalseValue(), SI2->getFalseValue(), + Depth + 1, Q); + } + return isKnownNonEqual(SI1->getTrueValue(), V2, Depth + 1, Q) && + isKnownNonEqual(SI1->getFalseValue(), V2, Depth + 1, Q); +} + /// Return true if it is known that V1 != V2. static bool isKnownNonEqual(const Value *V1, const Value *V2, unsigned Depth, const SimplifyQuery &Q) { @@ -3171,6 +3190,10 @@ static bool isKnownNonEqual(const Value *V1, const Value *V2, unsigned Depth, Known2.Zero.intersects(Known1.One)) return true; } + + if (isNonEqualSelect(V1, V2, Depth, Q) || isNonEqualSelect(V2, V1, Depth, Q)) + return true; + return false; } diff --git a/llvm/test/Analysis/BasicAA/non-equal-select.ll b/llvm/test/Analysis/BasicAA/non-equal-select.ll new file mode 100644 index 0000000000000..fe38a57eeb1b4 --- /dev/null +++ b/llvm/test/Analysis/BasicAA/non-equal-select.ll @@ -0,0 +1,79 @@ +; RUN: opt < %s -aa-pipeline=basic-aa -passes=aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s +@G = global [10 x i32] zeroinitializer, align 4 + +define void @select_in_gep1(i1 %c, i64 %x) { +entry: +; CHECK-LABEL: Function: select_in_gep1 +; CHECK: NoAlias: i32* %arrayidx1, i32* %arrayidx2 + %add1_ = add nsw i64 %x, 1 + %add2_ = add nsw i64 %x, 2 + %select_ = select i1 %c, i64 %add1_, i64 %add2_ + %arrayidx1 = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %select_ + store i32 42, ptr %arrayidx1, align 4 + %arrayidx2 = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %x + store i32 43, ptr %arrayidx2, align 4 + ret void +} + +define void @select_in_gep2(i1 %c, i64 %x) { +entry: + ; TODO: should be "NoAlias" here as well. +; CHECK-LABEL: Function: select_in_gep2 +; CHECK: MayAlias: i32* %arrayidx1, i32* %arrayidx2 + %add1_ = add nsw i64 %x, 1 + %add2_ = add nsw i64 %x, 2 + %add3_ = add nsw i64 %x, 3 + %select_ = select i1 %c, i64 %add1_, i64 %add2_ + %arrayidx1 = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %select_ + store i32 42, ptr %arrayidx1, align 4 + %arrayidx2 = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %add3_ + store i32 43, ptr %arrayidx2, align 4 + ret void +} + +define void @two_selects_in_gep_same_cond(i1 %c, i64 %x) { +entry: +; CHECK-LABEL: Function: two_selects_in_gep_same_cond +; CHECK: NoAlias: i32* %arrayidx1, i32* %arrayidx2 + %add1_ = add nsw i64 %x, 1 + %add2_ = add nsw i64 %x, 2 + %select1_ = select i1 %c, i64 %x, i64 %add1_ + %select2_ = select i1 %c, i64 %add2_, i64 %x + %arrayidx1 = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %select1_ + store i32 42, ptr %arrayidx1, align 4 + %arrayidx2 = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %select2_ + store i32 43, ptr %arrayidx2, align 4 + ret void +} + +define void @two_selects_in_gep_different_cond1(i1 %c1, i1 %c2, i64 %x) { +entry: +; CHECK-LABEL: Function: two_selects_in_gep_different_cond1 +; CHECK: NoAlias: i32* %arrayidx1, i32* %arrayidx2 + %add1_ = add nsw i64 %x, 1 + %add2_ = add nsw i64 %x, 2 + %add3_ = add nsw i64 %x, 3 + %add4_ = add nsw i64 %x, 4 + %select1_ = select i1 %c1, i64 %add1_, i64 %add2_ + %select2_ = select i1 %c2, i64 %add3_, i64 %add4_ + %arrayidx1 = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %select1_ + store i32 42, ptr %arrayidx1, align 4 + %arrayidx2 = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %select2_ + store i32 43, ptr %arrayidx2, align 4 + ret void +} + +define void @two_selects_in_gep_different_cond2(i1 %c1, i1 %c2, i64 %x) { +entry: +; CHECK-LABEL: Function: two_selects_in_gep_different_cond2 +; CHECK: MayAlias: i32* %arrayidx1, i32* %arrayidx2 + %add1_ = add nsw i64 %x, 1 + %add2_ = add nsw i64 %x, 2 + %select1_ = select i1 %c1, i64 %x, i64 %add1_ + %select2_ = select i1 %c2, i64 %x, i64 %add2_ + %arrayidx1 = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %select1_ + store i32 42, ptr %arrayidx1, align 4 + %arrayidx2 = getelementptr inbounds [10 x i32], ptr @G, i64 0, i64 %select2_ + store i32 43, ptr %arrayidx2, align 4 + ret void +}