This is an archive of the discontinued LLVM Phabricator instance.

[DependenceAnalysis] Guard analysis using getPointerBase()
ClosedPublic

Authored by efriedma on Jul 15 2021, 1:53 PM.

Details

Summary

D104806 broke some uses of getMinusSCEV() in DependenceAnalysis: subtraction with different pointer bases returns a SCEVCouldNotCompute. Make sure we avoid cases involving such subtractions.

Diff Detail

Event Timeline

efriedma created this revision.Jul 15 2021, 1:53 PM
efriedma requested review of this revision.Jul 15 2021, 1:53 PM
Herald added a project: Restricted Project. · View Herald TranscriptJul 15 2021, 1:53 PM
reames accepted this revision.Jul 15 2021, 2:14 PM

LGTM

I think I number of these queries could handle inequal base objects, but given there's no test coverage for it, it doesn't appear to matter.

This revision is now accepted and ready to land.Jul 15 2021, 2:14 PM
bmahjour added inline comments.Jul 15 2021, 2:37 PM
llvm/lib/Analysis/DependenceAnalysis.cpp
3556

We only get here if the two pointers MustAlias. If my understanding of MustAlias is correct (that it means precise and complete overlapping of memory), and if the two references are in the same loop, then comparing indexes seems reasonable. In that case, the effect of the following analysis should be as if src and dst SCEVs have their base pointers replaced with the same value. Not sure what's the best way to deal with such cases. Does it make sense to introduce a mode in getMinusSCEV where different base pointers can be permitted?

This revision was landed with ongoing or failed builds.Jul 15 2021, 2:57 PM
This revision was automatically updated to reflect the committed changes.
efriedma added inline comments.Jul 15 2021, 3:10 PM
llvm/lib/Analysis/DependenceAnalysis.cpp
3556

underlyingObjectsAlias(Src, Dst) == MustAlias is basically a slightly fancier version isIdentifiedObject(getUnderlyingObject(Src)) && isIdentifiedObject(getUnderlyingObject(Dst)) && getUnderlyingObject(Src) == getUnderlyingObject(Dst). The issue here is that getPointerBase() is less powerful than getUnderlyingObject().

It is possible to cast the operands of getMinusSCEV to integers using getPtrToIntExpr(); in that case, you won't get a SCEVCouldNotCompute. But then you end up with a SCEV containing something like ptrtoint(SrcSCEVPointerBase) - ptrtoint(DstSCEVPointerBase), which is basically impossible to analyze. So it seems simpler to just reject early.

efriedma added inline comments.Jul 15 2021, 3:28 PM
llvm/lib/Analysis/DependenceAnalysis.cpp
3556

Oh, also, there's been work to allow SCEV to look through LCSSA PHI nodes; that would allow DependenceAnalysis to analyze more cases. But that patch got reverted; not sure what the current status is.

artemrad added inline comments.
llvm/lib/Analysis/DependenceAnalysis.cpp
3556

This seems like a subset of cases we should be filtering out. Please also add checks for the access width being unaligned with the store/load size. In this case the base pointers are different but the accesses can still overlap. This case will not be caught by DependenceAnalysis.

define void @z0(i32* %A, i64 %n) nounwind uwtable ssp {
entry:
  %arrayidx = getelementptr inbounds i32, i32* %A, i64 %n
  %arrayidx_cast = bitcast i32* %arrayidx to i64*
  store i64 0, i64* %arrayidx_cast, align 4

; CHECK: da analyze - confused!
; CHECK: da analyze - confused!
; CHECK: da analyze - confused!
; CHECK: da analyze - none
; CHECK: da analyze - confused!
; CHECK: da analyze - confused!

  %add1 = add i64 %n, 1
  %arrayidx2 = getelementptr inbounds i32, i32* %A, i64 %add1
  %0 = load i32, i32* %arrayidx2, align 4
 
  ; Even if the load and store types are the same, if their
  ; alignments are smaller than the store size and they are
  ; accesses through something other than a straightforward
  ; gep, they can still overlap, as this access shows
  %arrayidx2_cast = bitcast i32* %arrayidx2 to i64*
  %1 = load i64, i64* %arrayidx2_cast, align 4
  ret void
}
efriedma added inline comments.Jul 16 2021, 4:43 PM
llvm/lib/Analysis/DependenceAnalysis.cpp
3556

Well, there are a few things we can do in that case:

  1. Bail out if we don't have two naturally aligned accesses of the same size.
  2. Perform multiple dependency checks, and merge the results. For example, if you have a size 4 access, and a size 8 access, you can treat the size 8 access as two size 4 accesses, and merge the results accordingly.
  3. Teach the dependence checks to use ranges, instead of plain indexes.

I'm afraid (1) will hurt performance. And I don't really want to sign up to do (2) or (3).

artemrad added inline comments.Jul 19 2021, 6:45 AM
llvm/lib/Analysis/DependenceAnalysis.cpp
3556

Well currently we do not bail out in the case of (1), so it is worse than loosing performance, we are giving incorrect results.

As for (2) and (3) completely agree this is a project and I did not mean to imply that you should undertake it. Apologies, that was not my intention.