; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt < %s -passes=correlated-propagation -S | FileCheck %s


define i1 @infer_nuw(i8 range(i8 0, 2) %A, i8 range(i8 0, 2) %B) {
; CHECK-LABEL: define i1 @infer_nuw(
; CHECK-SAME: i8 range(i8 0, 2) [[A:%.*]], i8 range(i8 0, 2) [[B:%.*]]) {
; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[B]], [[A]]
; CHECK-NEXT:    [[TRUNC:%.*]] = trunc nuw i8 [[XOR]] to i1
; CHECK-NEXT:    ret i1 [[TRUNC]]
;
  %xor = xor i8 %B, %A
  %trunc = trunc i8 %xor to i1
  ret i1 %trunc
}


define i4 @infer_nsw(i8 %A) {
; CHECK-LABEL: define range(i4 -4, 4) i4 @infer_nsw(
; CHECK-SAME: i8 [[A:%.*]]) {
; CHECK-NEXT:    [[ASHR:%.*]] = ashr i8 [[A]], 5
; CHECK-NEXT:    [[B:%.*]] = trunc nsw i8 [[ASHR]] to i4
; CHECK-NEXT:    ret i4 [[B]]
;
  %ashr = ashr i8 %A, 5
  %result = trunc i8 %ashr to i4
  ret i4 %result
}


define i8 @infer_nuw_nsw(i16 range(i16 -5, -3) %A, i16 range(i16 -5, -3) %B) {
; CHECK-LABEL: define range(i8 0, 8) i8 @infer_nuw_nsw(
; CHECK-SAME: i16 range(i16 -5, -3) [[A:%.*]], i16 range(i16 -5, -3) [[B:%.*]]) {
; CHECK-NEXT:    [[XOR:%.*]] = xor i16 [[B]], [[A]]
; CHECK-NEXT:    [[TRUNC:%.*]] = trunc nuw nsw i16 [[XOR]] to i8
; CHECK-NEXT:    ret i8 [[TRUNC]]
;
  %xor = xor i16 %B, %A
  %trunc = trunc i16 %xor to i8
  ret i8 %trunc
}


define i8 @infer_nsw_from_assume(i16 %x) {
; CHECK-LABEL: define i8 @infer_nsw_from_assume(
; CHECK-SAME: i16 [[X:%.*]]) {
; CHECK-NEXT:    [[ADD:%.*]] = add i16 [[X]], 128
; CHECK-NEXT:    [[OR_COND_I:%.*]] = icmp ult i16 [[ADD]], 256
; CHECK-NEXT:    tail call void @llvm.assume(i1 [[OR_COND_I]])
; CHECK-NEXT:    [[CONV1:%.*]] = trunc nsw i16 [[X]] to i8
; CHECK-NEXT:    ret i8 [[CONV1]]
;
  %add = add i16 %x, 128
  %or.cond.i = icmp ult i16 %add, 256
  tail call void @llvm.assume(i1 %or.cond.i)
  %conv1 = trunc i16 %x to i8
  ret i8 %conv1
}


define i1 @rust_issue_122734(i8 range(i8 0, 3) %A, i8 range(i8 0, 3) %B) {
; CHECK-LABEL: define i1 @rust_issue_122734(
; CHECK-SAME: i8 range(i8 0, 3) [[A:%.*]], i8 range(i8 0, 3) [[B:%.*]]) {
; CHECK-NEXT:  [[START:.*]]:
; CHECK-NEXT:    [[LHS:%.*]] = icmp eq i8 [[A]], 2
; CHECK-NEXT:    [[RHS:%.*]] = icmp eq i8 [[B]], 2
; CHECK-NEXT:    [[OR:%.*]] = or i1 [[LHS]], [[RHS]]
; CHECK-NEXT:    [[AND:%.*]] = and i1 [[LHS]], [[RHS]]
; CHECK-NEXT:    br i1 [[OR]], label %[[IFTRUE:.*]], label %[[IFFALSE:.*]]
; CHECK:       [[IFTRUE]]:
; CHECK-NEXT:    [[PHI:%.*]] = phi i1 [ [[XOR2:%.*]], %[[IFFALSE]] ], [ [[AND]], %[[START]] ]
; CHECK-NEXT:    ret i1 [[PHI]]
; CHECK:       [[IFFALSE]]:
; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[A]], [[B]]
; CHECK-NEXT:    [[TRUNC:%.*]] = trunc nuw i8 [[XOR]] to i1
; CHECK-NEXT:    [[XOR2]] = xor i1 [[TRUNC]], true
; CHECK-NEXT:    br label %[[IFTRUE]]
;
start:
  %lhs = icmp eq i8 %A, 2
  %rhs = icmp eq i8 %B, 2
  %or = or i1 %lhs, %rhs
  %and = and i1 %lhs, %rhs
  br i1 %or, label %iftrue, label %iffalse

iftrue:
  %phi = phi i1 [ %xor2, %iffalse], [ %and, %start ]
  ret i1 %phi

iffalse:
  %xor = xor i8 %A, %B
  %trunc = trunc i8 %xor to i1
  %xor2 = xor i1 %trunc, true
  br label %iftrue
}


define i1 @overdefined_range_negative(i8 %A, i8 %B) {
; CHECK-LABEL: define i1 @overdefined_range_negative(
; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[A]], [[B]]
; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[XOR]] to i1
; CHECK-NEXT:    ret i1 [[TRUNC]]
;
  %xor = xor i8 %A, %B
  %trunc = trunc i8 %xor to i1
  ret i1 %trunc
}
