[llvm-commits] [Patch] Make GlobalOpt conservative with TLS vars (PR14309, 3.2-blocker)
Nick Lewycky
nicholas at mxc.ca
Tue Nov 13 11:47:38 PST 2012
Hans Wennborg wrote:
> Hi all,
>
> The attached patch takes a stab at fixing PR14309 which was marked as
> a 3.2-blocker.
>
> For global variables which get the same value stored into them
> everywhere, GlobalOpt will replace them with a constant. The problem
> is that a thread-local GlobalVariable looks like one value, but is
> different between threads.
Thanks for looking at this!
+/// isThreadDependent - Return true if the value can vary between threads.
+bool Constant::isThreadDependent() const {
+ if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(this))
+ return GV->isThreadLocal();
+
+ for (unsigned I = 0, E = getNumOperands(); I != E; ++I) {
+ if (const Constant *C = dyn_cast<Constant>(getOperand(I))) {
Use cast<> instead of dyn_cast<> here. Constant operands are always
constants.
+ if (C->isThreadDependent())
Two things. Firstly, I'm worried about stack depth, so I'd rather this
function maintained its own worklist. Secondly, I'm worried about
callers using this as part of their own constant visiting and
accidentally forming an O(n^2) loop, because this function doesn't
expose a cache or anything. You needn't do anything about point #2
though, there are many places in llvm to fall into that particular trap.
+ return true;
+ }
+ }
+
+ return false;
+}
@@ -234,6 +235,14 @@ static bool AnalyzeGlobal(const Value *V,
GlobalStatus &GS,
if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(
SI->getOperand(1))) {
Value *StoredVal = SI->getOperand(0);
+
+ if (Constant *C = dyn_cast<Constant>(StoredVal)) {
+ if (C->isThreadDependent()) {
+ // The stored value changes between threads; don't
track it.
+ return true;
+ }
+ }
+
if (StoredVal == GV->getInitializer()) {
if (GS.StoredType < GlobalStatus::isInitializerStored)
GS.StoredType = GlobalStatus::isInitializerStored;
This is really scary. I didn't understand why you needed to to this
until I understood the test. (I thought the bug was that we weren't
copying the TLS bit to the new global at line 1819. Nope!)
> My patch introduces Constant::isThreadDependent() which returns true
> for thread-local variables and constants which depend on them (e.g. a
> GEP into a thread-local array), and teaches GlobalOpt not to track
> such values.
> Please take a look!
>
> Also, if anyone thinks there are more passes which assume that
> thread-local GlobalVariables have the same value everywhere, please
> let me know.
The memdep users for a start; memdep itself, gvn, dse. I think what's
been saving us is that nobody marks their "create a thread" function as
readonly.
I think this is just another reason we need to kill ConstantExpr, and
forbid expressions involving TLS to be constant.
Nick
More information about the llvm-commits
mailing list