Skip to content

Commit

Permalink
Allow switch instructions in SCoPs
Browse files Browse the repository at this point in the history
  This patch allows switch instructions with affine conditions in the
  SCoP. Also switch instructions in non-affine subregions are allowed.
  Both did not require much changes to the code, though there was some
  refactoring needed to integrate them without code duplication.

  In the llvm-test suite the number of profitable SCoPs increased from
  135 to 139 but more importantly we can handle more benchmarks and user
  inputs without preprocessing.

Differential Revision: http://reviews.llvm.org/D13200

llvm-svn: 248701
  • Loading branch information
Johannes Doerfert committed Sep 28, 2015
1 parent 3d77768 commit 9a132f3
Show file tree
Hide file tree
Showing 17 changed files with 1,126 additions and 65 deletions.
22 changes: 22 additions & 0 deletions polly/include/polly/ScopDetection.h
Expand Up @@ -271,6 +271,28 @@ class ScopDetection : public FunctionPass {
/// @return True if the instruction is valid, false otherwise.
bool isValidInstruction(Instruction &Inst, DetectionContext &Context) const;

/// @brief Check if the switch @p SI with condition @p Condition is valid.
///
/// @param BB The block to check.
/// @param SI The switch to check.
/// @param Condition The switch condition.
/// @param Context The context of scop detection.
///
/// @return True if the branch @p BI is valid.
bool isValidSwitch(BasicBlock &BB, SwitchInst *SI, Value *Condition,
DetectionContext &Context) const;

/// @brief Check if the branch @p BI with condition @p Condition is valid.
///
/// @param BB The block to check.
/// @param BI The branch to check.
/// @param Condition The branch condition.
/// @param Context The context of scop detection.
///
/// @return True if the branch @p BI is valid.
bool isValidBranch(BasicBlock &BB, BranchInst *BI, Value *Condition,
DetectionContext &Context) const;

/// @brief Check if the control flow in a basic block is valid.
///
/// @param BB The BB to check the control flow.
Expand Down
10 changes: 5 additions & 5 deletions polly/include/polly/ScopDetectionDiagnostic.h
Expand Up @@ -62,7 +62,7 @@ void emitValidRemarks(const llvm::Function &F, const Region *R);
enum RejectReasonKind {
// CFG Category
rrkCFG,
rrkNonBranchTerminator,
rrkInvalidTerminator,
rrkCondition,
rrkLastCFG,

Expand Down Expand Up @@ -230,13 +230,13 @@ class ReportCFG : public RejectReason {
};

//===----------------------------------------------------------------------===//
/// @brief Captures a non-branch terminator within a Scop candidate.
class ReportNonBranchTerminator : public ReportCFG {
/// @brief Captures bad terminator within a Scop candidate.
class ReportInvalidTerminator : public ReportCFG {
BasicBlock *BB;

public:
ReportNonBranchTerminator(BasicBlock *BB)
: ReportCFG(rrkNonBranchTerminator), BB(BB) {}
ReportInvalidTerminator(BasicBlock *BB)
: ReportCFG(rrkInvalidTerminator), BB(BB) {}

/// @name LLVM-RTTI interface
//@{
Expand Down
10 changes: 10 additions & 0 deletions polly/include/polly/Support/ScopHelper.h
Expand Up @@ -30,6 +30,7 @@ class StringRef;
class DataLayout;
class DominatorTree;
class RegionInfo;
class TerminatorInst;
class ScalarEvolution;
}

Expand Down Expand Up @@ -113,5 +114,14 @@ llvm::Value *expandCodeFor(Scop &S, llvm::ScalarEvolution &SE,
///
/// @return True if the block is a error block, false otherwise.
bool isErrorBlock(llvm::BasicBlock &BB);

/// @brief Return the condition for the terminator @p TI.
///
/// For unconditional branches the "i1 true" condition will be returned.
///
/// @param TI The terminator to get the condition from.
///
/// @return The condition of @p TI and nullptr if none could be extracted.
llvm::Value *getConditionFromTerminator(llvm::TerminatorInst *TI);
}
#endif
77 changes: 52 additions & 25 deletions polly/lib/Analysis/ScopDetection.cpp
Expand Up @@ -299,48 +299,43 @@ bool ScopDetection::addOverApproximatedRegion(Region *AR,
return (AllowNonAffineSubLoops || Context.BoxedLoopsSet.empty());
}

bool ScopDetection::isValidCFG(BasicBlock &BB,
DetectionContext &Context) const {
bool ScopDetection::isValidSwitch(BasicBlock &BB, SwitchInst *SI,
Value *Condition,
DetectionContext &Context) const {
Region &CurRegion = Context.CurRegion;

TerminatorInst *TI = BB.getTerminator();

// Return instructions are only valid if the region is the top level region.
if (isa<ReturnInst>(TI) && !CurRegion.getExit() && TI->getNumOperands() == 0)
return true;

BranchInst *Br = dyn_cast<BranchInst>(TI);
Loop *L = LI->getLoopFor(&BB);
const SCEV *ConditionSCEV = SE->getSCEVAtScope(Condition, L);

if (!Br)
return invalid<ReportNonBranchTerminator>(Context, /*Assert=*/true, &BB);

if (Br->isUnconditional())
return true;
if (!isAffineExpr(&CurRegion, ConditionSCEV, *SE))
if (!AllowNonAffineSubRegions ||
!addOverApproximatedRegion(RI->getRegionFor(&BB), Context))
return invalid<ReportNonAffBranch>(Context, /*Assert=*/true, &BB,
ConditionSCEV, ConditionSCEV, SI);

Value *Condition = Br->getCondition();
return true;
}

// UndefValue is not allowed as condition.
if (isa<UndefValue>(Condition))
return invalid<ReportUndefCond>(Context, /*Assert=*/true, Br, &BB);
bool ScopDetection::isValidBranch(BasicBlock &BB, BranchInst *BI,
Value *Condition,
DetectionContext &Context) const {
Region &CurRegion = Context.CurRegion;

// Only Constant and ICmpInst are allowed as condition.
if (!(isa<Constant>(Condition) || isa<ICmpInst>(Condition))) {
// Non constant conditions of branches need to be ICmpInst.
if (!isa<ICmpInst>(Condition)) {
if (!AllowNonAffineSubRegions ||
!addOverApproximatedRegion(RI->getRegionFor(&BB), Context))
return invalid<ReportInvalidCond>(Context, /*Assert=*/true, Br, &BB);
return invalid<ReportInvalidCond>(Context, /*Assert=*/true, BI, &BB);
}

// Allow perfectly nested conditions.
assert(Br->getNumSuccessors() == 2 && "Unexpected number of successors");

if (ICmpInst *ICmp = dyn_cast<ICmpInst>(Condition)) {
// Unsigned comparisons are not allowed. They trigger overflow problems
// in the code generation.
//
// TODO: This is not sufficient and just hides bugs. However it does pretty
// well.
if (ICmp->isUnsigned() && !AllowUnsigned)
return invalid<ReportUnsignedCond>(Context, /*Assert=*/true, Br, &BB);
return invalid<ReportUnsignedCond>(Context, /*Assert=*/true, BI, &BB);

// Are both operands of the ICmp affine?
if (isa<UndefValue>(ICmp->getOperand(0)) ||
Expand Down Expand Up @@ -369,6 +364,38 @@ bool ScopDetection::isValidCFG(BasicBlock &BB,
return true;
}

bool ScopDetection::isValidCFG(BasicBlock &BB,
DetectionContext &Context) const {
Region &CurRegion = Context.CurRegion;

TerminatorInst *TI = BB.getTerminator();

// Return instructions are only valid if the region is the top level region.
if (isa<ReturnInst>(TI) && !CurRegion.getExit() && TI->getNumOperands() == 0)
return true;

Value *Condition = getConditionFromTerminator(TI);

if (!Condition)
return invalid<ReportInvalidTerminator>(Context, /*Assert=*/true, &BB);

// UndefValue is not allowed as condition.
if (isa<UndefValue>(Condition))
return invalid<ReportUndefCond>(Context, /*Assert=*/true, TI, &BB);

// Constant conditions are always affine.
if (isa<Constant>(Condition))
return true;

if (BranchInst *BI = dyn_cast<BranchInst>(TI))
return isValidBranch(BB, BI, Condition, Context);

SwitchInst *SI = dyn_cast<SwitchInst>(TI);
assert(SI && "Terminator was neither branch nor switch");

return isValidSwitch(BB, SI, Condition, Context);
}

bool ScopDetection::isValidCallInst(CallInst &CI) {
if (CI.doesNotReturn())
return false;
Expand Down
12 changes: 6 additions & 6 deletions polly/lib/Analysis/ScopDetectionDiagnostic.cpp
Expand Up @@ -141,18 +141,18 @@ bool ReportCFG::classof(const RejectReason *RR) {
}

//===----------------------------------------------------------------------===//
// ReportNonBranchTerminator.
// ReportInvalidTerminator.

std::string ReportNonBranchTerminator::getMessage() const {
return ("Non branch instruction terminates BB: " + BB->getName()).str();
std::string ReportInvalidTerminator::getMessage() const {
return ("Invalid instruction terminates BB: " + BB->getName()).str();
}

const DebugLoc &ReportNonBranchTerminator::getDebugLoc() const {
const DebugLoc &ReportInvalidTerminator::getDebugLoc() const {
return BB->getTerminator()->getDebugLoc();
}

bool ReportNonBranchTerminator::classof(const RejectReason *RR) {
return RR->getKind() == rrkNonBranchTerminator;
bool ReportInvalidTerminator::classof(const RejectReason *RR) {
return RR->getKind() == rrkInvalidTerminator;
}

//===----------------------------------------------------------------------===//
Expand Down

0 comments on commit 9a132f3

Please sign in to comment.