Skip to content

Conversation

nikic
Copy link
Contributor

@nikic nikic commented Aug 6, 2024

If the GEP is both nuw and inbounds/nusw, the offset is non-negative. Pass this information to CastedValue and make use of it when determining the value range.

Proof for nusw+nuw->nneg: https://alive2.llvm.org/ce/z/a_CKAw
Proof for the test case: https://alive2.llvm.org/ce/z/yJ3ymP

If the GEP is both nuw and inbounds/nusw, the offset is
non-negative. Pass this information to CastedValue and make use
of it when determining the value range.

Proof for nusw+nuw->nneg: https://alive2.llvm.org/ce/z/a_CKAw
Proof for the test case: https://alive2.llvm.org/ce/z/yJ3ymP
@llvmbot llvmbot added the llvm:analysis Includes value tracking, cost tables and constant folding label Aug 6, 2024
@llvmbot
Copy link
Member

llvmbot commented Aug 6, 2024

@llvm/pr-subscribers-llvm-analysis

Author: Nikita Popov (nikic)

Changes

If the GEP is both nuw and inbounds/nusw, the offset is non-negative. Pass this information to CastedValue and make use of it when determining the value range.

Proof for nusw+nuw->nneg: https://alive2.llvm.org/ce/z/a_CKAw
Proof for the test case: https://alive2.llvm.org/ce/z/yJ3ymP


Full diff: https://github.com/llvm/llvm-project/pull/102141.diff

2 Files Affected:

  • (modified) llvm/lib/Analysis/BasicAliasAnalysis.cpp (+8-2)
  • (added) llvm/test/Analysis/BasicAA/nusw_nuw_nonneg.ll (+20)
diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
index 33131d80b35fa..7bfb23e14aaa7 100644
--- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
@@ -337,6 +337,10 @@ struct CastedValue {
     assert(N.getBitWidth() == V->getType()->getPrimitiveSizeInBits() &&
            "Incompatible bit width");
     if (TruncBits) N = N.truncate(N.getBitWidth() - TruncBits);
+    if (IsNonNegative && !N.isAllNonNegative())
+      N = N.intersectWith(
+          ConstantRange(APInt::getZero(N.getBitWidth()),
+                        APInt::getSignedMinValue(N.getBitWidth())));
     if (SExtBits) N = N.signExtend(N.getBitWidth() + SExtBits);
     if (ZExtBits) N = N.zeroExtend(N.getBitWidth() + ZExtBits);
     return N;
@@ -693,15 +697,17 @@ BasicAAResult::DecomposeGEPExpression(const Value *V, const DataLayout &DL,
 
       // If the integer type is smaller than the index size, it is implicitly
       // sign extended or truncated to index size.
+      bool NUSW = GEPOp->hasNoUnsignedSignedWrap();
+      bool NonNeg = NUSW && GEPOp->hasNoUnsignedWrap();
       unsigned Width = Index->getType()->getIntegerBitWidth();
       unsigned SExtBits = IndexSize > Width ? IndexSize - Width : 0;
       unsigned TruncBits = IndexSize < Width ? Width - IndexSize : 0;
       LinearExpression LE = GetLinearExpression(
-          CastedValue(Index, 0, SExtBits, TruncBits, false), DL, 0, AC, DT);
+          CastedValue(Index, 0, SExtBits, TruncBits, NonNeg), DL, 0, AC, DT);
 
       // Scale by the type size.
       unsigned TypeSize = AllocTypeSize.getFixedValue();
-      LE = LE.mul(APInt(IndexSize, TypeSize), GEPOp->hasNoUnsignedSignedWrap());
+      LE = LE.mul(APInt(IndexSize, TypeSize), NUSW);
       Decomposed.Offset += LE.Offset.sext(MaxIndexSize);
       APInt Scale = LE.Scale.sext(MaxIndexSize);
 
diff --git a/llvm/test/Analysis/BasicAA/nusw_nuw_nonneg.ll b/llvm/test/Analysis/BasicAA/nusw_nuw_nonneg.ll
new file mode 100644
index 0000000000000..84df62938e2f5
--- /dev/null
+++ b/llvm/test/Analysis/BasicAA/nusw_nuw_nonneg.ll
@@ -0,0 +1,20 @@
+; RUN: opt < %s -passes=aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+
+; CHECK-LABEL: test
+; CHECK: NoAlias:	i8* %p.minus.2, i8* %p.plus.2
+; CHECK: MayAlias:	i8* %p.idx.maybeneg, i8* %p.minus.2
+; CHECK: MayAlias:	i8* %p.idx.maybeneg, i8* %p.plus.2
+; CHECK: NoAlias:	i8* %p.idx.nneg, i8* %p.minus.2
+; CHECK: MayAlias:	i8* %p.idx.nneg, i8* %p.plus.2
+; CHECK: MustAlias:	i8* %p.idx.maybeneg, i8* %p.idx.nneg
+define void @test(ptr %p, i64 %idx) {
+  %p.minus.2 = getelementptr i8, ptr %p, i64 -2
+  %p.plus.2 = getelementptr i8, ptr %p, i64 2
+  %p.idx.maybeneg = getelementptr inbounds i8, ptr %p, i64 %idx
+  %p.idx.nneg = getelementptr nuw nusw i8, ptr %p, i64 %idx
+  load i8, ptr %p.minus.2
+  load i8, ptr %p.plus.2
+  load i8, ptr %p.idx.maybeneg
+  load i8, ptr %p.idx.nneg
+  ret void
+}

Copy link
Contributor

@hazzlim hazzlim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - thanks for the change :)

@nikic nikic merged commit 3c87f66 into llvm:main Aug 7, 2024
@nikic nikic deleted the basicaa-nusw-nuw-nonneg branch August 7, 2024 10:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
llvm:analysis Includes value tracking, cost tables and constant folding
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants