Skip to content

Commit

Permalink
[SCEV] Add explicit representations of umin/smin
Browse files Browse the repository at this point in the history
Summary:
Currently we express umin as `~umax(~x, ~y)`. However, this becomes
a problem for operands in non-integral pointer spaces, because `~x`
is not something we can compute for `x` non-integral. However, since
comparisons are generally still allowed, we are actually able to
express `umin(x, y)` directly as long as we don't try to express is
as a umax. Support this by adding an explicit umin/smin representation
to SCEV. We do this by factoring the existing getUMax/getSMax functions
into a new function that does all four. The previous two functions were
largely identical.

Reviewed By: sanjoy
Differential Revision: https://reviews.llvm.org/D50167

llvm-svn: 360159
  • Loading branch information
Keno authored and MrSidims committed May 24, 2019
1 parent aa22794 commit c5bbcda
Show file tree
Hide file tree
Showing 25 changed files with 597 additions and 519 deletions.
2 changes: 2 additions & 0 deletions llvm/include/llvm/Analysis/ScalarEvolution.h
Expand Up @@ -598,6 +598,8 @@ class ScalarEvolution {
/// \p IndexExprs The expressions for the indices.
const SCEV *getGEPExpr(GEPOperator *GEP,
const SmallVectorImpl<const SCEV *> &IndexExprs);
const SCEV *getMinMaxExpr(unsigned Kind,
SmallVectorImpl<const SCEV *> &Operands);
const SCEV *getSMaxExpr(const SCEV *LHS, const SCEV *RHS);
const SCEV *getSMaxExpr(SmallVectorImpl<const SCEV *> &Operands);
const SCEV *getUMaxExpr(const SCEV *LHS, const SCEV *RHS);
Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/Analysis/ScalarEvolutionExpander.h
Expand Up @@ -367,6 +367,10 @@ namespace llvm {

Value *visitUMaxExpr(const SCEVUMaxExpr *S);

Value *visitSMinExpr(const SCEVSMinExpr *S);

Value *visitUMinExpr(const SCEVUMinExpr *S);

Value *visitUnknown(const SCEVUnknown *S) {
return S->getValue();
}
Expand Down
128 changes: 106 additions & 22 deletions llvm/include/llvm/Analysis/ScalarEvolutionExpressions.h
Expand Up @@ -39,7 +39,7 @@ class Type;
// These should be ordered in terms of increasing complexity to make the
// folders simpler.
scConstant, scTruncate, scZeroExtend, scSignExtend, scAddExpr, scMulExpr,
scUDivExpr, scAddRecExpr, scUMaxExpr, scSMaxExpr,
scUDivExpr, scAddRecExpr, scUMaxExpr, scSMaxExpr, scUMinExpr, scSMinExpr,
scUnknown, scCouldNotCompute
};

Expand Down Expand Up @@ -190,10 +190,9 @@ class Type;

/// Methods for support type inquiry through isa, cast, and dyn_cast:
static bool classof(const SCEV *S) {
return S->getSCEVType() == scAddExpr ||
S->getSCEVType() == scMulExpr ||
S->getSCEVType() == scSMaxExpr ||
S->getSCEVType() == scUMaxExpr ||
return S->getSCEVType() == scAddExpr || S->getSCEVType() == scMulExpr ||
S->getSCEVType() == scSMaxExpr || S->getSCEVType() == scUMaxExpr ||
S->getSCEVType() == scSMinExpr || S->getSCEVType() == scUMinExpr ||
S->getSCEVType() == scAddRecExpr;
}
};
Expand All @@ -208,10 +207,9 @@ class Type;
public:
/// Methods for support type inquiry through isa, cast, and dyn_cast:
static bool classof(const SCEV *S) {
return S->getSCEVType() == scAddExpr ||
S->getSCEVType() == scMulExpr ||
S->getSCEVType() == scSMaxExpr ||
S->getSCEVType() == scUMaxExpr;
return S->getSCEVType() == scAddExpr || S->getSCEVType() == scMulExpr ||
S->getSCEVType() == scSMaxExpr || S->getSCEVType() == scUMaxExpr ||
S->getSCEVType() == scSMinExpr || S->getSCEVType() == scUMinExpr;
}

/// Set flags for a non-recurrence without clearing previously set flags.
Expand Down Expand Up @@ -366,17 +364,53 @@ class Type;
}
};

/// This class represents a signed maximum selection.
class SCEVSMaxExpr : public SCEVCommutativeExpr {
/// This node is the base class min/max selections.
class SCEVMinMaxExpr : public SCEVCommutativeExpr {
friend class ScalarEvolution;

SCEVSMaxExpr(const FoldingSetNodeIDRef ID,
const SCEV *const *O, size_t N)
: SCEVCommutativeExpr(ID, scSMaxExpr, O, N) {
// Max never overflows.
static bool isMinMaxType(enum SCEVTypes T) {
return T == scSMaxExpr || T == scUMaxExpr || T == scSMinExpr ||
T == scUMinExpr;
}

protected:
/// Note: Constructing subclasses via this constructor is allowed
SCEVMinMaxExpr(const FoldingSetNodeIDRef ID, enum SCEVTypes T,
const SCEV *const *O, size_t N)
: SCEVCommutativeExpr(ID, T, O, N) {
assert(isMinMaxType(T));
// Min and max never overflow
setNoWrapFlags((NoWrapFlags)(FlagNUW | FlagNSW));
}

public:
static bool classof(const SCEV *S) {
return isMinMaxType(static_cast<SCEVTypes>(S->getSCEVType()));
}

static enum SCEVTypes negate(enum SCEVTypes T) {
switch (T) {
case scSMaxExpr:
return scSMinExpr;
case scSMinExpr:
return scSMaxExpr;
case scUMaxExpr:
return scUMinExpr;
case scUMinExpr:
return scUMaxExpr;
default:
llvm_unreachable("Not a min or max SCEV type!");
}
}
};

/// This class represents a signed maximum selection.
class SCEVSMaxExpr : public SCEVMinMaxExpr {
friend class ScalarEvolution;

SCEVSMaxExpr(const FoldingSetNodeIDRef ID, const SCEV *const *O, size_t N)
: SCEVMinMaxExpr(ID, scSMaxExpr, O, N) {}

public:
/// Methods for support type inquiry through isa, cast, and dyn_cast:
static bool classof(const SCEV *S) {
Expand All @@ -385,15 +419,11 @@ class Type;
};

/// This class represents an unsigned maximum selection.
class SCEVUMaxExpr : public SCEVCommutativeExpr {
class SCEVUMaxExpr : public SCEVMinMaxExpr {
friend class ScalarEvolution;

SCEVUMaxExpr(const FoldingSetNodeIDRef ID,
const SCEV *const *O, size_t N)
: SCEVCommutativeExpr(ID, scUMaxExpr, O, N) {
// Max never overflows.
setNoWrapFlags((NoWrapFlags)(FlagNUW | FlagNSW));
}
SCEVUMaxExpr(const FoldingSetNodeIDRef ID, const SCEV *const *O, size_t N)
: SCEVMinMaxExpr(ID, scUMaxExpr, O, N) {}

public:
/// Methods for support type inquiry through isa, cast, and dyn_cast:
Expand All @@ -402,6 +432,34 @@ class Type;
}
};

/// This class represents a signed minimum selection.
class SCEVSMinExpr : public SCEVMinMaxExpr {
friend class ScalarEvolution;

SCEVSMinExpr(const FoldingSetNodeIDRef ID, const SCEV *const *O, size_t N)
: SCEVMinMaxExpr(ID, scSMinExpr, O, N) {}

public:
/// Methods for support type inquiry through isa, cast, and dyn_cast:
static bool classof(const SCEV *S) {
return S->getSCEVType() == scSMinExpr;
}
};

/// This class represents an unsigned minimum selection.
class SCEVUMinExpr : public SCEVMinMaxExpr {
friend class ScalarEvolution;

SCEVUMinExpr(const FoldingSetNodeIDRef ID, const SCEV *const *O, size_t N)
: SCEVMinMaxExpr(ID, scUMinExpr, O, N) {}

public:
/// Methods for support type inquiry through isa, cast, and dyn_cast:
static bool classof(const SCEV *S) {
return S->getSCEVType() == scUMinExpr;
}
};

/// This means that we are dealing with an entirely unknown SCEV
/// value, and only represent it as its LLVM Value. This is the
/// "bottom" value for the analysis.
Expand Down Expand Up @@ -474,6 +532,10 @@ class Type;
return ((SC*)this)->visitSMaxExpr((const SCEVSMaxExpr*)S);
case scUMaxExpr:
return ((SC*)this)->visitUMaxExpr((const SCEVUMaxExpr*)S);
case scSMinExpr:
return ((SC *)this)->visitSMinExpr((const SCEVSMinExpr *)S);
case scUMinExpr:
return ((SC *)this)->visitUMinExpr((const SCEVUMinExpr *)S);
case scUnknown:
return ((SC*)this)->visitUnknown((const SCEVUnknown*)S);
case scCouldNotCompute:
Expand Down Expand Up @@ -527,6 +589,8 @@ class Type;
case scMulExpr:
case scSMaxExpr:
case scUMaxExpr:
case scSMinExpr:
case scUMinExpr:
case scAddRecExpr:
for (const auto *Op : cast<SCEVNAryExpr>(S)->operands())
push(Op);
Expand Down Expand Up @@ -689,6 +753,26 @@ class Type;
return !Changed ? Expr : SE.getUMaxExpr(Operands);
}

const SCEV *visitSMinExpr(const SCEVSMinExpr *Expr) {
SmallVector<const SCEV *, 2> Operands;
bool Changed = false;
for (auto *Op : Expr->operands()) {
Operands.push_back(((SC *)this)->visit(Op));
Changed |= Op != Operands.back();
}
return !Changed ? Expr : SE.getSMinExpr(Operands);
}

const SCEV *visitUMinExpr(const SCEVUMinExpr *Expr) {
SmallVector<const SCEV *, 2> Operands;
bool Changed = false;
for (auto *Op : Expr->operands()) {
Operands.push_back(((SC *)this)->visit(Op));
Changed |= Op != Operands.back();
}
return !Changed ? Expr : SE.getUMinExpr(Operands);
}

const SCEV *visitUnknown(const SCEVUnknown *Expr) {
return Expr;
}
Expand Down

0 comments on commit c5bbcda

Please sign in to comment.