diff --git a/llvm/include/llvm/Analysis/MemoryDependenceAnalysis.h b/llvm/include/llvm/Analysis/MemoryDependenceAnalysis.h --- a/llvm/include/llvm/Analysis/MemoryDependenceAnalysis.h +++ b/llvm/include/llvm/Analysis/MemoryDependenceAnalysis.h @@ -363,6 +363,7 @@ PredIteratorCache PredCache; unsigned DefaultBlockScanLimit; + Optional ClobberOffset; public: MemoryDependenceResults(AAResults &AA, AssumptionCache &AC, @@ -468,6 +469,8 @@ /// Release memory in caches. void releaseMemory(); + Optional getClobberOffset() const { return ClobberOffset; } + private: MemDepResult getCallDependencyFrom(CallBase *Call, bool isReadOnlyCall, BasicBlock::iterator ScanIt, diff --git a/llvm/lib/Analysis/MemoryDependenceAnalysis.cpp b/llvm/lib/Analysis/MemoryDependenceAnalysis.cpp --- a/llvm/lib/Analysis/MemoryDependenceAnalysis.cpp +++ b/llvm/lib/Analysis/MemoryDependenceAnalysis.cpp @@ -512,16 +512,12 @@ if (R == AliasResult::MustAlias) return MemDepResult::getDef(Inst); -#if 0 // FIXME: Temporarily disabled. GVN is cleverly rewriting loads - // in terms of clobbering loads, but since it does this by looking - // at the clobbering load directly, it doesn't know about any - // phi translation that may have happened along the way. - // If we have a partial alias, then return this as a clobber for the // client to handle. - if (R == AliasResult::PartialAlias) + if (R == AliasResult::PartialAlias && R.hasOffset()) { + ClobberOffset = R.getOffset(); return MemDepResult::getClobber(Inst); -#endif + } // Random may-alias loads don't depend on each other without a // dependence. @@ -640,6 +636,7 @@ } MemDepResult MemoryDependenceResults::getDependency(Instruction *QueryInst) { + ClobberOffset = None; Instruction *ScanPos = QueryInst; // Check for a cached result diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp --- a/llvm/lib/Transforms/Scalar/GVN.cpp +++ b/llvm/lib/Transforms/Scalar/GVN.cpp @@ -998,9 +998,22 @@ // Can't forward from non-atomic to atomic without violating memory model. if (DepLoad != Load && Address && Load->isAtomic() <= DepLoad->isAtomic()) { - int Offset = analyzeLoadFromClobberingLoad(Load->getType(), Address, - DepLoad, DL); - + Type *LoadType = Load->getType(); + int Offset = -1; + + // If Memory Dependence Analysis reported clobber check, it was nested + // and can be extracted from the MD result + if (DepInfo.isClobber() && + canCoerceMustAliasedValueToLoad(DepLoad, LoadType, DL)) { + const auto ClobberOff = MD->getClobberOffset(); + // TODO: GVN has no deal with a negative offset. + Offset = (ClobberOff == None || ClobberOff.getValue() < 0) + ? -1 + : ClobberOff.getValue(); + } + if (Offset == -1) + Offset = + analyzeLoadFromClobberingLoad(LoadType, Address, DepLoad, DL); if (Offset != -1) { Res = AvailableValue::getLoad(DepLoad, Offset); return true; diff --git a/llvm/test/Transforms/GVN/PRE/rle.ll b/llvm/test/Transforms/GVN/PRE/rle.ll --- a/llvm/test/Transforms/GVN/PRE/rle.ll +++ b/llvm/test/Transforms/GVN/PRE/rle.ll @@ -699,14 +699,14 @@ %add = add nsw i32 %tmp2, %conv ret i32 %add -; TEMPORARILYDISABLED-LABEL: @load_load_partial_alias( -; TEMPORARILYDISABLED: load i32, i32* -; TEMPORARILYDISABLED-NOT: load -; TEMPORARILYDISABLED: lshr i32 {{.*}}, 8 -; TEMPORARILYDISABLED-NOT: load -; TEMPORARILYDISABLED: trunc i32 {{.*}} to i8 -; TEMPORARILYDISABLED-NOT: load -; TEMPORARILYDISABLED: ret i32 +; CHECK-LABEL: @load_load_partial_alias( +; CHECK: load i32, i32* +; CHECK-NOT: load +; CHECK: lshr i32 {{.*}}, {{8|16}} +; CHECK-NOT: load +; CHECK: trunc i32 {{.*}} to i8 +; CHECK-NOT: load +; CHECK: ret i32 } @@ -726,12 +726,36 @@ if.end: ret i32 52 -; TEMPORARILY_DISABLED-LABEL: @load_load_partial_alias_cross_block( -; TEMPORARILY_DISABLED: land.lhs.true: -; TEMPORARILY_DISABLED-NOT: load i8 -; TEMPORARILY_DISABLED: ret i32 %conv6 +; CHECK-LABEL: @load_load_partial_alias_cross_block( +; CHECK: land.lhs.true: +; CHECK-NOT: load i8 +; CHECK: ret i32 %conv6 } +; Cross block partial alias case with phi translation. +; FIXME: Currently we fail to clobber both partially aliased cases of load. +define i32 @load_load_partial_alias_cross_block_phi_trans(i8* %P) nounwind ssp { +entry: + %xx = bitcast i8* %P to i32* + %x1 = load i32, i32* %xx, align 4 + %cmp = icmp eq i32 %x1, 127 + br i1 %cmp, label %inc, label %end + +inc: + br label %end + +end: + %ind = phi i64 [1, %entry], [2, %inc] + %arrayidx4 = getelementptr inbounds i8, i8* %P, i64 %ind + %tmp5 = load i8, i8* %arrayidx4, align 1 + %conv6 = zext i8 %tmp5 to i32 + ret i32 %conv6 + +; CHECK-LABEL: @load_load_partial_alias_cross_block_phi_trans( +; CHECK: end: +; CHECK: load i8 +; CHECK: ret i32 %conv6 +} ;;===----------------------------------------------------------------------===;; ;; Load Widening