Index: include/llvm/Analysis/Loads.h =================================================================== --- include/llvm/Analysis/Loads.h +++ include/llvm/Analysis/Loads.h @@ -21,6 +21,7 @@ class AliasAnalysis; class DataLayout; class MDNode; +class StoreInst; /// isSafeToLoadUnconditionally - Return true if we know that executing a load /// from this value cannot trap. If it is not obviously safe to load from the @@ -53,6 +54,11 @@ AliasAnalysis *AA = nullptr, AAMDNodes *AATags = nullptr); +/// ExtractValueFromStoredAggregate - Check if the pointer Ptr points +/// into an aggregate stored by the SI in a way that allows to extract the +/// value that it points at. If so return that value. +Value *ExtractValueFromStoredAggregate(Value *Ptr, StoreInst *SI); + } #endif Index: lib/Analysis/Loads.cpp =================================================================== --- lib/Analysis/Loads.cpp +++ lib/Analysis/Loads.cpp @@ -226,6 +226,12 @@ return SI->getOperand(0); } + if (Value *V = ExtractValueFromStoredAggregate(Ptr, SI)) { + if (AATags) + SI->getAAMetadata(*AATags); + return V; + } + // If both StrippedPtr and StorePtr reach all the way to an alloca or // global and they are different, ignore the store. This is a trivial form // of alias analysis that is important for reg2mem'd code. @@ -265,3 +271,27 @@ // block. return nullptr; } + +/// ExtractValueFromStoredAggregate - Check if the pointer Ptr points +/// into an aggregate stored by the SI in a way that allows to extract the +/// value that it points at. If so return that value. +Value *llvm::ExtractValueFromStoredAggregate(Value *Ptr, StoreInst *SI) { + // If this load is through a GEPI, we can possibly extract the loaded value + // from the stored aggregate + if (GetElementPtrInst *GEPI = dyn_cast(Ptr)) { + Value *StoredVal = SI->getValueOperand(); + if (StoredVal->getType()->isAggregateType() && + GEPI->getOperand(0) == SI->getPointerOperand() && + GEPI->isInBounds() && GEPI->hasAllConstantIndices() && + cast(GEPI->getOperand(1))->isZero()) { + std::vector Indices; + Indices.reserve(GEPI->getNumIndices()); + for (auto II = GEPI->idx_begin() + 1, IE = GEPI->idx_end(); II != IE; ++II) + Indices.push_back(cast(*II)->getSExtValue()); + + return FindInsertedValue(StoredVal, Indices); + } + } + + return nullptr; +} Index: lib/Transforms/Scalar/GVN.cpp =================================================================== --- lib/Transforms/Scalar/GVN.cpp +++ lib/Transforms/Scalar/GVN.cpp @@ -1417,6 +1417,12 @@ continue; } } + + if (Value *V = ExtractValueFromStoredAggregate( + LI->getPointerOperand(), DepSI)) { + ValuesPerBlock.push_back(AvailableValueInBlock::get(DepBB, V)); + continue; + } } // Check to see if we have something like this: @@ -1480,6 +1486,12 @@ // Reject loads and stores that are to the same address but are of // different types if we have to. if (S->getValueOperand()->getType() != LI->getType()) { + if (Value *V = ExtractValueFromStoredAggregate( + LI->getPointerOperand(), S)) { + ValuesPerBlock.push_back(AvailableValueInBlock::get(DepBB, V)); + continue; + } + // If the stored value is larger or equal to the loaded value, we can // reuse it. if (!DL || !CanCoerceMustAliasedValueToLoad(S->getValueOperand(), @@ -1888,8 +1900,23 @@ } } - // If the value isn't available, don't do anything! if (Dep.isClobber()) { + // Check if the load is fed by a store of an aggregate from which we can + // extract the value + if (StoreInst *DepSI = dyn_cast(Dep.getInst())) { + if (Value *AvailVal = ExtractValueFromStoredAggregate( + L->getPointerOperand(), DepSI)) { + // Replace the load! + L->replaceAllUsesWith(AvailVal); + if (AvailVal->getType()->getScalarType()->isPointerTy()) + MD->invalidateCachedPointerInfo(AvailVal); + markInstructionForDeletion(L); + ++NumGVNLoad; + return true; + } + } + + // If the value isn't available, don't do anything! DEBUG( // fast print dep, using operator<< on instruction is too slow. dbgs() << "GVN: load "; @@ -1922,7 +1949,10 @@ // actually have the same type. See if we know how to reuse the stored // value (depending on its type). if (StoredVal->getType() != L->getType()) { - if (DL) { + if (Value *V = ExtractValueFromStoredAggregate( + L->getPointerOperand(), DepSI)) + StoredVal = V; + else if (DL) { StoredVal = CoerceAvailableValueToLoadType(StoredVal, L->getType(), L, *DL); if (!StoredVal) Index: test/Transforms/GVN/load-from-fca.ll =================================================================== --- /dev/null +++ test/Transforms/GVN/load-from-fca.ll @@ -0,0 +1,49 @@ +; RUN: opt -S -basicaa -gvn < %s | FileCheck %s + +define i8 @local_load_from_fca_def({ i8, i8 }* %tmp) { +block1: + store { i8, i8 } { i8 0, i8 1 }, { i8, i8 }* %tmp + %ptr = getelementptr inbounds { i8, i8 }* %tmp, i64 0, i32 0 + %val = load i8* %ptr + ret i8 %val +; CHECK-NOT: %val = load i8* %ptr +; CHECK: ret i8 0 +} + +define i8 @local_load_from_fca_clobber({ i8, i8 }* %tmp) { +block1: + store { i8, i8 } { i8 0, i8 1 }, { i8, i8 }* %tmp + %ptr = getelementptr inbounds { i8, i8 }* %tmp, i64 0, i32 1 + %val = load i8* %ptr + ret i8 %val +; CHECK-NOT: %val = load i8* %ptr +; CHECK: ret i8 1 +} + +define i8 @nonlocal_load_from_fca_def({ i8, i8 }* %tmp, i1 %c) { +block1: + %ptr = getelementptr inbounds { i8, i8 }* %tmp, i64 0, i32 0 + br i1 %c, label %then, label %out +then: + br label %out +out: + store { i8, i8 } { i8 2, i8 3 }, { i8, i8 }* %tmp + %val = load i8* %ptr + ret i8 %val +; CHECK-NOT: %val = load i8* %ptr +; CHECK: ret i8 2 +} + +define i8 @nonlocal_load_from_fca_clobber({ i8, i8 }* %tmp, i1 %c) { +block1: + store { i8, i8 } { i8 2, i8 3 }, { i8, i8 }* %tmp + br i1 %c, label %then, label %out +then: + br label %out +out: + %ptr = getelementptr inbounds { i8, i8 }* %tmp, i64 0, i32 1 + %val = load i8* %ptr + ret i8 %val +; CHECK-NOT: %val = load i8* %ptr +; CHECK: ret i8 3 +}