diff --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h index 4b8cb3a39a86db..191d96cd289b04 100644 --- a/llvm/include/llvm/Analysis/ScalarEvolution.h +++ b/llvm/include/llvm/Analysis/ScalarEvolution.h @@ -1761,6 +1761,10 @@ class ScalarEvolution { /// V. const SCEV *getOperandsToCreate(Value *V, SmallVectorImpl &Ops); + /// Returns SCEV for the first operand of a phi if all phi operands have + /// identical opcodes and operands. + const SCEV *createNodeForPHIWithIdenticalOperands(PHINode *PN); + /// Provide the special handling we need to analyze PHI SCEVs. const SCEV *createNodeForPHI(PHINode *PN); diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp index b10811133770e1..a05e3e2cb42fee 100644 --- a/llvm/lib/Analysis/ScalarEvolution.cpp +++ b/llvm/lib/Analysis/ScalarEvolution.cpp @@ -6019,6 +6019,42 @@ const SCEV *ScalarEvolution::createNodeFromSelectLikePHI(PHINode *PN) { return nullptr; } +/// Returns SCEV for the first operand of a phi if all phi operands have +/// identical opcodes and operands +/// eg. +/// a: %add = %a + %b +/// br %c +/// b: %add1 = %a + %b +/// br %c +/// c: %phi = phi [%add, a], [%add1, b] +/// scev(%phi) => scev(%add) +const SCEV * +ScalarEvolution::createNodeForPHIWithIdenticalOperands(PHINode *PN) { + BinaryOperator *CommonInst = nullptr; + // Check if instructions are identical. + for (Value *Incoming : PN->incoming_values()) { + auto *IncomingInst = dyn_cast(Incoming); + if (!IncomingInst) + return nullptr; + if (CommonInst) { + if (!CommonInst->isIdenticalToWhenDefined(IncomingInst)) + return nullptr; // Not identical, give up + } else { + // Remember binary operator + CommonInst = IncomingInst; + } + } + if (!CommonInst) + return nullptr; + + // Check if SCEV exprs for instructions are identical. + const SCEV *CommonSCEV = getSCEV(CommonInst); + bool SCEVExprsIdentical = + all_of(drop_begin(PN->incoming_values()), + [this, CommonSCEV](Value *V) { return CommonSCEV == getSCEV(V); }); + return SCEVExprsIdentical ? CommonSCEV : nullptr; +} + const SCEV *ScalarEvolution::createNodeForPHI(PHINode *PN) { if (const SCEV *S = createAddRecFromPHI(PN)) return S; @@ -6030,6 +6066,9 @@ const SCEV *ScalarEvolution::createNodeForPHI(PHINode *PN) { /*UseInstrInfo=*/true, /*CanUseUndef=*/false})) return getSCEV(V); + if (const SCEV *S = createNodeForPHIWithIdenticalOperands(PN)) + return S; + if (const SCEV *S = createNodeFromSelectLikePHI(PN)) return S; diff --git a/llvm/test/Analysis/ScalarEvolution/trip-count-phi-increment.ll b/llvm/test/Analysis/ScalarEvolution/trip-count-phi-increment.ll new file mode 100644 index 00000000000000..db284b263d068c --- /dev/null +++ b/llvm/test/Analysis/ScalarEvolution/trip-count-phi-increment.ll @@ -0,0 +1,92 @@ +; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 5 +; RUN: opt < %s -disable-output "-passes=print" 2>&1 | FileCheck %s +define void @test1(ptr %x, ptr %y) { +; CHECK-LABEL: 'test1' +; CHECK-NEXT: Classifying expressions for: @test1 +; CHECK-NEXT: %v1.0 = phi i32 [ 0, %entry ], [ %k.0, %if.end ] +; CHECK-NEXT: --> {0,+,1}<%for.cond> U: [0,7) S: [0,7) Exits: 6 LoopDispositions: { %for.cond: Computable } +; CHECK-NEXT: %add = add nsw i32 %v1.0, 1 +; CHECK-NEXT: --> {1,+,1}<%for.cond> U: [1,8) S: [1,8) Exits: 7 LoopDispositions: { %for.cond: Computable } +; CHECK-NEXT: %add6 = add nsw i32 %v1.0, 1 +; CHECK-NEXT: --> {1,+,1}<%for.cond> U: [1,8) S: [1,8) Exits: 7 LoopDispositions: { %for.cond: Computable } +; CHECK-NEXT: %k.0 = phi i32 [ %add, %if.then ], [ %add6, %if.else ] +; CHECK-NEXT: --> {1,+,1}<%for.cond> U: [1,8) S: [1,8) Exits: 7 LoopDispositions: { %for.cond: Computable } +; CHECK-NEXT: Determining loop execution counts for: @test1 +; CHECK-NEXT: Loop %for.cond: backedge-taken count is i32 6 +; CHECK-NEXT: Loop %for.cond: constant max backedge-taken count is i32 6 +; CHECK-NEXT: Loop %for.cond: symbolic max backedge-taken count is i32 6 +; CHECK-NEXT: Loop %for.cond: Trip multiple is 7 +; +entry: + br label %for.cond + +for.cond: ; preds = %6, %0 + %v1.0 = phi i32 [ 0, %entry ], [ %k.0, %if.end ] + %cmp = icmp slt i32 %v1.0, 6 + br i1 %cmp, label %for.body, label %exit + +for.body: ; preds = %1 + %cmp3 = icmp slt i32 %v1.0, 2 + br i1 %cmp3, label %if.then, label %if.else + +if.then: ; preds = %2 + %add = add nsw i32 %v1.0, 1 + br label %if.end + +if.else: ; preds = %2 + %add6 = add nsw i32 %v1.0, 1 + br label %if.end + +if.end: ; preds = %4, %3 + %k.0 = phi i32 [ %add, %if.then ], [ %add6, %if.else ] + br label %for.cond + +exit: ; preds = %5 + ret void +} + +define void @test2(ptr %x, ptr %y) { +; CHECK-LABEL: 'test2' +; CHECK-NEXT: Classifying expressions for: @test2 +; CHECK-NEXT: %v1.0 = phi i32 [ 0, %entry ], [ %k.0, %if.end ] +; CHECK-NEXT: --> {0,+,1}<%for.cond> U: [0,7) S: [0,7) Exits: 6 LoopDispositions: { %for.cond: Computable } +; CHECK-NEXT: %add = add nuw i32 %v1.0, 1 +; CHECK-NEXT: --> {1,+,1}<%for.cond> U: [1,8) S: [1,8) Exits: 7 LoopDispositions: { %for.cond: Computable } +; CHECK-NEXT: %add6 = add nsw i32 %v1.0, 1 +; CHECK-NEXT: --> {1,+,1}<%for.cond> U: [1,8) S: [1,8) Exits: 7 LoopDispositions: { %for.cond: Computable } +; CHECK-NEXT: %k.0 = phi i32 [ %add, %if.then ], [ %add6, %if.else ] +; CHECK-NEXT: --> {1,+,1}<%for.cond> U: [1,8) S: [1,8) Exits: 7 LoopDispositions: { %for.cond: Computable } +; CHECK-NEXT: Determining loop execution counts for: @test2 +; CHECK-NEXT: Loop %for.cond: backedge-taken count is i32 6 +; CHECK-NEXT: Loop %for.cond: constant max backedge-taken count is i32 6 +; CHECK-NEXT: Loop %for.cond: symbolic max backedge-taken count is i32 6 +; CHECK-NEXT: Loop %for.cond: Trip multiple is 7 +; +entry: + br label %for.cond + +for.cond: ; preds = %6, %0 + %v1.0 = phi i32 [ 0, %entry ], [ %k.0, %if.end ] + %cmp = icmp slt i32 %v1.0, 6 + br i1 %cmp, label %for.body, label %exit + +for.body: ; preds = %1 + %cmp3 = icmp slt i32 %v1.0, 2 + br i1 %cmp3, label %if.then, label %if.else + +if.then: ; preds = %2 + %add = add nuw i32 %v1.0, 1 + br label %if.end + +if.else: ; preds = %2 + %add6 = add nsw i32 %v1.0, 1 + br label %if.end + +if.end: ; preds = %4, %3 + %k.0 = phi i32 [ %add, %if.then ], [ %add6, %if.else ] + br label %for.cond + +exit: ; preds = %5 + ret void +} +