13ca95b02SDimitry Andric //===- ScalarEvolutionNormalization.cpp - See below -----------------------===//
2f22ef01cSRoman Divacky //
3f22ef01cSRoman Divacky //                     The LLVM Compiler Infrastructure
4f22ef01cSRoman Divacky //
5f22ef01cSRoman Divacky // This file is distributed under the University of Illinois Open Source
6f22ef01cSRoman Divacky // License. See LICENSE.TXT for details.
7f22ef01cSRoman Divacky //
8f22ef01cSRoman Divacky //===----------------------------------------------------------------------===//
9f22ef01cSRoman Divacky //
10f22ef01cSRoman Divacky // This file implements utilities for working with "normalized" expressions.
11f22ef01cSRoman Divacky // See the comments at the top of ScalarEvolutionNormalization.h for details.
12f22ef01cSRoman Divacky //
13f22ef01cSRoman Divacky //===----------------------------------------------------------------------===//
14f22ef01cSRoman Divacky 
15*db17bf38SDimitry Andric #include "llvm/Analysis/ScalarEvolutionNormalization.h"
16f22ef01cSRoman Divacky #include "llvm/Analysis/LoopInfo.h"
17f22ef01cSRoman Divacky #include "llvm/Analysis/ScalarEvolutionExpressions.h"
18f22ef01cSRoman Divacky using namespace llvm;
19f22ef01cSRoman Divacky 
207a7e6055SDimitry Andric /// TransformKind - Different types of transformations that
217a7e6055SDimitry Andric /// TransformForPostIncUse can do.
227a7e6055SDimitry Andric enum TransformKind {
237a7e6055SDimitry Andric   /// Normalize - Normalize according to the given loops.
247a7e6055SDimitry Andric   Normalize,
257a7e6055SDimitry Andric   /// Denormalize - Perform the inverse transform on the expression with the
267a7e6055SDimitry Andric   /// given loop set.
277a7e6055SDimitry Andric   Denormalize
286122f3e6SDimitry Andric };
296122f3e6SDimitry Andric 
307a7e6055SDimitry Andric namespace {
317a7e6055SDimitry Andric struct NormalizeDenormalizeRewriter
327a7e6055SDimitry Andric     : public SCEVRewriteVisitor<NormalizeDenormalizeRewriter> {
337a7e6055SDimitry Andric   const TransformKind Kind;
347a7e6055SDimitry Andric 
357a7e6055SDimitry Andric   // NB! Pred is a function_ref.  Storing it here is okay only because
367a7e6055SDimitry Andric   // we're careful about the lifetime of NormalizeDenormalizeRewriter.
377a7e6055SDimitry Andric   const NormalizePredTy Pred;
387a7e6055SDimitry Andric 
NormalizeDenormalizeRewriter__anon9528d84a0111::NormalizeDenormalizeRewriter397a7e6055SDimitry Andric   NormalizeDenormalizeRewriter(TransformKind Kind, NormalizePredTy Pred,
407a7e6055SDimitry Andric                                ScalarEvolution &SE)
417a7e6055SDimitry Andric       : SCEVRewriteVisitor<NormalizeDenormalizeRewriter>(SE), Kind(Kind),
427a7e6055SDimitry Andric         Pred(Pred) {}
437a7e6055SDimitry Andric   const SCEV *visitAddRecExpr(const SCEVAddRecExpr *Expr);
447a7e6055SDimitry Andric };
456122f3e6SDimitry Andric } // namespace
466122f3e6SDimitry Andric 
477a7e6055SDimitry Andric const SCEV *
visitAddRecExpr(const SCEVAddRecExpr * AR)487a7e6055SDimitry Andric NormalizeDenormalizeRewriter::visitAddRecExpr(const SCEVAddRecExpr *AR) {
49e580952dSDimitry Andric   SmallVector<const SCEV *, 8> Operands;
507a7e6055SDimitry Andric 
517a7e6055SDimitry Andric   transform(AR->operands(), std::back_inserter(Operands),
527a7e6055SDimitry Andric             [&](const SCEV *Op) { return visit(Op); });
537a7e6055SDimitry Andric 
5451690af2SDimitry Andric   if (!Pred(AR))
5551690af2SDimitry Andric     return SE.getAddRecExpr(Operands, AR->getLoop(), SCEV::FlagAnyWrap);
5651690af2SDimitry Andric 
5751690af2SDimitry Andric   // Normalization and denormalization are fancy names for decrementing and
5851690af2SDimitry Andric   // incrementing a SCEV expression with respect to a set of loops.  Since
5951690af2SDimitry Andric   // Pred(AR) has returned true, we know we need to normalize or denormalize AR
6051690af2SDimitry Andric   // with respect to its loop.
6151690af2SDimitry Andric 
6251690af2SDimitry Andric   if (Kind == Denormalize) {
6351690af2SDimitry Andric     // Denormalization / "partial increment" is essentially the same as \c
6451690af2SDimitry Andric     // SCEVAddRecExpr::getPostIncExpr.  Here we use an explicit loop to make the
6551690af2SDimitry Andric     // symmetry with Normalization clear.
6651690af2SDimitry Andric     for (int i = 0, e = Operands.size() - 1; i < e; i++)
6751690af2SDimitry Andric       Operands[i] = SE.getAddExpr(Operands[i], Operands[i + 1]);
6851690af2SDimitry Andric   } else {
6951690af2SDimitry Andric     assert(Kind == Normalize && "Only two possibilities!");
7051690af2SDimitry Andric 
7151690af2SDimitry Andric     // Normalization / "partial decrement" is a bit more subtle.  Since
7251690af2SDimitry Andric     // incrementing a SCEV expression (in general) changes the step of the SCEV
7351690af2SDimitry Andric     // expression as well, we cannot use the step of the current expression.
7451690af2SDimitry Andric     // Instead, we have to use the step of the very expression we're trying to
7551690af2SDimitry Andric     // compute!
7691bc56edSDimitry Andric     //
7751690af2SDimitry Andric     // We solve the issue by recursively building up the result, starting from
7851690af2SDimitry Andric     // the "least significant" operand in the add recurrence:
7951690af2SDimitry Andric     //
8051690af2SDimitry Andric     // Base case:
8151690af2SDimitry Andric     //   Single operand add recurrence.  It's its own normalization.
8251690af2SDimitry Andric     //
8351690af2SDimitry Andric     // N-operand case:
8451690af2SDimitry Andric     //   {S_{N-1},+,S_{N-2},+,...,+,S_0} = S
8551690af2SDimitry Andric     //
8651690af2SDimitry Andric     //   Since the step recurrence of S is {S_{N-2},+,...,+,S_0}, we know its
8751690af2SDimitry Andric     //   normalization by induction.  We subtract the normalized step
8851690af2SDimitry Andric     //   recurrence from S_{N-1} to get the normalization of S.
8951690af2SDimitry Andric 
9051690af2SDimitry Andric     for (int i = Operands.size() - 2; i >= 0; i--)
9151690af2SDimitry Andric       Operands[i] = SE.getMinusSCEV(Operands[i], Operands[i + 1]);
92f22ef01cSRoman Divacky   }
9351690af2SDimitry Andric 
9451690af2SDimitry Andric   return SE.getAddRecExpr(Operands, AR->getLoop(), SCEV::FlagAnyWrap);
95f22ef01cSRoman Divacky }
96e580952dSDimitry Andric 
normalizeForPostIncUse(const SCEV * S,const PostIncLoopSet & Loops,ScalarEvolution & SE)977a7e6055SDimitry Andric const SCEV *llvm::normalizeForPostIncUse(const SCEV *S,
987a7e6055SDimitry Andric                                          const PostIncLoopSet &Loops,
997a7e6055SDimitry Andric                                          ScalarEvolution &SE) {
1007a7e6055SDimitry Andric   auto Pred = [&](const SCEVAddRecExpr *AR) {
1017a7e6055SDimitry Andric     return Loops.count(AR->getLoop());
1027a7e6055SDimitry Andric   };
1037a7e6055SDimitry Andric   return NormalizeDenormalizeRewriter(Normalize, Pred, SE).visit(S);
104f22ef01cSRoman Divacky }
105e580952dSDimitry Andric 
normalizeForPostIncUseIf(const SCEV * S,NormalizePredTy Pred,ScalarEvolution & SE)1067a7e6055SDimitry Andric const SCEV *llvm::normalizeForPostIncUseIf(const SCEV *S, NormalizePredTy Pred,
1077a7e6055SDimitry Andric                                            ScalarEvolution &SE) {
1087a7e6055SDimitry Andric   return NormalizeDenormalizeRewriter(Normalize, Pred, SE).visit(S);
109f22ef01cSRoman Divacky }
110e580952dSDimitry Andric 
denormalizeForPostIncUse(const SCEV * S,const PostIncLoopSet & Loops,ScalarEvolution & SE)1117a7e6055SDimitry Andric const SCEV *llvm::denormalizeForPostIncUse(const SCEV *S,
1127a7e6055SDimitry Andric                                            const PostIncLoopSet &Loops,
1137a7e6055SDimitry Andric                                            ScalarEvolution &SE) {
1147a7e6055SDimitry Andric   auto Pred = [&](const SCEVAddRecExpr *AR) {
1157a7e6055SDimitry Andric     return Loops.count(AR->getLoop());
1167a7e6055SDimitry Andric   };
1177a7e6055SDimitry Andric   return NormalizeDenormalizeRewriter(Denormalize, Pred, SE).visit(S);
1186122f3e6SDimitry Andric }
119