[llvm-commits] [llvm] r149847 - in /llvm/trunk: lib/Transforms/IPO/GlobalOpt.cpp test/Transforms/GlobalOpt/atomic.ll
Nick Lewycky
nicholas at mxc.ca
Sun Feb 5 12:03:12 PST 2012
Nick Lewycky wrote:
> Author: nicholas
> Date: Sun Feb 5 13:56:38 2012
> New Revision: 149847
>
> URL: http://llvm.org/viewvc/llvm-project?rev=149847&view=rev
> Log:
> Teach GlobalOpt to handle atomic accesses to globals.
>
> * Most of the transforms come through intact by having each transformed load or
> store copy the ordering and synchronization scope of the original.
> * The transform that turns a global only accessed in main() into an alloca
> (since main is non-recursive) with a store of the initial value uses an
> unordered store
Doh, I meant NotAtomic, as nothing can race on this store. The code in
the commit uses NotAtomic here.
, since it's guaranteed to be the first thing to happen in main.
> (Threads may have started before main (!) but they can't have the address of a
> function local before the point in the entry block we insert our code.)
> * The heap-SRoA transforms are disabled in the face of atomic operations. This
> can probably be improved; it seems odd to have atomic accesses to an alloca
> that doesn't have its address taken.
>
> AnalyzeGlobal keeps track of the strongest ordering found in any use of the
> global. This is more information than we need right now, but it's cheap to
> compute and likely to be useful.
>
> Added:
> llvm/trunk/test/Transforms/GlobalOpt/atomic.ll
> Modified:
> llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp
>
> Modified: llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp?rev=149847&r1=149846&r2=149847&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp (original)
> +++ llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp Sun Feb 5 13:56:38 2012
> @@ -148,14 +148,27 @@
> /// HasPHIUser - Set to true if this global has a user that is a PHI node.
> bool HasPHIUser;
>
> + /// AtomicOrdering - Set to the strongest atomic ordering requirement.
> + AtomicOrdering Ordering;
> +
> GlobalStatus() : isCompared(false), isLoaded(false), StoredType(NotStored),
> StoredOnceValue(0), AccessingFunction(0),
> - HasMultipleAccessingFunctions(false), HasNonInstructionUser(false),
> - HasPHIUser(false) {}
> + HasMultipleAccessingFunctions(false),
> + HasNonInstructionUser(false), HasPHIUser(false),
> + Ordering(NotAtomic) {}
> };
>
> }
>
> +/// StrongerOrdering - Return the stronger of the two ordering. If the two
> +/// orderings are acquire and release, then return AcquireRelease.
> +///
> +static AtomicOrdering StrongerOrdering(AtomicOrdering X, AtomicOrdering Y) {
> + if (X == Acquire&& Y == Release) return AcquireRelease;
> + if (Y == Acquire&& X == Release) return AcquireRelease;
> + return (AtomicOrdering)std::max(X, Y);
> +}
> +
> /// SafeToDestroyConstant - It is safe to destroy a constant iff it is only used
> /// by constants itself. Note that constants cannot be cyclic, so this test is
> /// pretty easy to implement recursively.
> @@ -200,14 +213,16 @@
> }
> if (const LoadInst *LI = dyn_cast<LoadInst>(I)) {
> GS.isLoaded = true;
> - // Don't hack on volatile/atomic loads.
> - if (!LI->isSimple()) return true;
> + // Don't hack on volatile loads.
> + if (LI->isVolatile()) return true;
> + GS.Ordering = StrongerOrdering(GS.Ordering, LI->getOrdering());
> } else if (const StoreInst *SI = dyn_cast<StoreInst>(I)) {
> // Don't allow a store OF the address, only stores TO the address.
> if (SI->getOperand(0) == V) return true;
>
> - // Don't hack on volatile/atomic stores.
> - if (!SI->isSimple()) return true;
> + // Don't hack on volatile stores.
> + if (SI->isVolatile()) return true;
> + GS.Ordering = StrongerOrdering(GS.Ordering, SI->getOrdering());
>
> // If this is a direct store to the global (i.e., the global is a scalar
> // value, not an aggregate), keep more specific information about
> @@ -879,7 +894,8 @@
> while (!GV->use_empty()) {
> if (StoreInst *SI = dyn_cast<StoreInst>(GV->use_back())) {
> // The global is initialized when the store to it occurs.
> - new StoreInst(ConstantInt::getTrue(GV->getContext()), InitBool, SI);
> + new StoreInst(ConstantInt::getTrue(GV->getContext()), InitBool, false, 0,
> + SI->getOrdering(), SI->getSynchScope(), SI);
> SI->eraseFromParent();
> continue;
> }
> @@ -894,7 +910,10 @@
>
> ICmpInst *ICI = cast<ICmpInst>(LoadUse.getUser());
> // Replace the cmp X, 0 with a use of the bool value.
> - Value *LV = new LoadInst(InitBool, InitBool->getName()+".val", ICI);
> + // Sink the load to where the compare was, if atomic rules allow us to.
> + Value *LV = new LoadInst(InitBool, InitBool->getName()+".val", false, 0,
> + LI->getOrdering(), LI->getSynchScope(),
> + LI->isUnordered() ? (Instruction*)ICI : LI);
> InitBoolUsed = true;
> switch (ICI->getPredicate()) {
> default: llvm_unreachable("Unknown ICmp Predicate!");
> @@ -1454,6 +1473,7 @@
> static bool TryToOptimizeStoreOfMallocToGlobal(GlobalVariable *GV,
> CallInst *CI,
> Type *AllocTy,
> + AtomicOrdering Ordering,
> Module::global_iterator&GVI,
> TargetData *TD) {
> if (!TD)
> @@ -1503,6 +1523,9 @@
> // into multiple malloc'd arrays, one for each field. This is basically
> // SRoA for malloc'd memory.
>
> + if (Ordering != NotAtomic)
> + return false;
> +
> // If this is an allocation of a fixed size array of structs, analyze as a
> // variable size array. malloc [100 x struct],1 -> malloc struct, 100
> if (NElems == ConstantInt::get(CI->getArgOperand(0)->getType(), 1))
> @@ -1545,6 +1568,7 @@
> // OptimizeOnceStoredGlobal - Try to optimize globals based on the knowledge
> // that only one value (besides its initializer) is ever stored to the global.
> static bool OptimizeOnceStoredGlobal(GlobalVariable *GV, Value *StoredOnceVal,
> + AtomicOrdering Ordering,
> Module::global_iterator&GVI,
> TargetData *TD) {
> // Ignore no-op GEPs and bitcasts.
> @@ -1566,7 +1590,7 @@
> } else if (CallInst *CI = extractMallocCall(StoredOnceVal)) {
> Type *MallocType = getMallocAllocatedType(CI);
> if (MallocType&& TryToOptimizeStoreOfMallocToGlobal(GV, CI, MallocType,
> - GVI, TD))
> + Ordering, GVI, TD))
> return true;
> }
> }
> @@ -1642,7 +1666,8 @@
> if (LoadInst *LI = dyn_cast<LoadInst>(StoredVal)) {
> assert(LI->getOperand(0) == GV&& "Not a copy!");
> // Insert a new load, to preserve the saved value.
> - StoreVal = new LoadInst(NewGV, LI->getName()+".b", LI);
> + StoreVal = new LoadInst(NewGV, LI->getName()+".b", false, 0,
> + LI->getOrdering(), LI->getSynchScope(), LI);
> } else {
> assert((isa<CastInst>(StoredVal) || isa<SelectInst>(StoredVal))&&
> "This is not a form that we understand!");
> @@ -1650,11 +1675,13 @@
> assert(isa<LoadInst>(StoreVal)&& "Not a load of NewGV!");
> }
> }
> - new StoreInst(StoreVal, NewGV, SI);
> + new StoreInst(StoreVal, NewGV, false, 0,
> + SI->getOrdering(), SI->getSynchScope(), SI);
> } else {
> // Change the load into a load of bool then a select.
> LoadInst *LI = cast<LoadInst>(UI);
> - LoadInst *NLI = new LoadInst(NewGV, LI->getName()+".b", LI);
> + LoadInst *NLI = new LoadInst(NewGV, LI->getName()+".b", false, 0,
> + LI->getOrdering(), LI->getSynchScope(), LI);
> Value *NSI;
> if (IsOneZero)
> NSI = new ZExtInst(NLI, LI->getType(), "", LI);
> @@ -1808,7 +1835,7 @@
>
> // Try to optimize globals based on the knowledge that only one value
> // (besides its initializer) is ever stored to the global.
> - if (OptimizeOnceStoredGlobal(GV, GS.StoredOnceValue, GVI,
> + if (OptimizeOnceStoredGlobal(GV, GS.StoredOnceValue, GS.Ordering, GVI,
> getAnalysisIfAvailable<TargetData>()))
> return true;
>
>
> Added: llvm/trunk/test/Transforms/GlobalOpt/atomic.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GlobalOpt/atomic.ll?rev=149847&view=auto
> ==============================================================================
> --- llvm/trunk/test/Transforms/GlobalOpt/atomic.ll (added)
> +++ llvm/trunk/test/Transforms/GlobalOpt/atomic.ll Sun Feb 5 13:56:38 2012
> @@ -0,0 +1,10 @@
> +; RUN: opt -globalopt< %s -S -o - | FileCheck %s
> +
> + at GV1 = internal global i64 1
> +; CHECK: @GV1 = internal unnamed_addr constant i64 1
> +
> +define void @test1() {
> +entry:
> + %0 = load atomic i8* bitcast (i64* @GV1 to i8*) acquire, align 8
> + ret void
> +}
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
More information about the llvm-commits
mailing list