[llvm] 83ded5d - re-land "[AA] Teach BasicAA to recognize basic GEP range information."

Clement Courbet via llvm-commits llvm-commits at lists.llvm.org
Mon Oct 11 01:04:40 PDT 2021


Author: Clement Courbet
Date: 2021-10-11T10:04:22+02:00
New Revision: 83ded5d3239170a430e49cde80ea40e68b9af230

URL: https://github.com/llvm/llvm-project/commit/83ded5d3239170a430e49cde80ea40e68b9af230
DIFF: https://github.com/llvm/llvm-project/commit/83ded5d3239170a430e49cde80ea40e68b9af230.diff

LOG: re-land "[AA] Teach BasicAA to recognize basic GEP range information."

Now that PR52104 is fixed.

Added: 
    llvm/test/Analysis/BasicAA/range.ll

Modified: 
    llvm/lib/Analysis/BasicAliasAnalysis.cpp
    llvm/test/Analysis/BasicAA/assume-index-positive.ll
    llvm/test/Analysis/BasicAA/sequential-gep.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
index 84e7683b9624..69f5cf025135 100644
--- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
@@ -31,6 +31,7 @@
 #include "llvm/IR/Argument.h"
 #include "llvm/IR/Attributes.h"
 #include "llvm/IR/Constant.h"
+#include "llvm/IR/ConstantRange.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/DerivedTypes.h"
@@ -312,6 +313,14 @@ struct ExtendedValue {
     return N;
   }
 
+  ConstantRange evaluateWith(ConstantRange N) const {
+    assert(N.getBitWidth() == V->getType()->getPrimitiveSizeInBits() &&
+           "Incompatible bit width");
+    if (SExtBits) N = N.signExtend(N.getBitWidth() + SExtBits);
+    if (ZExtBits) N = N.zeroExtend(N.getBitWidth() + ZExtBits);
+    return N;
+  }
+
   bool canDistributeOver(bool NUW, bool NSW) const {
     // zext(x op<nuw> y) == zext(x) op<nuw> zext(y)
     // sext(x op<nsw> y) == sext(x) op<nsw> sext(y)
@@ -1291,13 +1300,24 @@ AliasResult BasicAAResult::aliasGEP(
       return AliasResult::NoAlias;
 
     if (V1Size.hasValue() && V2Size.hasValue()) {
-      // Try to determine whether abs(VarIndex) > 0.
+      // Try to determine the range of values for VarIndex.
+      // VarIndexRange is such that:
+      //    (VarIndex <= -MinAbsVarIndex || MinAbsVarIndex <= VarIndex) &&
+      //    VarIndexRange.contains(VarIndex)
       Optional<APInt> MinAbsVarIndex;
+      Optional<ConstantRange> VarIndexRange;
       if (DecompGEP1.VarIndices.size() == 1) {
-        // VarIndex = Scale*V. If V != 0 then abs(VarIndex) >= abs(Scale).
+        // VarIndex = Scale*V.
         const VariableGEPIndex &Var = DecompGEP1.VarIndices[0];
-        if (isKnownNonZero(Var.Val.V, DL, 0, &AC, Var.CxtI, DT))
+        if (isKnownNonZero(Var.Val.V, DL, 0, &AC, Var.CxtI, DT)) {
+          // If V != 0 then abs(VarIndex) >= abs(Scale).
           MinAbsVarIndex = Var.Scale.abs();
+        }
+        ConstantRange R = Var.Val.evaluateWith(
+            computeConstantRange(Var.Val.V, true, &AC, Var.CxtI));
+        if (!R.isFullSet() && !R.isEmptySet())
+          VarIndexRange = R.sextOrTrunc(Var.Scale.getBitWidth())
+                              .multiply(ConstantRange(Var.Scale));
       } else if (DecompGEP1.VarIndices.size() == 2) {
         // VarIndex = Scale*V0 + (-Scale)*V1.
         // If V0 != V1 then abs(VarIndex) >= abs(Scale).
@@ -1316,12 +1336,26 @@ AliasResult BasicAAResult::aliasGEP(
         // The constant offset will have added at least +/-MinAbsVarIndex to it.
         APInt OffsetLo = DecompGEP1.Offset - *MinAbsVarIndex;
         APInt OffsetHi = DecompGEP1.Offset + *MinAbsVarIndex;
-        // Check that an access at OffsetLo or lower, and an access at OffsetHi
-        // or higher both do not alias.
+        // We know that Offset <= OffsetLo || Offset >= OffsetHi
         if (OffsetLo.isNegative() && (-OffsetLo).uge(V1Size.getValue()) &&
             OffsetHi.isNonNegative() && OffsetHi.uge(V2Size.getValue()))
           return AliasResult::NoAlias;
       }
+
+      if (VarIndexRange) {
+        ConstantRange OffsetRange =
+            VarIndexRange->add(ConstantRange(DecompGEP1.Offset));
+
+        // We know that Offset >= MinOffset.
+        // (MinOffset >= V2Size) => (Offset >= V2Size) => NoAlias.
+        if (OffsetRange.getSignedMin().sge(V2Size.getValue()))
+          return AliasResult::NoAlias;
+
+        // We know that Offset <= MaxOffset.
+        // (MaxOffset <= -V1Size) => (Offset <= -V1Size) => NoAlias.
+        if (OffsetRange.getSignedMax().sle(-V1Size.getValue()))
+          return AliasResult::NoAlias;
+      }
     }
 
     if (constantOffsetHeuristic(DecompGEP1, V1Size, V2Size, &AC, DT))

diff  --git a/llvm/test/Analysis/BasicAA/assume-index-positive.ll b/llvm/test/Analysis/BasicAA/assume-index-positive.ll
index 54eb34a2cdb9..bbe7263590cf 100644
--- a/llvm/test/Analysis/BasicAA/assume-index-positive.ll
+++ b/llvm/test/Analysis/BasicAA/assume-index-positive.ll
@@ -59,9 +59,9 @@ define void @test2(double* %ptr, i32 %skip) {
 define void @test3(double* %ptr, i32 %skip) {
 ; CHECK-LABEL: Function: test3: 4 pointers, 1 call sites
 ; CHECK-NEXT:  MustAlias:   <6 x double>* %col.ptr.1, double* %ptr
-; CHECK-NEXT:  MayAlias:    double* %col.ptr.2, double* %ptr
+; CHECK-NEXT:  NoAlias:     double* %col.ptr.2, double* %ptr
 ; CHECK-NEXT:  MayAlias:    <6 x double>* %col.ptr.1, double* %col.ptr.2
-; CHECK-NEXT:  MayAlias:    <6 x double>* %col.ptr.2.cast, double* %ptr
+; CHECK-NEXT:  NoAlias:     <6 x double>* %col.ptr.2.cast, double* %ptr
 ; CHECK-NEXT:  MayAlias:    <6 x double>* %col.ptr.1, <6 x double>* %col.ptr.2.cast
 ; CHECK-NEXT:  MustAlias:   <6 x double>* %col.ptr.2.cast, double* %col.ptr.2
 ; CHECK-NEXT:  NoModRef:  Ptr: double* %ptr <->  call void @llvm.assume(i1 %gt)

diff  --git a/llvm/test/Analysis/BasicAA/range.ll b/llvm/test/Analysis/BasicAA/range.ll
new file mode 100644
index 000000000000..5a3c09b57a0e
--- /dev/null
+++ b/llvm/test/Analysis/BasicAA/range.ll
@@ -0,0 +1,188 @@
+; RUN: opt < %s -basic-aa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+
+%struct.S = type { i32, [2 x i32], i32 }
+%struct.S2 = type { i32, [4 x i32], [4 x i32] }
+
+; CHECK: Function: t1
+; CHECK: NoAlias: i32* %gep1, i32* %gep2
+define void @t1(%struct.S* %s) {
+  %gep1 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 1
+  %gep2 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 0
+  ret void
+}
+
+; CHECK: Function: t2_fwd
+; CHECK: MayAlias: i32* %gep1, i32* %gep2
+define void @t2_fwd(%struct.S* %s, i32* %q) {
+  %in_array = load i32, i32* %q, !range !0
+  %gep1 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 %in_array
+  %gep2 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 0
+  ret void
+}
+
+; CHECK: Function: t2_rev
+; CHECK: MayAlias: i32* %gep1, i32* %gep2
+define void @t2_rev(%struct.S* %s, i32* %q) {
+  %in_array = load i32, i32* %q, !range !0
+  %gep1 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 0
+  %gep2 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 %in_array
+  ret void
+}
+
+; CHECK: Function: t3_fwd
+; CHECK: NoAlias: i32* %gep1, i32* %gep2
+define void @t3_fwd(%struct.S* %s, i32* %q) {
+  %knownzero = load i32, i32* %q, !range !1
+  %gep1 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 %knownzero
+  %gep2 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 1
+  ret void
+}
+
+; CHECK: Function: t3_rev
+; CHECK: NoAlias: i32* %gep1, i32* %gep2
+define void @t3_rev(%struct.S* %s, i32* %q) {
+  %knownzero = load i32, i32* %q, !range !1
+  %gep1 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 1
+  %gep2 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 %knownzero
+  ret void
+}
+
+; CHECK: Function: member_after
+; CHECK: NoAlias: i32* %gep1, i32* %gep2
+define void @member_after(%struct.S* %s, i32* %q) {
+  %in_array = load i32, i32* %q, !range !0
+  %gep1 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 %in_array
+  %gep2 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 2
+  ret void
+}
+
+; CHECK: Function: member_after_rev
+; CHECK: NoAlias: i32* %gep1, i32* %gep2
+define void @member_after_rev(%struct.S* %s, i32* %q) {
+  %in_array = load i32, i32* %q, !range !0
+  %gep2 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 2
+  %gep1 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 %in_array
+  ret void
+}
+
+; CHECK: Function: member_before
+; CHECK: NoAlias: i32* %gep1, i32* %gep2
+define void @member_before(%struct.S* %s, i32* %q) {
+  %in_array = load i32, i32* %q, !range !0
+  %gep1 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 %in_array
+  %gep2 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 0
+  ret void
+}
+
+; CHECK: Function: member_before_rev
+; CHECK: NoAlias: i32* %gep1, i32* %gep2
+define void @member_before_rev(%struct.S* %s, i32* %q) {
+  %in_array = load i32, i32* %q, !range !0
+  %gep2 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 0
+  %gep1 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 %in_array
+  ret void
+}
+
+; CHECK: Function: t5
+; CHECK-NEXT: MayAlias: %struct.S2* %s, i32* %q
+; CHECK-NEXT: MayAlias: %struct.S2* %s, i32* %gep1
+; CHECK-NEXT: MayAlias: i32* %gep1, i32* %q
+; CHECK-NEXT: PartialAlias (off 4): %struct.S2* %s, i32* %gep2
+; CHECK-NEXT: MayAlias: i32* %gep2, i32* %q
+; CHECK-NEXT: NoAlias: i32* %gep1, i32* %gep2
+define void @t5(%struct.S2* %s, i32* %q) {
+  %in_array = load i32, i32* %q, !range !3
+  %gep1 = getelementptr inbounds %struct.S2, %struct.S2* %s, i64 0, i32 2, i32 %in_array
+  %gep2 = getelementptr inbounds %struct.S2, %struct.S2* %s, i64 0, i32 1, i32 0
+  ret void
+}
+
+; CHECK: Function: t6
+; CHECK-NEXT: MayAlias: %struct.S2* %s, i32* %q
+; CHECK-NEXT: MayAlias: %struct.S2* %s, i32* %gep1
+; CHECK-NEXT: MayAlias: i32* %gep1, i32* %q
+; CHECK-NEXT: PartialAlias (off 16): %struct.S2* %s, i32* %gep2
+; CHECK-NEXT: MayAlias: i32* %gep2, i32* %q
+; CHECK-NEXT: MayAlias: i32* %gep1, i32* %gep2
+define void @t6(%struct.S2* %s, i32* %q) {
+  %in_array = load i32, i32* %q, !range !3
+  %gep1 = getelementptr inbounds %struct.S2, %struct.S2* %s, i64 0, i32 2, i32 %in_array
+  %gep2 = getelementptr inbounds %struct.S2, %struct.S2* %s, i64 0, i32 1, i32 3
+  ret void
+}
+
+; CHECK: Function: t7
+; CHECK-NEXT: MayAlias: %struct.S2* %s, i32* %q
+; CHECK-NEXT: MayAlias: %struct.S2* %s, i32* %gep1
+; CHECK-NEXT: MayAlias: i32* %gep1, i32* %q
+; CHECK-NEXT: PartialAlias (off 20): %struct.S2* %s, i32* %gep2
+; CHECK-NEXT: MayAlias: i32* %gep2, i32* %q
+; CHECK-NEXT: NoAlias: i32* %gep1, i32* %gep2
+define void @t7(%struct.S2* %s, i32* %q) {
+  %in_array = load i32, i32* %q, !range !4
+  %gep1 = getelementptr inbounds %struct.S2, %struct.S2* %s, i64 0, i32 2, i32 %in_array
+  %gep2 = getelementptr inbounds %struct.S2, %struct.S2* %s, i64 0, i32 2, i32 0
+  ret void
+}
+
+; CHECK: Function: t8
+; CHECK-NEXT: MayAlias: %struct.S2* %s, i32* %q
+; CHECK-NEXT: MayAlias: %struct.S2* %s, i32* %gep1
+; CHECK-NEXT: MayAlias: i32* %gep1, i32* %q
+; CHECK-NEXT: PartialAlias (off 24): %struct.S2* %s, i32* %gep2
+; CHECK-NEXT: MayAlias: i32* %gep2, i32* %q
+; CHECK-NEXT: MayAlias: i32* %gep1, i32* %gep2
+define void @t8(%struct.S2* %s, i32* %q) {
+  %in_array = load i32, i32* %q, !range !4
+  %gep1 = getelementptr inbounds %struct.S2, %struct.S2* %s, i64 0, i32 2, i32 %in_array
+  %gep2 = getelementptr inbounds %struct.S2, %struct.S2* %s, i64 0, i32 2, i32 1
+  ret void
+}
+
+; CHECK: Function: t9
+; CHECK-NEXT: MayAlias: %struct.S2* %s, i32* %q
+; CHECK-NEXT: MayAlias: %struct.S2* %s, i32* %gep1
+; CHECK-NEXT: MayAlias: i32* %gep1, i32* %q
+; CHECK-NEXT: PartialAlias (off 20): %struct.S2* %s, i32* %gep2
+; CHECK-NEXT: MayAlias: i32* %gep2, i32* %q
+; CHECK-NEXT: NoAlias: i32* %gep1, i32* %gep2
+define void @t9(%struct.S2* %s, i32* %q) {
+  %in_array = load i32, i32* %q, !range !5
+  %gep1 = getelementptr inbounds %struct.S2, %struct.S2* %s, i64 0, i32 1, i32 %in_array
+  %gep2 = getelementptr inbounds %struct.S2, %struct.S2* %s, i64 0, i32 2, i32 0
+  ret void
+}
+
+; CHECK: Function: t10
+; CHECK-NEXT: MayAlias: %struct.S2* %s, i32* %q
+; CHECK-NEXT: MayAlias: %struct.S2* %s, i32* %gep1
+; CHECK-NEXT: MayAlias: i32* %gep1, i32* %q
+; CHECK-NEXT: PartialAlias (off 4): %struct.S2* %s, i32* %gep2
+; CHECK-NEXT: MayAlias: i32* %gep2, i32* %q
+; CHECK-NEXT: MayAlias: i32* %gep1, i32* %gep2
+define void @t10(%struct.S2* %s, i32* %q) {
+  %in_array = load i32, i32* %q, !range !5
+  %gep1 = getelementptr inbounds %struct.S2, %struct.S2* %s, i64 0, i32 2, i32 %in_array
+  %gep2 = getelementptr inbounds %struct.S2, %struct.S2* %s, i64 0, i32 1, i32 0
+  ret void
+}
+
+; CHECK: Function: zeroext_index
+; CHECK-NEXT:  MayAlias:     [256 x i32]* %s, i8* %q
+; CHECK-NEXT:  MayAlias:     [256 x i32]* %s, i32* %gep
+; CHECK-NEXT:  MayAlias:     i32* %gep, i8* %q
+define void @zeroext_index([256 x i32]* %s, i8* %q) {
+  %a = load i8, i8* %q, !range !6
+  %in_array = zext i8 %a to i32
+  %gep = getelementptr inbounds [256 x i32], [256 x i32]* %s, i64 0, i32 %in_array
+  ret void
+}
+
+
+!0 = !{ i32 0, i32 2 }
+!1 = !{ i32 0, i32 1 }
+!2 = !{ i32 1, i32 2 }
+!3 = !{ i32 -2, i32 0 }
+!4 = !{ i32 1, i32 536870911 }
+!5 = !{ i32 -536870911, i32 4 }
+!6 = !{ i8 -2, i8 0 }

diff  --git a/llvm/test/Analysis/BasicAA/sequential-gep.ll b/llvm/test/Analysis/BasicAA/sequential-gep.ll
index d7a1af024cec..27fec52f5ec5 100644
--- a/llvm/test/Analysis/BasicAA/sequential-gep.ll
+++ b/llvm/test/Analysis/BasicAA/sequential-gep.ll
@@ -134,7 +134,7 @@ define void @non_zero_index_simple(i32* %p, i32* %q) {
 }
 
 ; CHECK-LABEL: non_zero_index_with_offset
-; CHECK: MayAlias: i32* %gep, i32* %p
+; CHECK: NoAlias: i32* %gep, i32* %p
 ; CHECK: NoAlias: i16* %gep.16, i32* %p
 define void @non_zero_index_with_offset(i32* %p, i32* %q) {
   %knownnonzero = load i32, i32* %q, !range !0
@@ -157,4 +157,4 @@ define void @non_zero_index_assume(i32* %p, i32 %knownnonzero) {
 
 declare void @llvm.assume(i1)
 
-!0 = !{ i32 1, i32 5 }
+!0 = !{ i32 1, i32 0 }


        


More information about the llvm-commits mailing list