Index: lib/Analysis/BasicAliasAnalysis.cpp =================================================================== --- lib/Analysis/BasicAliasAnalysis.cpp +++ lib/Analysis/BasicAliasAnalysis.cpp @@ -976,6 +976,16 @@ return AliasAnalysis::MayAlias; } +/// isActualObject - Return true if V represents an actual object where we can +/// reason about the offsets directly, like an argument, alloca, or global +/// value. +static bool isActualObject(const Value *V) { + if (isa(V) || isa(V) || isa(V)) + return true; + + return false; +} + /// aliasGEP - Provide a bunch of ad-hoc rules to disambiguate a GEP instruction /// against another pointer. We know that V1 is a GEP, but we don't know /// anything about V2. UnderlyingV1 is GetUnderlyingObject(GEP1, DL), @@ -1024,37 +1034,45 @@ // identical. if ((BaseAlias == MayAlias) && V1Size == V2Size) { // Do the base pointers alias assuming type and size. - AliasResult PreciseBaseAlias = aliasCheck(UnderlyingV1, V1Size, - V1AAInfo, UnderlyingV2, - V2Size, V2AAInfo); - if (PreciseBaseAlias == NoAlias) { - // See if the computed offset from the common pointer tells us about the - // relation of the resulting pointer. - int64_t GEP2BaseOffset; - bool GEP2MaxLookupReached; - SmallVector GEP2VariableIndices; - const Value *GEP2BasePtr = - DecomposeGEPExpression(GEP2, GEP2BaseOffset, GEP2VariableIndices, - GEP2MaxLookupReached, *DL, AC2, DT); - const Value *GEP1BasePtr = - DecomposeGEPExpression(GEP1, GEP1BaseOffset, GEP1VariableIndices, - GEP1MaxLookupReached, *DL, AC1, DT); - // DecomposeGEPExpression and GetUnderlyingObject should return the - // same result except when DecomposeGEPExpression has no DataLayout. - if (GEP1BasePtr != UnderlyingV1 || GEP2BasePtr != UnderlyingV2) { - assert(!DL && - "DecomposeGEPExpression and GetUnderlyingObject disagree!"); - return MayAlias; - } - // If the max search depth is reached the result is undefined - if (GEP2MaxLookupReached || GEP1MaxLookupReached) - return MayAlias; + AliasResult PreciseBaseAlias = aliasCheck(UnderlyingV1, V1Size, V1AAInfo, + UnderlyingV2, V2Size, V2AAInfo); + // See if the computed offset from the common pointer tells us about the + // relation of the resulting pointer. + int64_t GEP2BaseOffset; + bool GEP2MaxLookupReached; + SmallVector GEP2VariableIndices; + const Value *GEP2BasePtr = + DecomposeGEPExpression(GEP2, GEP2BaseOffset, GEP2VariableIndices, + GEP2MaxLookupReached, *DL, AC2, DT); + const Value *GEP1BasePtr = + DecomposeGEPExpression(GEP1, GEP1BaseOffset, GEP1VariableIndices, + GEP1MaxLookupReached, *DL, AC1, DT); + // DecomposeGEPExpression and GetUnderlyingObject should return the + // same result except when DecomposeGEPExpression has no DataLayout. + if (GEP1BasePtr != UnderlyingV1 || GEP2BasePtr != UnderlyingV2) { + assert(!DL && + "DecomposeGEPExpression and GetUnderlyingObject disagree!"); + return MayAlias; + } + // If the max search depth is reached the result is undefined + if (GEP2MaxLookupReached || GEP1MaxLookupReached) + return MayAlias; - // Same offsets. + if (PreciseBaseAlias == NoAlias) { + // If they have the same offsets, and the underlying object is noalias, + // they must not alias if (GEP1BaseOffset == GEP2BaseOffset && GEP1VariableIndices == GEP2VariableIndices) return NoAlias; GEP1VariableIndices.clear(); + } else { + // If these are both arguments, global variable, or alloca, and the + // [offset, offset+size] ranges don't overlap, they can't alias + if (isActualObject(UnderlyingV1) && isActualObject(UnderlyingV2) && + GEP1VariableIndices == GEP2VariableIndices) + if ((GEP2BaseOffset - (GEP1BaseOffset + V1Size) > 0) || + (GEP1BaseOffset - (GEP2BaseOffset + V2Size) > 0)) + return NoAlias; } } Index: test/Analysis/BasicAA/gep-alias.ll =================================================================== --- test/Analysis/BasicAA/gep-alias.ll +++ test/Analysis/BasicAA/gep-alias.ll @@ -228,3 +228,26 @@ ; CHECK-LABEL: @test12( ; CHECK: ret i32 %r } + +%struct.S03 = type { i16, [4 x %struct.S00], i16 } +%struct.S00 = type { i8, i16, i32, i32 } + +; We should be able to determine the second store and the load do not conflict, +; but the first store and the load are must alias +define i32 @test13(%struct.S03* %a, %struct.S03* %b) { + %1 = getelementptr inbounds %struct.S03, %struct.S03* %a, i32 0, i32 1 + %2 = getelementptr inbounds [4 x %struct.S00], [4 x %struct.S00]* %1, i32 0, i64 0 + %3 = getelementptr inbounds %struct.S00, %struct.S00* %2, i32 0, i32 2 + store i32 1, i32* %3, align 4 + %4 = getelementptr inbounds %struct.S03, %struct.S03* %b, i32 0, i32 1 + %5 = getelementptr inbounds [4 x %struct.S00], [4 x %struct.S00]* %4, i32 0, i64 1 + %6 = getelementptr inbounds %struct.S00, %struct.S00* %5, i32 0, i32 2 + store i32 2, i32* %6, align 4 + %7 = getelementptr inbounds %struct.S03, %struct.S03* %a, i32 0, i32 1 + %8 = getelementptr inbounds [4 x %struct.S00], [4 x %struct.S00]* %7, i32 0, i64 0 + %9 = getelementptr inbounds %struct.S00, %struct.S00* %8, i32 0, i32 2 + %10 = load i32, i32* %9, align 4 +; CHECK-LABEL: @test13 +; CHECK: ret i32 1 + ret i32 %10 +}