From: Michael Zolotukhin Date: Wed, 3 May 2017 23:53:38 +0000 (+0000) Subject: [SCEV] createAddRecFromPHI: Optimize for the most common case. X-Git-Tag: llvmorg-5.0.0-rc1~6011 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=37162adf3eebd7b29eb73ec26d0d3bc96686be54;p=platform%2Fupstream%2Fllvm.git [SCEV] createAddRecFromPHI: Optimize for the most common case. Summary: The existing implementation creates a symbolic SCEV expression every time we analyze a phi node and then has to remove it, when the analysis is finished. This is very expensive, and in most of the cases it's also unnecessary. According to the data I collected, ~60-70% of analyzed phi nodes (measured on SPEC) have the following form: PN = phi(Start, OP(Self, Constant)) Handling such cases separately significantly speeds this up. Reviewers: sanjoy, pete Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32663 llvm-svn: 302096 --- diff --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h index 54bc4dc..18fee31 100644 --- a/llvm/include/llvm/Analysis/ScalarEvolution.h +++ b/llvm/include/llvm/Analysis/ScalarEvolution.h @@ -816,6 +816,10 @@ private: /// Helper function called from createNodeForPHI. const SCEV *createAddRecFromPHI(PHINode *PN); + /// A helper function for createAddRecFromPHI to handle simple cases. + const SCEV *createSimpleAffineAddRec(PHINode *PN, Value *BEValueV, + Value *StartValueV); + /// Helper function called from createNodeForPHI. const SCEV *createNodeFromSelectLikePHI(PHINode *PN); diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp index bd747f7..38f740b 100644 --- a/llvm/lib/Analysis/ScalarEvolution.cpp +++ b/llvm/lib/Analysis/ScalarEvolution.cpp @@ -4083,6 +4083,56 @@ static Optional MatchBinaryOp(Value *V, DominatorTree &DT) { return None; } +/// A helper function for createAddRecFromPHI to handle simple cases. +/// +/// This function tries to find an AddRec expression for the simplest (yet most +/// common) cases: PN = PHI(Start, OP(Self, LoopInvariant)). +/// If it fails, createAddRecFromPHI will use a more general, but slow, +/// technique for finding the AddRec expression. +const SCEV *ScalarEvolution::createSimpleAffineAddRec(PHINode *PN, + Value *BEValueV, + Value *StartValueV) { + const Loop *L = LI.getLoopFor(PN->getParent()); + assert(L && L->getHeader() == PN->getParent()); + assert(BEValueV && StartValueV); + + auto BO = MatchBinaryOp(BEValueV, DT); + if (!BO) + return nullptr; + + if (BO->Opcode != Instruction::Add) + return nullptr; + + const SCEV *Accum = nullptr; + if (BO->LHS == PN && L->isLoopInvariant(BO->RHS)) + Accum = getSCEV(BO->RHS); + else if (BO->RHS == PN && L->isLoopInvariant(BO->LHS)) + Accum = getSCEV(BO->LHS); + + if (!Accum) + return nullptr; + + SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap; + if (BO->IsNUW) + Flags = setFlags(Flags, SCEV::FlagNUW); + if (BO->IsNSW) + Flags = setFlags(Flags, SCEV::FlagNSW); + + const SCEV *StartVal = getSCEV(StartValueV); + const SCEV *PHISCEV = getAddRecExpr(StartVal, Accum, L, Flags); + + ValueExprMap[SCEVCallbackVH(PN, this)] = PHISCEV; + + // We can add Flags to the post-inc expression only if we + // know that it us *undefined behavior* for BEValueV to + // overflow. + if (auto *BEInst = dyn_cast(BEValueV)) + if (isLoopInvariant(Accum, L) && isAddRecNeverPoison(BEInst, L)) + (void)getAddRecExpr(getAddExpr(StartVal, Accum), Accum, L, Flags); + + return PHISCEV; +} + const SCEV *ScalarEvolution::createAddRecFromPHI(PHINode *PN) { const Loop *L = LI.getLoopFor(PN->getParent()); if (!L || L->getHeader() != PN->getParent()) @@ -4111,10 +4161,16 @@ const SCEV *ScalarEvolution::createAddRecFromPHI(PHINode *PN) { if (!BEValueV || !StartValueV) return nullptr; - // While we are analyzing this PHI node, handle its value symbolically. - const SCEV *SymbolicName = getUnknown(PN); assert(ValueExprMap.find_as(PN) == ValueExprMap.end() && "PHI node already processed?"); + + // First, try to find AddRec expression without creating a fictituos symbolic + // value for PN. + if (auto *S = createSimpleAffineAddRec(PN, BEValueV, StartValueV)) + return S; + + // Handle PHI node value symbolically. + const SCEV *SymbolicName = getUnknown(PN); ValueExprMap.insert({SCEVCallbackVH(PN, this), SymbolicName}); // Using this symbolic name for the PHI, analyze the value coming around diff --git a/llvm/test/Analysis/ScalarEvolution/ZeroStep.ll b/llvm/test/Analysis/ScalarEvolution/ZeroStep.ll new file mode 100644 index 0000000..fc6ed01 --- /dev/null +++ b/llvm/test/Analysis/ScalarEvolution/ZeroStep.ll @@ -0,0 +1,18 @@ +; RUN: opt -analyze -scalar-evolution < %s -o - -S | FileCheck %s + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.9.0" + +; Test that SCEV is capable of figuring out value of 'IV' that actually does not change. +; CHECK: Classifying expressions for: @foo +; CHECK: %iv.i = phi i64 +; CHECK: -5 U: [-5,-4) S: [-5,-4) Exits: -5 LoopDispositions: { %loop: Invariant } +define void @foo() { +entry: + br label %loop + +loop: + %iv.i = phi i64 [ -5, %entry ], [ %iv.next.i, %loop ] + %iv.next.i = add nsw i64 %iv.i, 0 + br label %loop +} diff --git a/llvm/test/CodeGen/X86/2014-08-29-CompactUnwind.ll b/llvm/test/CodeGen/X86/2014-08-29-CompactUnwind.ll index e7e8bb7..f6d6bd3 100644 --- a/llvm/test/CodeGen/X86/2014-08-29-CompactUnwind.ll +++ b/llvm/test/CodeGen/X86/2014-08-29-CompactUnwind.ll @@ -24,7 +24,7 @@ target triple = "x86_64-apple-macosx10.9.0" ; CHECK-NOT: {{compact encoding:.*0x0309f800}} ; CHECK: {{compact encoding:.*0x030df800}} -define void @__asan_report_error() #0 { +define void @__asan_report_error(i64 %step) #0 { %str.i = alloca i64, align 8 %stack = alloca [256 x i64], align 8 br label %print_shadow_bytes.exit.i @@ -37,7 +37,7 @@ print_shadow_bytes.exit.i: ; preds = %print_shadow_bytes.exit.i, %0 %reg17 = shl i64 %iv.i, 1 %reg19 = inttoptr i64 %reg17 to i8* call void (i64*, i8*, ...) @append(i64* %str.i, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str2, i64 0, i64 0), i8* %reg16, i8* %reg19) - %iv.next.i = add nsw i64 %iv.i, 0 + %iv.next.i = add nsw i64 %iv.i, %step br label %print_shadow_bytes.exit.i }