1*0b57cec5SDimitry Andric //===- ScalarEvolutionNormalization.cpp - See below -----------------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This file implements utilities for working with "normalized" expressions. 10*0b57cec5SDimitry Andric // See the comments at the top of ScalarEvolutionNormalization.h for details. 11*0b57cec5SDimitry Andric // 12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 13*0b57cec5SDimitry Andric 14*0b57cec5SDimitry Andric #include "llvm/Analysis/ScalarEvolutionNormalization.h" 15*0b57cec5SDimitry Andric #include "llvm/Analysis/LoopInfo.h" 16*0b57cec5SDimitry Andric #include "llvm/Analysis/ScalarEvolutionExpressions.h" 17*0b57cec5SDimitry Andric using namespace llvm; 18*0b57cec5SDimitry Andric 19*0b57cec5SDimitry Andric /// TransformKind - Different types of transformations that 20*0b57cec5SDimitry Andric /// TransformForPostIncUse can do. 21*0b57cec5SDimitry Andric enum TransformKind { 22*0b57cec5SDimitry Andric /// Normalize - Normalize according to the given loops. 23*0b57cec5SDimitry Andric Normalize, 24*0b57cec5SDimitry Andric /// Denormalize - Perform the inverse transform on the expression with the 25*0b57cec5SDimitry Andric /// given loop set. 26*0b57cec5SDimitry Andric Denormalize 27*0b57cec5SDimitry Andric }; 28*0b57cec5SDimitry Andric 29*0b57cec5SDimitry Andric namespace { 30*0b57cec5SDimitry Andric struct NormalizeDenormalizeRewriter 31*0b57cec5SDimitry Andric : public SCEVRewriteVisitor<NormalizeDenormalizeRewriter> { 32*0b57cec5SDimitry Andric const TransformKind Kind; 33*0b57cec5SDimitry Andric 34*0b57cec5SDimitry Andric // NB! Pred is a function_ref. Storing it here is okay only because 35*0b57cec5SDimitry Andric // we're careful about the lifetime of NormalizeDenormalizeRewriter. 36*0b57cec5SDimitry Andric const NormalizePredTy Pred; 37*0b57cec5SDimitry Andric 38*0b57cec5SDimitry Andric NormalizeDenormalizeRewriter(TransformKind Kind, NormalizePredTy Pred, 39*0b57cec5SDimitry Andric ScalarEvolution &SE) 40*0b57cec5SDimitry Andric : SCEVRewriteVisitor<NormalizeDenormalizeRewriter>(SE), Kind(Kind), 41*0b57cec5SDimitry Andric Pred(Pred) {} 42*0b57cec5SDimitry Andric const SCEV *visitAddRecExpr(const SCEVAddRecExpr *Expr); 43*0b57cec5SDimitry Andric }; 44*0b57cec5SDimitry Andric } // namespace 45*0b57cec5SDimitry Andric 46*0b57cec5SDimitry Andric const SCEV * 47*0b57cec5SDimitry Andric NormalizeDenormalizeRewriter::visitAddRecExpr(const SCEVAddRecExpr *AR) { 48*0b57cec5SDimitry Andric SmallVector<const SCEV *, 8> Operands; 49*0b57cec5SDimitry Andric 50*0b57cec5SDimitry Andric transform(AR->operands(), std::back_inserter(Operands), 51*0b57cec5SDimitry Andric [&](const SCEV *Op) { return visit(Op); }); 52*0b57cec5SDimitry Andric 53*0b57cec5SDimitry Andric if (!Pred(AR)) 54*0b57cec5SDimitry Andric return SE.getAddRecExpr(Operands, AR->getLoop(), SCEV::FlagAnyWrap); 55*0b57cec5SDimitry Andric 56*0b57cec5SDimitry Andric // Normalization and denormalization are fancy names for decrementing and 57*0b57cec5SDimitry Andric // incrementing a SCEV expression with respect to a set of loops. Since 58*0b57cec5SDimitry Andric // Pred(AR) has returned true, we know we need to normalize or denormalize AR 59*0b57cec5SDimitry Andric // with respect to its loop. 60*0b57cec5SDimitry Andric 61*0b57cec5SDimitry Andric if (Kind == Denormalize) { 62*0b57cec5SDimitry Andric // Denormalization / "partial increment" is essentially the same as \c 63*0b57cec5SDimitry Andric // SCEVAddRecExpr::getPostIncExpr. Here we use an explicit loop to make the 64*0b57cec5SDimitry Andric // symmetry with Normalization clear. 65*0b57cec5SDimitry Andric for (int i = 0, e = Operands.size() - 1; i < e; i++) 66*0b57cec5SDimitry Andric Operands[i] = SE.getAddExpr(Operands[i], Operands[i + 1]); 67*0b57cec5SDimitry Andric } else { 68*0b57cec5SDimitry Andric assert(Kind == Normalize && "Only two possibilities!"); 69*0b57cec5SDimitry Andric 70*0b57cec5SDimitry Andric // Normalization / "partial decrement" is a bit more subtle. Since 71*0b57cec5SDimitry Andric // incrementing a SCEV expression (in general) changes the step of the SCEV 72*0b57cec5SDimitry Andric // expression as well, we cannot use the step of the current expression. 73*0b57cec5SDimitry Andric // Instead, we have to use the step of the very expression we're trying to 74*0b57cec5SDimitry Andric // compute! 75*0b57cec5SDimitry Andric // 76*0b57cec5SDimitry Andric // We solve the issue by recursively building up the result, starting from 77*0b57cec5SDimitry Andric // the "least significant" operand in the add recurrence: 78*0b57cec5SDimitry Andric // 79*0b57cec5SDimitry Andric // Base case: 80*0b57cec5SDimitry Andric // Single operand add recurrence. It's its own normalization. 81*0b57cec5SDimitry Andric // 82*0b57cec5SDimitry Andric // N-operand case: 83*0b57cec5SDimitry Andric // {S_{N-1},+,S_{N-2},+,...,+,S_0} = S 84*0b57cec5SDimitry Andric // 85*0b57cec5SDimitry Andric // Since the step recurrence of S is {S_{N-2},+,...,+,S_0}, we know its 86*0b57cec5SDimitry Andric // normalization by induction. We subtract the normalized step 87*0b57cec5SDimitry Andric // recurrence from S_{N-1} to get the normalization of S. 88*0b57cec5SDimitry Andric 89*0b57cec5SDimitry Andric for (int i = Operands.size() - 2; i >= 0; i--) 90*0b57cec5SDimitry Andric Operands[i] = SE.getMinusSCEV(Operands[i], Operands[i + 1]); 91*0b57cec5SDimitry Andric } 92*0b57cec5SDimitry Andric 93*0b57cec5SDimitry Andric return SE.getAddRecExpr(Operands, AR->getLoop(), SCEV::FlagAnyWrap); 94*0b57cec5SDimitry Andric } 95*0b57cec5SDimitry Andric 96*0b57cec5SDimitry Andric const SCEV *llvm::normalizeForPostIncUse(const SCEV *S, 97*0b57cec5SDimitry Andric const PostIncLoopSet &Loops, 98*0b57cec5SDimitry Andric ScalarEvolution &SE) { 99*0b57cec5SDimitry Andric auto Pred = [&](const SCEVAddRecExpr *AR) { 100*0b57cec5SDimitry Andric return Loops.count(AR->getLoop()); 101*0b57cec5SDimitry Andric }; 102*0b57cec5SDimitry Andric return NormalizeDenormalizeRewriter(Normalize, Pred, SE).visit(S); 103*0b57cec5SDimitry Andric } 104*0b57cec5SDimitry Andric 105*0b57cec5SDimitry Andric const SCEV *llvm::normalizeForPostIncUseIf(const SCEV *S, NormalizePredTy Pred, 106*0b57cec5SDimitry Andric ScalarEvolution &SE) { 107*0b57cec5SDimitry Andric return NormalizeDenormalizeRewriter(Normalize, Pred, SE).visit(S); 108*0b57cec5SDimitry Andric } 109*0b57cec5SDimitry Andric 110*0b57cec5SDimitry Andric const SCEV *llvm::denormalizeForPostIncUse(const SCEV *S, 111*0b57cec5SDimitry Andric const PostIncLoopSet &Loops, 112*0b57cec5SDimitry Andric ScalarEvolution &SE) { 113*0b57cec5SDimitry Andric auto Pred = [&](const SCEVAddRecExpr *AR) { 114*0b57cec5SDimitry Andric return Loops.count(AR->getLoop()); 115*0b57cec5SDimitry Andric }; 116*0b57cec5SDimitry Andric return NormalizeDenormalizeRewriter(Denormalize, Pred, SE).visit(S); 117*0b57cec5SDimitry Andric } 118