summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Wennborg <hans@hanshq.net>2014-06-20 00:38:12 +0000
committerHans Wennborg <hans@hanshq.net>2014-06-20 00:38:12 +0000
commit4dc895164a8b3a26792dc7fe5db391e7218968be (patch)
tree11accff7423f33d9dc3307047c34bbce208f499a
parent9801b253ad3be9d9151e78e738115fa7725db7ff (diff)
downloadbcm5719-llvm-4dc895164a8b3a26792dc7fe5db391e7218968be.tar.gz
bcm5719-llvm-4dc895164a8b3a26792dc7fe5db391e7218968be.zip
Don't build switch lookup tables for dllimport or TLS variables
We would previously put dllimport variables in switch lookup tables, which doesn't work because the address cannot be used in a constant initializer. This is basically the same problem that we have in PR19955. Putting TLS variables in switch tables also desn't work, because the address of such a variable is not constant. Differential Revision: http://reviews.llvm.org/D4220 llvm-svn: 211331
-rw-r--r--llvm/include/llvm/IR/Constant.h3
-rw-r--r--llvm/lib/IR/Constants.cpp53
-rw-r--r--llvm/lib/Transforms/Utils/SimplifyCFG.cpp4
-rw-r--r--llvm/test/Transforms/SimplifyCFG/X86/switch_to_lookup_table.ll52
4 files changed, 92 insertions, 20 deletions
diff --git a/llvm/include/llvm/IR/Constant.h b/llvm/include/llvm/IR/Constant.h
index 39c7c37dafd..257bb80f211 100644
--- a/llvm/include/llvm/IR/Constant.h
+++ b/llvm/include/llvm/IR/Constant.h
@@ -71,6 +71,9 @@ public:
/// isThreadDependent - Return true if the value can vary between threads.
bool isThreadDependent() const;
+ /// Return true if the value is dependent on a dllimport variable.
+ bool isDLLImportDependent() const;
+
/// isConstantUsed - Return true if the constant has users other than constant
/// exprs and other dangling things.
bool isConstantUsed() const;
diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp
index aa26cff6a7b..5851625383b 100644
--- a/llvm/lib/IR/Constants.cpp
+++ b/llvm/lib/IR/Constants.cpp
@@ -278,35 +278,48 @@ bool Constant::canTrap() const {
return canTrapImpl(this, NonTrappingOps);
}
-/// isThreadDependent - Return true if the value can vary between threads.
-bool Constant::isThreadDependent() const {
- SmallPtrSet<const Constant*, 64> Visited;
- SmallVector<const Constant*, 64> WorkList;
- WorkList.push_back(this);
- Visited.insert(this);
+/// Check if C contains a GlobalValue for which Predicate is true.
+static bool
+ConstHasGlobalValuePredicate(const Constant *C,
+ bool (*Predicate)(const GlobalValue *)) {
+ SmallPtrSet<const Constant *, 8> Visited;
+ SmallVector<const Constant *, 8> WorkList;
+ WorkList.push_back(C);
+ Visited.insert(C);
while (!WorkList.empty()) {
- const Constant *C = WorkList.pop_back_val();
-
- if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(C)) {
- if (GV->isThreadLocal())
+ const Constant *WorkItem = WorkList.pop_back_val();
+ if (const auto *GV = dyn_cast<GlobalValue>(WorkItem))
+ if (Predicate(GV))
return true;
- }
-
- for (unsigned I = 0, E = C->getNumOperands(); I != E; ++I) {
- const Constant *D = dyn_cast<Constant>(C->getOperand(I));
- if (!D)
+ for (const Value *Op : WorkItem->operands()) {
+ const Constant *ConstOp = dyn_cast<Constant>(Op);
+ if (!ConstOp)
continue;
- if (Visited.insert(D))
- WorkList.push_back(D);
+ if (Visited.insert(ConstOp))
+ WorkList.push_back(ConstOp);
}
}
-
return false;
}
-/// isConstantUsed - Return true if the constant has users other than constant
-/// exprs and other dangling things.
+/// Return true if the value can vary between threads.
+bool Constant::isThreadDependent() const {
+ auto DLLImportPredicate = [](const GlobalValue *GV) {
+ return GV->isThreadLocal();
+ };
+ return ConstHasGlobalValuePredicate(this, DLLImportPredicate);
+}
+
+bool Constant::isDLLImportDependent() const {
+ auto DLLImportPredicate = [](const GlobalValue *GV) {
+ return GV->hasDLLImportStorageClass();
+ };
+ return ConstHasGlobalValuePredicate(this, DLLImportPredicate);
+}
+
+/// Return true if the constant has users other than constant exprs and other
+/// dangling things.
bool Constant::isConstantUsed() const {
for (const User *U : users()) {
const Constant *UC = dyn_cast<Constant>(U);
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index e155daf6fcc..ff2f2a03622 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -3313,6 +3313,10 @@ static bool ForwardSwitchConditionToPHI(SwitchInst *SI) {
static bool ValidLookupTableConstant(Constant *C) {
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(C))
return CE->isGEPWithNoNotionalOverIndexing();
+ if (C->isThreadDependent())
+ return false;
+ if (C->isDLLImportDependent())
+ return false;
return isa<ConstantFP>(C) ||
isa<ConstantInt>(C) ||
diff --git a/llvm/test/Transforms/SimplifyCFG/X86/switch_to_lookup_table.ll b/llvm/test/Transforms/SimplifyCFG/X86/switch_to_lookup_table.ll
index 81079b1aa5a..ee63d2c0c0f 100644
--- a/llvm/test/Transforms/SimplifyCFG/X86/switch_to_lookup_table.ll
+++ b/llvm/test/Transforms/SimplifyCFG/X86/switch_to_lookup_table.ll
@@ -918,3 +918,55 @@ return:
; CHECK: switch i32
; CHECK-NOT: @switch.table
}
+
+; Don't build tables for switches with TLS variables.
+@tls_a = thread_local global i32 0
+@tls_b = thread_local global i32 0
+@tls_c = thread_local global i32 0
+@tls_d = thread_local global i32 0
+define i32* @tls(i32 %x) {
+entry:
+ switch i32 %x, label %sw.default [
+ i32 0, label %return
+ i32 1, label %sw.bb1
+ i32 2, label %sw.bb2
+ ]
+sw.bb1:
+ br label %return
+sw.bb2:
+ br label %return
+sw.default:
+ br label %return
+return:
+ %retval.0 = phi i32* [ @tls_d, %sw.default ], [ @tls_c, %sw.bb2 ], [ @tls_b, %sw.bb1 ], [ @tls_a, %entry ]
+ ret i32* %retval.0
+; CHECK-LABEL: @tls(
+; CHECK: switch i32
+; CHECK-NOT: @switch.table
+}
+
+; Don't build tables for switches with dllimport variables.
+@dllimport_a = external dllimport global i32
+@dllimport_b = external dllimport global i32
+@dllimport_c = external dllimport global i32
+@dllimport_d = external dllimport global i32
+define i32* @dllimport(i32 %x) {
+entry:
+ switch i32 %x, label %sw.default [
+ i32 0, label %return
+ i32 1, label %sw.bb1
+ i32 2, label %sw.bb2
+ ]
+sw.bb1:
+ br label %return
+sw.bb2:
+ br label %return
+sw.default:
+ br label %return
+return:
+ %retval.0 = phi i32* [ @dllimport_d, %sw.default ], [ @dllimport_c, %sw.bb2 ], [ @dllimport_b, %sw.bb1 ], [ @dllimport_a, %entry ]
+ ret i32* %retval.0
+; CHECK-LABEL: @dllimport(
+; CHECK: switch i32
+; CHECK-NOT: @switch.table
+}
OpenPOWER on IntegriCloud