summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/Analysis/TargetTransformInfo.h8
-rw-r--r--llvm/include/llvm/Analysis/TargetTransformInfoImpl.h1
-rw-r--r--llvm/lib/Analysis/TargetTransformInfo.cpp3
-rw-r--r--llvm/lib/Target/ARM/ARMTargetTransformInfo.h10
-rw-r--r--llvm/lib/Transforms/Utils/SimplifyCFG.cpp44
-rw-r--r--llvm/test/Transforms/SimplifyCFG/ARM/switch-to-lookup-table.ll132
6 files changed, 181 insertions, 17 deletions
diff --git a/llvm/include/llvm/Analysis/TargetTransformInfo.h b/llvm/include/llvm/Analysis/TargetTransformInfo.h
index 1fcc361acef..c8224b32dfb 100644
--- a/llvm/include/llvm/Analysis/TargetTransformInfo.h
+++ b/llvm/include/llvm/Analysis/TargetTransformInfo.h
@@ -381,6 +381,10 @@ public:
/// target.
bool shouldBuildLookupTables() const;
+ /// \brief Return true if switches should be turned into lookup tables
+ /// containing this constant value for the target.
+ bool shouldBuildLookupTablesForConstant(Constant *C) const;
+
/// \brief Don't restrict interleaved unrolling to small loops.
bool enableAggressiveInterleaving(bool LoopHasReductions) const;
@@ -703,6 +707,7 @@ public:
virtual unsigned getJumpBufAlignment() = 0;
virtual unsigned getJumpBufSize() = 0;
virtual bool shouldBuildLookupTables() = 0;
+ virtual bool shouldBuildLookupTablesForConstant(Constant *C) = 0;
virtual bool enableAggressiveInterleaving(bool LoopHasReductions) = 0;
virtual bool enableInterleavedAccessVectorization() = 0;
virtual bool isFPVectorizationPotentiallyUnsafe() = 0;
@@ -888,6 +893,9 @@ public:
bool shouldBuildLookupTables() override {
return Impl.shouldBuildLookupTables();
}
+ bool shouldBuildLookupTablesForConstant(Constant *C) override {
+ return Impl.shouldBuildLookupTablesForConstant(C);
+ }
bool enableAggressiveInterleaving(bool LoopHasReductions) override {
return Impl.enableAggressiveInterleaving(LoopHasReductions);
}
diff --git a/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h b/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
index a664f25e791..5b037245c29 100644
--- a/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
+++ b/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
@@ -248,6 +248,7 @@ public:
unsigned getJumpBufSize() { return 0; }
bool shouldBuildLookupTables() { return true; }
+ bool shouldBuildLookupTablesForConstant(Constant *C) { return true; }
bool enableAggressiveInterleaving(bool LoopHasReductions) { return false; }
diff --git a/llvm/lib/Analysis/TargetTransformInfo.cpp b/llvm/lib/Analysis/TargetTransformInfo.cpp
index 7f225a59258..fb0db03eb3f 100644
--- a/llvm/lib/Analysis/TargetTransformInfo.cpp
+++ b/llvm/lib/Analysis/TargetTransformInfo.cpp
@@ -178,6 +178,9 @@ unsigned TargetTransformInfo::getJumpBufSize() const {
bool TargetTransformInfo::shouldBuildLookupTables() const {
return TTIImpl->shouldBuildLookupTables();
}
+bool TargetTransformInfo::shouldBuildLookupTablesForConstant(Constant *C) const {
+ return TTIImpl->shouldBuildLookupTablesForConstant(C);
+}
bool TargetTransformInfo::enableAggressiveInterleaving(bool LoopHasReductions) const {
return TTIImpl->enableAggressiveInterleaving(LoopHasReductions);
diff --git a/llvm/lib/Target/ARM/ARMTargetTransformInfo.h b/llvm/lib/Target/ARM/ARMTargetTransformInfo.h
index a0ca9e64800..c8b057b6aaf 100644
--- a/llvm/lib/Target/ARM/ARMTargetTransformInfo.h
+++ b/llvm/lib/Target/ARM/ARMTargetTransformInfo.h
@@ -128,6 +128,16 @@ public:
int getInterleavedMemoryOpCost(unsigned Opcode, Type *VecTy, unsigned Factor,
ArrayRef<unsigned> Indices, unsigned Alignment,
unsigned AddressSpace);
+
+ bool shouldBuildLookupTablesForConstant(Constant *C) const {
+ // In the ROPI and RWPI relocation models we can't have pointers to global
+ // variables or functions in constant data, so don't convert switches to
+ // lookup tables if any of the values would need relocation.
+ if (ST->isROPI() || ST->isRWPI())
+ return !C->needsRelocation();
+
+ return true;
+ }
/// @}
};
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 1546a60c337..63b9f4061f2 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -4425,18 +4425,25 @@ static bool ForwardSwitchConditionToPHI(SwitchInst *SI) {
/// Return true if the backend will be able to handle
/// initializing an array of constants like C.
-static bool ValidLookupTableConstant(Constant *C) {
+static bool ValidLookupTableConstant(Constant *C, const TargetTransformInfo &TTI) {
if (C->isThreadDependent())
return false;
if (C->isDLLImportDependent())
return false;
+ if (!isa<ConstantFP>(C) && !isa<ConstantInt>(C) &&
+ !isa<ConstantPointerNull>(C) && !isa<GlobalValue>(C) &&
+ !isa<UndefValue>(C) && !isa<ConstantExpr>(C))
+ return false;
+
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(C))
- return CE->isGEPWithNoNotionalOverIndexing();
+ if (!CE->isGEPWithNoNotionalOverIndexing())
+ return false;
- return isa<ConstantFP>(C) || isa<ConstantInt>(C) ||
- isa<ConstantPointerNull>(C) || isa<GlobalValue>(C) ||
- isa<UndefValue>(C);
+ if (!TTI.shouldBuildLookupTablesForConstant(C))
+ return false;
+
+ return true;
}
/// If V is a Constant, return it. Otherwise, try to look up
@@ -4490,8 +4497,8 @@ ConstantFold(Instruction *I, const DataLayout &DL,
static bool
GetCaseResults(SwitchInst *SI, ConstantInt *CaseVal, BasicBlock *CaseDest,
BasicBlock **CommonDest,
- SmallVectorImpl<std::pair<PHINode *, Constant *>> &Res,
- const DataLayout &DL) {
+ SmallVectorImpl<std::pair<PHINode *, Constant *> > &Res,
+ const DataLayout &DL, const TargetTransformInfo &TTI) {
// The block from which we enter the common destination.
BasicBlock *Pred = SI->getParent();
@@ -4553,7 +4560,7 @@ GetCaseResults(SwitchInst *SI, ConstantInt *CaseVal, BasicBlock *CaseDest,
return false;
// Be conservative about which kinds of constants we support.
- if (!ValidLookupTableConstant(ConstVal))
+ if (!ValidLookupTableConstant(ConstVal, TTI))
return false;
Res.push_back(std::make_pair(PHI, ConstVal));
@@ -4585,14 +4592,15 @@ static bool InitializeUniqueCases(SwitchInst *SI, PHINode *&PHI,
BasicBlock *&CommonDest,
SwitchCaseResultVectorTy &UniqueResults,
Constant *&DefaultResult,
- const DataLayout &DL) {
+ const DataLayout &DL,
+ const TargetTransformInfo &TTI) {
for (auto &I : SI->cases()) {
ConstantInt *CaseVal = I.getCaseValue();
// Resulting value at phi nodes for this case value.
SwitchCaseResultsTy Results;
if (!GetCaseResults(SI, CaseVal, I.getCaseSuccessor(), &CommonDest, Results,
- DL))
+ DL, TTI))
return false;
// Only one value per case is permitted
@@ -4610,7 +4618,7 @@ static bool InitializeUniqueCases(SwitchInst *SI, PHINode *&PHI,
SmallVector<std::pair<PHINode *, Constant *>, 1> DefaultResults;
BasicBlock *DefaultDest = SI->getDefaultDest();
GetCaseResults(SI, nullptr, SI->getDefaultDest(), &CommonDest, DefaultResults,
- DL);
+ DL, TTI);
// If the default value is not found abort unless the default destination
// is unreachable.
DefaultResult =
@@ -4689,7 +4697,8 @@ static void RemoveSwitchAfterSelectConversion(SwitchInst *SI, PHINode *PHI,
/// phi nodes in a common successor block with only two different
/// constant values, replace the switch with select.
static bool SwitchToSelect(SwitchInst *SI, IRBuilder<> &Builder,
- AssumptionCache *AC, const DataLayout &DL) {
+ AssumptionCache *AC, const DataLayout &DL,
+ const TargetTransformInfo &TTI) {
Value *const Cond = SI->getCondition();
PHINode *PHI = nullptr;
BasicBlock *CommonDest = nullptr;
@@ -4697,7 +4706,7 @@ static bool SwitchToSelect(SwitchInst *SI, IRBuilder<> &Builder,
SwitchCaseResultVectorTy UniqueResults;
// Collect all the cases that will deliver the same value from the switch.
if (!InitializeUniqueCases(SI, PHI, CommonDest, UniqueResults, DefaultResult,
- DL))
+ DL, TTI))
return false;
// Selects choose between maximum two values.
if (UniqueResults.size() != 2)
@@ -5135,7 +5144,7 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
typedef SmallVector<std::pair<PHINode *, Constant *>, 4> ResultsTy;
ResultsTy Results;
if (!GetCaseResults(SI, CaseVal, CI.getCaseSuccessor(), &CommonDest,
- Results, DL))
+ Results, DL, TTI))
return false;
// Append the result from this case to the list for each phi.
@@ -5161,8 +5170,9 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
// If the table has holes, we need a constant result for the default case
// or a bitmask that fits in a register.
SmallVector<std::pair<PHINode *, Constant *>, 4> DefaultResultsList;
- bool HasDefaultResults = GetCaseResults(SI, nullptr, SI->getDefaultDest(),
- &CommonDest, DefaultResultsList, DL);
+ bool HasDefaultResults =
+ GetCaseResults(SI, nullptr, SI->getDefaultDest(), &CommonDest,
+ DefaultResultsList, DL, TTI);
bool NeedMask = (TableHasHoles && !HasDefaultResults);
if (NeedMask) {
@@ -5458,7 +5468,7 @@ bool SimplifyCFGOpt::SimplifySwitch(SwitchInst *SI, IRBuilder<> &Builder) {
if (EliminateDeadSwitchCases(SI, AC, DL))
return SimplifyCFG(BB, TTI, BonusInstThreshold, AC) | true;
- if (SwitchToSelect(SI, Builder, AC, DL))
+ if (SwitchToSelect(SI, Builder, AC, DL, TTI))
return SimplifyCFG(BB, TTI, BonusInstThreshold, AC) | true;
if (ForwardSwitchConditionToPHI(SI))
diff --git a/llvm/test/Transforms/SimplifyCFG/ARM/switch-to-lookup-table.ll b/llvm/test/Transforms/SimplifyCFG/ARM/switch-to-lookup-table.ll
new file mode 100644
index 00000000000..16f028d2e85
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/ARM/switch-to-lookup-table.ll
@@ -0,0 +1,132 @@
+; RUN: opt -S -simplifycfg -mtriple=arm -relocation-model=static < %s | FileCheck %s --check-prefix=CHECK --check-prefix=ENABLE
+; RUN: opt -S -simplifycfg -mtriple=arm -relocation-model=pic < %s | FileCheck %s --check-prefix=CHECK --check-prefix=ENABLE
+; RUN: opt -S -simplifycfg -mtriple=arm -relocation-model=ropi < %s | FileCheck %s --check-prefix=CHECK --check-prefix=DISABLE
+; RUN: opt -S -simplifycfg -mtriple=arm -relocation-model=rwpi < %s | FileCheck %s --check-prefix=CHECK --check-prefix=DISABLE
+; RUN: opt -S -simplifycfg -mtriple=arm -relocation-model=ropi-rwpi < %s | FileCheck %s --check-prefix=CHECK --check-prefix=DISABLE
+
+; CHECK: @{{.*}} = private unnamed_addr constant [3 x i32] [i32 1234, i32 5678, i32 15532]
+; ENABLE: @{{.*}} = private unnamed_addr constant [3 x i32*] [i32* @c1, i32* @c2, i32* @c3]
+; DISABLE-NOT: @{{.*}} = private unnamed_addr constant [3 x i32*] [i32* @c1, i32* @c2, i32* @c3]
+; ENABLE: @{{.*}} = private unnamed_addr constant [3 x i32*] [i32* @g1, i32* @g2, i32* @g3]
+; DISABLE-NOT: @{{.*}} = private unnamed_addr constant [3 x i32*] [i32* @g1, i32* @g2, i32* @g3]
+; ENABLE: @{{.*}} = private unnamed_addr constant [3 x i32 (i32, i32)*] [i32 (i32, i32)* @f1, i32 (i32, i32)* @f2, i32 (i32, i32)* @f3]
+; DISABLE-NOT: @{{.*}} = private unnamed_addr constant [3 x i32 (i32, i32)*] [i32 (i32, i32)* @f1, i32 (i32, i32)* @f2, i32 (i32, i32)* @f3]
+
+target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
+target triple = "armv7a--none-eabi"
+
+define i32 @test1(i32 %n) {
+entry:
+ switch i32 %n, label %sw.default [
+ i32 0, label %sw.bb
+ i32 1, label %sw.bb1
+ i32 2, label %sw.bb2
+ ]
+
+sw.bb:
+ br label %return
+
+sw.bb1:
+ br label %return
+
+sw.bb2:
+ br label %return
+
+sw.default:
+ br label %return
+
+return:
+ %retval.0 = phi i32 [ 15498, %sw.default ], [ 15532, %sw.bb2 ], [ 5678, %sw.bb1 ], [ 1234, %sw.bb ]
+ ret i32 %retval.0
+}
+
+@c1 = external constant i32, align 4
+@c2 = external constant i32, align 4
+@c3 = external constant i32, align 4
+@c4 = external constant i32, align 4
+
+
+define i32* @test2(i32 %n) {
+entry:
+ switch i32 %n, label %sw.default [
+ i32 0, label %sw.bb
+ i32 1, label %sw.bb1
+ i32 2, label %sw.bb2
+ ]
+
+sw.bb:
+ br label %return
+
+sw.bb1:
+ br label %return
+
+sw.bb2:
+ br label %return
+
+sw.default:
+ br label %return
+
+return:
+ %retval.0 = phi i32* [ @c4, %sw.default ], [ @c3, %sw.bb2 ], [ @c2, %sw.bb1 ], [ @c1, %sw.bb ]
+ ret i32* %retval.0
+}
+
+@g1 = external global i32, align 4
+@g2 = external global i32, align 4
+@g3 = external global i32, align 4
+@g4 = external global i32, align 4
+
+define i32* @test3(i32 %n) {
+entry:
+ switch i32 %n, label %sw.default [
+ i32 0, label %sw.bb
+ i32 1, label %sw.bb1
+ i32 2, label %sw.bb2
+ ]
+
+sw.bb:
+ br label %return
+
+sw.bb1:
+ br label %return
+
+sw.bb2:
+ br label %return
+
+sw.default:
+ br label %return
+
+return:
+ %retval.0 = phi i32* [ @g4, %sw.default ], [ @g3, %sw.bb2 ], [ @g2, %sw.bb1 ], [ @g1, %sw.bb ]
+ ret i32* %retval.0
+}
+
+declare i32 @f1(i32, i32)
+declare i32 @f2(i32, i32)
+declare i32 @f3(i32, i32)
+declare i32 @f4(i32, i32)
+declare i32 @f5(i32, i32)
+
+define i32 @test4(i32 %a, i32 %b, i32 %c) {
+entry:
+ %cmp = icmp eq i32 %a, 1
+ br i1 %cmp, label %cond.end11, label %cond.false
+
+cond.false:
+ %cmp1 = icmp eq i32 %a, 2
+ br i1 %cmp1, label %cond.end11, label %cond.false3
+
+cond.false3:
+ %cmp4 = icmp eq i32 %a, 3
+ br i1 %cmp4, label %cond.end11, label %cond.false6
+
+cond.false6:
+ %cmp7 = icmp eq i32 %a, 4
+ %cond = select i1 %cmp7, i32 (i32, i32)* @f4, i32 (i32, i32)* @f5
+ br label %cond.end11
+
+cond.end11:
+ %cond12 = phi i32 (i32, i32)* [ @f1, %entry ], [ @f2, %cond.false ], [ %cond, %cond.false6 ], [ @f3, %cond.false3 ]
+ %call = call i32 %cond12(i32 %b, i32 %c) #2
+ ret i32 %call
+}
OpenPOWER on IntegriCloud