Skip to content

[DA] Dependence analysis does not handle array accesses of different sizes #116630

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

sebpop
Copy link
Contributor

@sebpop sebpop commented Nov 18, 2024

This fixes bug #16183 where the elements of a same array are accesses as i32 and i64. This is not handled by the array dependence analysis.

@llvmbot
Copy link
Member

llvmbot commented Nov 18, 2024

@llvm/pr-subscribers-testing-tools

@llvm/pr-subscribers-llvm-analysis

Author: Sebastian Pop (sebpop)

Changes

This fixes bug #16183 where the elements of a same array are accesses as i32 and i64. This is not handled by the array dependence analysis.


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

2 Files Affected:

  • (modified) llvm/lib/Analysis/DependenceAnalysis.cpp (+7-1)
  • (added) llvm/test/Analysis/DependenceAnalysis/DifferentAccessSize.ll (+15)
diff --git a/llvm/lib/Analysis/DependenceAnalysis.cpp b/llvm/lib/Analysis/DependenceAnalysis.cpp
index a4a98ea0bae146..c1028effcfc1bc 100644
--- a/llvm/lib/Analysis/DependenceAnalysis.cpp
+++ b/llvm/lib/Analysis/DependenceAnalysis.cpp
@@ -730,8 +730,14 @@ static AliasResult underlyingObjectsAlias(AAResults *AA,
   const Value *BObj = getUnderlyingObject(LocB.Ptr);
 
   // If the underlying objects are the same, they must alias
-  if (AObj == BObj)
+  if (AObj == BObj) {
+    // The dependence test gets confused if the size of the memory accesses
+    // differ.
+    if (LocA.Size != LocB.Size)
+      return AliasResult::MayAlias;
+
     return AliasResult::MustAlias;
+  }
 
   // We may have hit the recursion limit for underlying objects, or have
   // underlying objects where we don't know they will alias.
diff --git a/llvm/test/Analysis/DependenceAnalysis/DifferentAccessSize.ll b/llvm/test/Analysis/DependenceAnalysis/DifferentAccessSize.ll
new file mode 100644
index 00000000000000..4d5da005ea437b
--- /dev/null
+++ b/llvm/test/Analysis/DependenceAnalysis/DifferentAccessSize.ll
@@ -0,0 +1,15 @@
+; RUN: opt < %s -disable-output "-passes=print<da>" -aa-pipeline=basic-aa 2>&1 \
+; RUN: | FileCheck %s
+
+; The dependence test does not handle array accesses of different sizes: i32 and i64.
+; Bug 16183 - https://github.com/llvm/llvm-project/issues/16183
+; CHECK-LABEL: bug16183_alias
+; CHECK: da analyze - confused!
+
+define i64 @bug16183_alias(i32* nocapture %A) {
+entry:
+  %arrayidx = getelementptr inbounds i32, ptr %A, i64 1
+  store i32 2, ptr %arrayidx, align 4
+  %0 = load i64, ptr %A, align 8
+  ret i64 %0
+}

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

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

This looks like something that should be checked at a higher level than underlyingObjectsAlias, because the access size is not relevant to determine whether the underlying objects alias.

@sebpop
Copy link
Contributor Author

sebpop commented Jan 7, 2025

I believe I addressed all the comments.
@nikic could you please have a look again and approve?
Thank you.

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

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

Looking a bit more closely, I'm not sure that "different access sizes" is really the core issue here.

For example, consider this variant of your test case:

define i32 @bug16183_alias(ptr nocapture %A) {
entry:
  %arrayidx = getelementptr inbounds i8, ptr %A, i64 2
  store i32 2, ptr %arrayidx, align 1 
  %0 = load i32, ptr %A, align 1
  ret i32 %0
}

This has equal access sizes, but the two accesses still overlap, because the GEP is only by half the access width. It currently reports da analyze - none! and wouldn't be fixed by your patch.

Without looking at the implementation, I expect the issue here is that the code does not verify that the access sizes and the access stride are compatible.

Value *SrcPtr = getLoadStorePointerOperand(Src);
Value *DstPtr = getLoadStorePointerOperand(Dst);
const MemoryLocation &LocA = MemoryLocation::get(Dst);
const MemoryLocation &LocB = MemoryLocation::get(Src);
Copy link
Contributor

Choose a reason for hiding this comment

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

LocA, LocB -> LocSrc, LocDst or SrcLoc, DstLoc maybe?

@@ -3632,6 +3635,8 @@ DependenceInfo::depends(Instruction *Src, Instruction *Dst,

unsigned Pairs = 1;
SmallVector<Subscript, 2> Pair(Pairs);
Value *SrcPtr = getLoadStorePointerOperand(Src);
Value *DstPtr = getLoadStorePointerOperand(Dst);
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you use const Value *SrcPtr = LocA.Value; here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, I can't use const here: SE->getSCEV takes a Value*:

const llvm::SCEV* llvm::ScalarEvolution::getSCEV(llvm::Value*)

; CHECK-LABEL: bug16183_alias
; CHECK: da analyze - confused!

define i64 @bug16183_alias(i32* nocapture %A) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
define i64 @bug16183_alias(i32* nocapture %A) {
define i64 @bug16183_alias(ptr nocapture %A) {

Copy link

github-actions bot commented Jan 18, 2025

✅ With the latest revision this PR passed the undef deprecator.

@sebpop
Copy link
Contributor Author

sebpop commented Jan 18, 2025

Looking a bit more closely, I'm not sure that "different access sizes" is really the core issue here.

[...] the code does not verify that the access sizes and the access stride are compatible.

This is more difficult to solve. Please see separate patch #123436 that describes the issue. DA is a symbolic solver that needs to collect a set of assumptions under which the DA produces correct results. We need to implement something similar to what Polly does in collecting a set of symbolic constraints, and those get generated as a runtime test versioning the loops generated by Polly.

sjoerdmeijer added a commit to sjoerdmeijer/llvm-project that referenced this pull request Jan 29, 2025
This is a work in progress patch to enable loop-interchange by default
and is a continuation of the RFC:

https://discourse.llvm.org/t/enabling-loop-interchange/82589

Basically, we promised to fix any compile-time and correctness issues in
the different components involved here (loop-interchange and dependence
analaysis.) before discussing enabling interchange by default. We think
are close to complete this; I would like to explain where we are and
wanted to check if there are any thoughts or concerns. A quick overview
of the correctness and compile-time improvements that we have made include:

Correctness:
- [LoopInterchange] Remove 'S' Scalar Dependencies (llvm#119345)
- [LoopInterchange] Fix overflow in cost calculation (llvm#111807)
- [LoopInterchange] Handle LE and GE correctly (PR llvm#124901) @kasuga-fj
- [DA] disambiguate evolution of base addresses (llvm#116628)

Compile-times:
- [LoopInterchange] Constrain number of load/stores in a loop (llvm#118973)
- [LoopInterchange] Bail out early if minimum loop nest is not met (llvm#115128)
- [LoopInterchange] Hoist isComputableLoopNest() in the control flow (llvm#124247)

And in terms of remaining work, we think we are very close to fixing
these depenence analysis issues:
- [DA] do not handle array accesses of different offsets (llvm#123436)
- [DA] Dependence analysis does not handle array accesses of different sizes (llvm#116630)
- [DA] use NSW arithmetic llvm#116632

The compile-time increase with a geomean increase of 0.19% looks good
(after committing llvm#124247), I think:

  stage1-O3:
  Benchmark
  kimwitu++        +0.10%
  sqlite3          +0.14%
  consumer-typeset +0.07%
  Bullet           +0.06%
  tramp3d-v4       +0.21%
  mafft            +0.39%
  ClamAVi          +0.06%
  lencod           +0.61%
  SPASS            +0.17%
  7zip             +0.08%
  geomean          +0.19%

See also:
http://llvm-compile-time-tracker.com/compare.php?from=19a7fe03b4f58c4f73ea91d5e63bc4c6e61f987b&to=b24f1367d68ee675ea93ecda4939208c6b68ae4b&stat=instructions%3Au

We might want to look into lencod to see if we can improve more, but not
sure it is strictly necessary.
…sizes

This fixes bug llvm#16183
where the elements of a same array are accesses as i32 and i64.
This is not handled by the array dependence analysis.
@sebpop
Copy link
Contributor Author

sebpop commented Jan 31, 2025

@nikic can you check if we can commit this patch independently of #123436

Thanks!

@sebpop
Copy link
Contributor Author

sebpop commented Feb 20, 2025

Hi @nikic,
#123436 fixes the test you mentioned above in #116630 (review)
Both #123436 and this PR #116630 are ready for review.


FullDependence Result(Src, Dst, PossiblyLoopIndependent, CommonLevels);
++TotalArrayPairs;
if (DstLoc.Size != SrcLoc.Size) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't we need to check if they are precise or not (with calling isPrecise)?

if (DstLoc.Size != SrcLoc.Size) {
// The dependence test gets confused if the size of the memory accesses
// differ.
LLVM_DEBUG(dbgs() << "can't analyze must alias with different sizes\n");
Copy link
Contributor

Choose a reason for hiding this comment

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

Only "must alias"?

@sebpop
Copy link
Contributor Author

sebpop commented May 9, 2025

This will be committed together with #123436

@sebpop sebpop closed this May 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants