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