Skip to content

Commit 4dc8951

Browse files
committedJun 20, 2014
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
1 parent 9801b25 commit 4dc8951

File tree

4 files changed

+92
-20
lines changed

4 files changed

+92
-20
lines changed
 

‎llvm/include/llvm/IR/Constant.h

+3
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ class Constant : public User {
7171
/// isThreadDependent - Return true if the value can vary between threads.
7272
bool isThreadDependent() const;
7373

74+
/// Return true if the value is dependent on a dllimport variable.
75+
bool isDLLImportDependent() const;
76+
7477
/// isConstantUsed - Return true if the constant has users other than constant
7578
/// exprs and other dangling things.
7679
bool isConstantUsed() const;

‎llvm/lib/IR/Constants.cpp

+33-20
Original file line numberDiff line numberDiff line change
@@ -278,35 +278,48 @@ bool Constant::canTrap() const {
278278
return canTrapImpl(this, NonTrappingOps);
279279
}
280280

281-
/// isThreadDependent - Return true if the value can vary between threads.
282-
bool Constant::isThreadDependent() const {
283-
SmallPtrSet<const Constant*, 64> Visited;
284-
SmallVector<const Constant*, 64> WorkList;
285-
WorkList.push_back(this);
286-
Visited.insert(this);
281+
/// Check if C contains a GlobalValue for which Predicate is true.
282+
static bool
283+
ConstHasGlobalValuePredicate(const Constant *C,
284+
bool (*Predicate)(const GlobalValue *)) {
285+
SmallPtrSet<const Constant *, 8> Visited;
286+
SmallVector<const Constant *, 8> WorkList;
287+
WorkList.push_back(C);
288+
Visited.insert(C);
287289

288290
while (!WorkList.empty()) {
289-
const Constant *C = WorkList.pop_back_val();
290-
291-
if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(C)) {
292-
if (GV->isThreadLocal())
291+
const Constant *WorkItem = WorkList.pop_back_val();
292+
if (const auto *GV = dyn_cast<GlobalValue>(WorkItem))
293+
if (Predicate(GV))
293294
return true;
294-
}
295-
296-
for (unsigned I = 0, E = C->getNumOperands(); I != E; ++I) {
297-
const Constant *D = dyn_cast<Constant>(C->getOperand(I));
298-
if (!D)
295+
for (const Value *Op : WorkItem->operands()) {
296+
const Constant *ConstOp = dyn_cast<Constant>(Op);
297+
if (!ConstOp)
299298
continue;
300-
if (Visited.insert(D))
301-
WorkList.push_back(D);
299+
if (Visited.insert(ConstOp))
300+
WorkList.push_back(ConstOp);
302301
}
303302
}
304-
305303
return false;
306304
}
307305

308-
/// isConstantUsed - Return true if the constant has users other than constant
309-
/// exprs and other dangling things.
306+
/// Return true if the value can vary between threads.
307+
bool Constant::isThreadDependent() const {
308+
auto DLLImportPredicate = [](const GlobalValue *GV) {
309+
return GV->isThreadLocal();
310+
};
311+
return ConstHasGlobalValuePredicate(this, DLLImportPredicate);
312+
}
313+
314+
bool Constant::isDLLImportDependent() const {
315+
auto DLLImportPredicate = [](const GlobalValue *GV) {
316+
return GV->hasDLLImportStorageClass();
317+
};
318+
return ConstHasGlobalValuePredicate(this, DLLImportPredicate);
319+
}
320+
321+
/// Return true if the constant has users other than constant exprs and other
322+
/// dangling things.
310323
bool Constant::isConstantUsed() const {
311324
for (const User *U : users()) {
312325
const Constant *UC = dyn_cast<Constant>(U);

‎llvm/lib/Transforms/Utils/SimplifyCFG.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -3313,6 +3313,10 @@ static bool ForwardSwitchConditionToPHI(SwitchInst *SI) {
33133313
static bool ValidLookupTableConstant(Constant *C) {
33143314
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(C))
33153315
return CE->isGEPWithNoNotionalOverIndexing();
3316+
if (C->isThreadDependent())
3317+
return false;
3318+
if (C->isDLLImportDependent())
3319+
return false;
33163320

33173321
return isa<ConstantFP>(C) ||
33183322
isa<ConstantInt>(C) ||

‎llvm/test/Transforms/SimplifyCFG/X86/switch_to_lookup_table.ll

+52
Original file line numberDiff line numberDiff line change
@@ -918,3 +918,55 @@ return:
918918
; CHECK: switch i32
919919
; CHECK-NOT: @switch.table
920920
}
921+
922+
; Don't build tables for switches with TLS variables.
923+
@tls_a = thread_local global i32 0
924+
@tls_b = thread_local global i32 0
925+
@tls_c = thread_local global i32 0
926+
@tls_d = thread_local global i32 0
927+
define i32* @tls(i32 %x) {
928+
entry:
929+
switch i32 %x, label %sw.default [
930+
i32 0, label %return
931+
i32 1, label %sw.bb1
932+
i32 2, label %sw.bb2
933+
]
934+
sw.bb1:
935+
br label %return
936+
sw.bb2:
937+
br label %return
938+
sw.default:
939+
br label %return
940+
return:
941+
%retval.0 = phi i32* [ @tls_d, %sw.default ], [ @tls_c, %sw.bb2 ], [ @tls_b, %sw.bb1 ], [ @tls_a, %entry ]
942+
ret i32* %retval.0
943+
; CHECK-LABEL: @tls(
944+
; CHECK: switch i32
945+
; CHECK-NOT: @switch.table
946+
}
947+
948+
; Don't build tables for switches with dllimport variables.
949+
@dllimport_a = external dllimport global i32
950+
@dllimport_b = external dllimport global i32
951+
@dllimport_c = external dllimport global i32
952+
@dllimport_d = external dllimport global i32
953+
define i32* @dllimport(i32 %x) {
954+
entry:
955+
switch i32 %x, label %sw.default [
956+
i32 0, label %return
957+
i32 1, label %sw.bb1
958+
i32 2, label %sw.bb2
959+
]
960+
sw.bb1:
961+
br label %return
962+
sw.bb2:
963+
br label %return
964+
sw.default:
965+
br label %return
966+
return:
967+
%retval.0 = phi i32* [ @dllimport_d, %sw.default ], [ @dllimport_c, %sw.bb2 ], [ @dllimport_b, %sw.bb1 ], [ @dllimport_a, %entry ]
968+
ret i32* %retval.0
969+
; CHECK-LABEL: @dllimport(
970+
; CHECK: switch i32
971+
; CHECK-NOT: @switch.table
972+
}

0 commit comments

Comments
 (0)