; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 6
; RUN: opt < %s -disable-output -passes="print<da>" -da-dump-monotonicity-report \
; RUN:     -da-enable-monotonicity-check 2>&1 | FileCheck %s
; RUN: opt < %s -disable-output -passes="print<da>" 2>&1 | FileCheck %s -check-prefix=DISABLE-CHECK

;
; for (i = 0; i < (1ULL << 60); i++) {
;   A[i] = 1;
;
;   unsigned long long offset = i * 32 + (1ULL << 62);
;   // offset is positive when interpreted as a signed value.
;   // To prevent violating the size limitation for an allocated object.
;   if (offset < (1ULL << 63))
;     A[offset] = 2;
; }
;
; -----------------------------------------------------------------------------
;
; There is a dependency between the two stores. To detect it, we need to check
; the monotonicity and bail out the analysis since `offset` is not monotonic.
;
;  memory location  | first store (A[i]) | second store (A[offset])
; ------------------|--------------------|----------------------------
;  A[0]             | i = 0              | i = 2^59 - 2^57
;  A[2^60 - 32]     | i = 2^60 - 32      | i = 2^59 - 2^57 + 2^55 - 1
;
define void @f(ptr %A) {
; CHECK-LABEL: 'f'
; CHECK-NEXT:  Monotonicity check:
; CHECK-NEXT:    Inst: store i8 1, ptr %idx.0, align 1
; CHECK-NEXT:      Expr: {0,+,1}<nuw><nsw><%loop.header>
; CHECK-NEXT:      Monotonicity: MultivariateSignedMonotonic
; CHECK-NEXT:    Inst: store i8 2, ptr %idx.1, align 1
; CHECK-NEXT:      Expr: {4611686018427387904,+,32}<%loop.header>
; CHECK-NEXT:      Monotonicity: Unknown
; CHECK-NEXT:      Reason: {4611686018427387904,+,32}<%loop.header>
; CHECK-EMPTY:
; CHECK-NEXT:  Src: store i8 1, ptr %idx.0, align 1 --> Dst: store i8 1, ptr %idx.0, align 1
; CHECK-NEXT:    da analyze - none!
; CHECK-NEXT:  Src: store i8 1, ptr %idx.0, align 1 --> Dst: store i8 2, ptr %idx.1, align 1
; CHECK-NEXT:    da analyze - confused!
; CHECK-NEXT:  Src: store i8 2, ptr %idx.1, align 1 --> Dst: store i8 2, ptr %idx.1, align 1
; CHECK-NEXT:    da analyze - confused!
;
; DISABLE-CHECK-LABEL: 'f'
; DISABLE-CHECK-NEXT:  Src: store i8 1, ptr %idx.0, align 1 --> Dst: store i8 1, ptr %idx.0, align 1
; DISABLE-CHECK-NEXT:    da analyze - none!
; DISABLE-CHECK-NEXT:  Src: store i8 1, ptr %idx.0, align 1 --> Dst: store i8 2, ptr %idx.1, align 1
; DISABLE-CHECK-NEXT:    da analyze - none!
; DISABLE-CHECK-NEXT:  Src: store i8 2, ptr %idx.1, align 1 --> Dst: store i8 2, ptr %idx.1, align 1
; DISABLE-CHECK-NEXT:    da analyze - none!
;
entry:
  br label %loop.header

loop.header:
  %i = phi i64 [ 0, %entry ], [ %i.next, %loop.latch ]
  %idx.0 = getelementptr inbounds i8, ptr %A, i64 %i
  store i8 1, ptr %idx.0
  %offset.tmp = mul i64 %i, 32
  %offset = add i64 %offset.tmp, 4611686018427387904 ; 1ULL << 62
  %if.cond = icmp sge i64 %offset, 0
  br i1 %if.cond, label %if.then, label %loop.latch

if.then:
  %idx.1 = getelementptr inbounds i8, ptr %A, i64 %offset
  store i8 2, ptr %idx.1
  br label %loop.latch

loop.latch:
  %i.next = add nuw nsw i64 %i, 1
  %exit.cond = icmp eq i64 %i.next, 1152921504606846976 ; 1ULL << 60
  br i1 %exit.cond, label %exit, label %loop.header

exit:
  ret void
}
