llvm/llvm/test/Transforms/CorrelatedValuePropagation/abs.ll

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

declare void @llvm.assume(i1)
declare i32 @llvm.abs.i32(i32, i1)
declare i8 @llvm.abs.i8(i8, i1)
declare i1 @llvm.abs.i1(i1, i1)

; If we don't know anything about the argument, we can't do anything.

define i8 @test0(i8 %x) {
; CHECK-LABEL: @test0(
; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X:%.*]], i1 false)
; CHECK-NEXT:    ret i8 [[R]]
;
  %r = call i8 @llvm.abs.i8(i8 %x, i1 0)
  ret i8 %r
}
define i8 @test1(i8 %x) {
; CHECK-LABEL: @test1(
; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X:%.*]], i1 true)
; CHECK-NEXT:    ret i8 [[R]]
;
  %r = call i8 @llvm.abs.i8(i8 %x, i1 1)
  ret i8 %r
}

; But if we know that the argument is always positive, we can bypass @llvm.abs.

define i8 @test2(i8 %x) {
; CHECK-LABEL: @test2(
; CHECK-NEXT:    [[LIM:%.*]] = icmp sge i8 [[X:%.*]], -1
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 true)
; CHECK-NEXT:    ret i8 [[R]]
;

  %lim = icmp sge i8 %x, -1
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.abs.i8(i8 %x, i1 0)
  ret i8 %r
}
define i8 @test3(i8 %x) {
; CHECK-LABEL: @test3(
; CHECK-NEXT:    [[LIM:%.*]] = icmp sge i8 [[X:%.*]], -1
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 true)
; CHECK-NEXT:    ret i8 [[R]]
;

  %lim = icmp sge i8 %x, -1
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.abs.i8(i8 %x, i1 1)
  ret i8 %r
}

define i8 @test4(i8 %x) {
; CHECK-LABEL: @test4(
; CHECK-NEXT:    [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 0
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    ret i8 [[X]]
;

  %lim = icmp sge i8 %x, 0
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.abs.i8(i8 %x, i1 0)
  ret i8 %r
}
define i8 @test5(i8 %x) {
; CHECK-LABEL: @test5(
; CHECK-NEXT:    [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 0
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    ret i8 [[X]]
;

  %lim = icmp sge i8 %x, 0
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.abs.i8(i8 %x, i1 1)
  ret i8 %r
}

define i8 @test6(i8 %x) {
; CHECK-LABEL: @test6(
; CHECK-NEXT:    [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 1
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    ret i8 [[X]]
;

  %lim = icmp sge i8 %x, 1
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.abs.i8(i8 %x, i1 0)
  ret i8 %r
}
define i8 @test7(i8 %x) {
; CHECK-LABEL: @test7(
; CHECK-NEXT:    [[LIM:%.*]] = icmp sge i8 [[X:%.*]], 1
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    ret i8 [[X]]
;

  %lim = icmp sge i8 %x, 1
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.abs.i8(i8 %x, i1 1)
  ret i8 %r
}

; Likewise, INT_MIN is fine for otherwise-positive value.

define i8 @test8(i8 %x) {
; CHECK-LABEL: @test8(
; CHECK-NEXT:    [[LIM:%.*]] = icmp ule i8 [[X:%.*]], 127
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    ret i8 [[X]]
;

  %lim = icmp ule i8 %x, 127
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.abs.i8(i8 %x, i1 0)
  ret i8 %r
}
define i8 @test9(i8 %x) {
; CHECK-LABEL: @test9(
; CHECK-NEXT:    [[LIM:%.*]] = icmp ule i8 [[X:%.*]], 127
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    ret i8 [[X]]
;

  %lim = icmp ule i8 %x, 127
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.abs.i8(i8 %x, i1 1)
  ret i8 %r
}

define i8 @test10(i8 %x) {
; CHECK-LABEL: @test10(
; CHECK-NEXT:    [[LIM:%.*]] = icmp ule i8 [[X:%.*]], -128
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    ret i8 [[X]]
;

  %lim = icmp ule i8 %x, 128
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.abs.i8(i8 %x, i1 0)
  ret i8 %r
}
define i8 @test11(i8 %x) {
; CHECK-LABEL: @test11(
; CHECK-NEXT:    [[LIM:%.*]] = icmp ule i8 [[X:%.*]], -128
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    ret i8 [[X]]
;

  %lim = icmp ule i8 %x, 128
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.abs.i8(i8 %x, i1 1)
  ret i8 %r
}

define i8 @test12(i8 %x) {
; CHECK-LABEL: @test12(
; CHECK-NEXT:    [[LIM:%.*]] = icmp ule i8 [[X:%.*]], -127
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 false)
; CHECK-NEXT:    ret i8 [[R]]
;

  %lim = icmp ule i8 %x, 129
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.abs.i8(i8 %x, i1 0)
  ret i8 %r
}
define i8 @test13(i8 %x) {
; CHECK-LABEL: @test13(
; CHECK-NEXT:    [[LIM:%.*]] = icmp ule i8 [[X:%.*]], -127
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 true)
; CHECK-NEXT:    ret i8 [[R]]
;

  %lim = icmp ule i8 %x, 129
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.abs.i8(i8 %x, i1 1)
  ret i8 %r
}

; Likewise, if we know that argument is always negative,
; we can expand @llvm.abs into a direct negation.
; For negative arguments, we must be careful to include 0 though.

define i8 @test14(i8 %x) {
; CHECK-LABEL: @test14(
; CHECK-NEXT:    [[LIM:%.*]] = icmp sle i8 [[X:%.*]], -1
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R1:%.*]] = sub i8 0, [[X]]
; CHECK-NEXT:    ret i8 [[R1]]
;

  %lim = icmp sle i8 %x, -1
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.abs.i8(i8 %x, i1 0)
  ret i8 %r
}
define i8 @test15(i8 %x) {
; CHECK-LABEL: @test15(
; CHECK-NEXT:    [[LIM:%.*]] = icmp sle i8 [[X:%.*]], -1
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R1:%.*]] = sub nsw i8 0, [[X]]
; CHECK-NEXT:    ret i8 [[R1]]
;

  %lim = icmp sle i8 %x, -1
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.abs.i8(i8 %x, i1 1)
  ret i8 %r
}

define i8 @test16(i8 %x) {
; CHECK-LABEL: @test16(
; CHECK-NEXT:    [[LIM:%.*]] = icmp sle i8 [[X:%.*]], 0
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R1:%.*]] = sub i8 0, [[X]]
; CHECK-NEXT:    ret i8 [[R1]]
;

  %lim = icmp sle i8 %x, 0
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.abs.i8(i8 %x, i1 0)
  ret i8 %r
}
define i8 @test17(i8 %x) {
; CHECK-LABEL: @test17(
; CHECK-NEXT:    [[LIM:%.*]] = icmp sle i8 [[X:%.*]], 0
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R1:%.*]] = sub nsw i8 0, [[X]]
; CHECK-NEXT:    ret i8 [[R1]]
;

  %lim = icmp sle i8 %x, 0
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.abs.i8(i8 %x, i1 1)
  ret i8 %r
}

define i8 @test18(i8 %x) {
; CHECK-LABEL: @test18(
; CHECK-NEXT:    [[LIM:%.*]] = icmp sle i8 [[X:%.*]], 1
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 false)
; CHECK-NEXT:    ret i8 [[R]]
;

  %lim = icmp sle i8 %x, 1
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.abs.i8(i8 %x, i1 0)
  ret i8 %r
}
define i8 @test19(i8 %x) {
; CHECK-LABEL: @test19(
; CHECK-NEXT:    [[LIM:%.*]] = icmp sle i8 [[X:%.*]], 1
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 true)
; CHECK-NEXT:    ret i8 [[R]]
;

  %lim = icmp sle i8 %x, 1
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.abs.i8(i8 %x, i1 1)
  ret i8 %r
}

; And again, INT_MIN is also fine for otherwise-negative range.

define i8 @test20(i8 %x) {
; CHECK-LABEL: @test20(
; CHECK-NEXT:    [[LIM:%.*]] = icmp uge i8 [[X:%.*]], 127
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 false)
; CHECK-NEXT:    ret i8 [[R]]
;

  %lim = icmp uge i8 %x, 127
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.abs.i8(i8 %x, i1 0)
  ret i8 %r
}
define i8 @test21(i8 %x) {
; CHECK-LABEL: @test21(
; CHECK-NEXT:    [[LIM:%.*]] = icmp uge i8 [[X:%.*]], 127
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 true)
; CHECK-NEXT:    ret i8 [[R]]
;

  %lim = icmp uge i8 %x, 127
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.abs.i8(i8 %x, i1 1)
  ret i8 %r
}

define i8 @test22(i8 %x) {
; CHECK-LABEL: @test22(
; CHECK-NEXT:    [[LIM:%.*]] = icmp uge i8 [[X:%.*]], -128
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R1:%.*]] = sub i8 0, [[X]]
; CHECK-NEXT:    ret i8 [[R1]]
;

  %lim = icmp uge i8 %x, 128
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.abs.i8(i8 %x, i1 0)
  ret i8 %r
}
define i8 @test23(i8 %x) {
; CHECK-LABEL: @test23(
; CHECK-NEXT:    [[LIM:%.*]] = icmp uge i8 [[X:%.*]], -128
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R1:%.*]] = sub nsw i8 0, [[X]]
; CHECK-NEXT:    ret i8 [[R1]]
;

  %lim = icmp uge i8 %x, 128
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.abs.i8(i8 %x, i1 1)
  ret i8 %r
}

define i8 @test24(i8 %x) {
; CHECK-LABEL: @test24(
; CHECK-NEXT:    [[LIM:%.*]] = icmp uge i8 [[X:%.*]], -127
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R1:%.*]] = sub nsw i8 0, [[X]]
; CHECK-NEXT:    ret i8 [[R1]]
;

  %lim = icmp uge i8 %x, 129
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.abs.i8(i8 %x, i1 0)
  ret i8 %r
}
define i8 @test25(i8 %x) {
; CHECK-LABEL: @test25(
; CHECK-NEXT:    [[LIM:%.*]] = icmp uge i8 [[X:%.*]], -127
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R1:%.*]] = sub nsw i8 0, [[X]]
; CHECK-NEXT:    ret i8 [[R1]]
;

  %lim = icmp uge i8 %x, 129
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.abs.i8(i8 %x, i1 1)
  ret i8 %r
}

; If all else fails, we can sometimes at least inferr NSW.

define i8 @test26(i8 %x) {
; CHECK-LABEL: @test26(
; CHECK-NEXT:    [[LIM:%.*]] = icmp ne i8 [[X:%.*]], -128
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 true)
; CHECK-NEXT:    ret i8 [[R]]
;
  %lim = icmp ne i8 %x, 128
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.abs.i8(i8 %x, i1 0)
  ret i8 %r
}
define i8 @test27(i8 %x) {
; CHECK-LABEL: @test27(
; CHECK-NEXT:    [[LIM:%.*]] = icmp ne i8 [[X:%.*]], -128
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    [[R:%.*]] = call i8 @llvm.abs.i8(i8 [[X]], i1 true)
; CHECK-NEXT:    ret i8 [[R]]
;
  %lim = icmp ne i8 %x, 128
  call void @llvm.assume(i1 %lim)
  %r = call i8 @llvm.abs.i8(i8 %x, i1 1)
  ret i8 %r
}

define i1 @pr59887(i1 %x, i1 %c) {
; CHECK-LABEL: @pr59887(
; CHECK-NEXT:    [[RES:%.*]] = select i1 [[C:%.*]], i1 [[X:%.*]], i1 false
; CHECK-NEXT:    ret i1 [[RES]]
;
  %abs = call i1 @llvm.abs.i1(i1 %x, i1 false)
  %res = select i1 %c, i1 %abs, i1 false
  ret i1 %res
}

; Because of `undef`, We can't delete `abs`.
; We can't replace the `abs` argument with true either.
define i32 @pr68381_undef_abs_false(i1 %c0, i1 %c1, i8 %v1) {
; CHECK-LABEL: @pr68381_undef_abs_false(
; CHECK-NEXT:  start:
; CHECK-NEXT:    br i1 [[C0:%.*]], label [[BB0:%.*]], label [[BB1:%.*]]
; CHECK:       bb0:
; CHECK-NEXT:    [[V1_I32:%.*]] = zext i8 [[V1:%.*]] to i32
; CHECK-NEXT:    br label [[BB1]]
; CHECK:       bb1:
; CHECK-NEXT:    [[X:%.*]] = phi i32 [ [[V1_I32]], [[BB0]] ], [ undef, [[START:%.*]] ]
; CHECK-NEXT:    br i1 [[C1:%.*]], label [[BB0]], label [[BB2:%.*]]
; CHECK:       bb2:
; CHECK-NEXT:    [[Z:%.*]] = call i32 @llvm.abs.i32(i32 [[X]], i1 false)
; CHECK-NEXT:    ret i32 [[Z]]
;
start:
  br i1 %c0, label %bb0, label %bb1

bb0:
  %v1_i32 = zext i8 %v1 to i32
  br label %bb1

bb1:
  %x = phi i32 [ %v1_i32, %bb0 ], [ undef, %start ]
  br i1 %c1, label %bb0, label %bb2

bb2:
  %z = call i32 @llvm.abs.i32(i32 %x, i1 false)
  ret i32 %z
}

; Because of `and`, we can delete `abs`.
define i32 @pr68381_undef_abs_false_and(i1 %c0, i1 %c1, i8 %v1) {
; CHECK-LABEL: @pr68381_undef_abs_false_and(
; CHECK-NEXT:  start:
; CHECK-NEXT:    br i1 [[C0:%.*]], label [[BB0:%.*]], label [[BB1:%.*]]
; CHECK:       bb0:
; CHECK-NEXT:    [[V1_I32:%.*]] = zext i8 [[V1:%.*]] to i32
; CHECK-NEXT:    br label [[BB1]]
; CHECK:       bb1:
; CHECK-NEXT:    [[X:%.*]] = phi i32 [ [[V1_I32]], [[BB0]] ], [ undef, [[START:%.*]] ]
; CHECK-NEXT:    br i1 [[C1:%.*]], label [[BB0]], label [[BB2:%.*]]
; CHECK:       bb2:
; CHECK-NEXT:    [[Y:%.*]] = and i32 [[X]], 255
; CHECK-NEXT:    ret i32 [[Y]]
;
start:
  br i1 %c0, label %bb0, label %bb1

bb0:
  %v1_i32 = zext i8 %v1 to i32
  br label %bb1

bb1:
  %x = phi i32 [ %v1_i32, %bb0 ], [ undef, %start ]
  br i1 %c1, label %bb0, label %bb2

bb2:
  %y = and i32 %x, 255
  %z = call i32 @llvm.abs.i32(i32 %y, i1 false)
  ret i32 %z
}

; Because of `undef`, we can't replace `abs` with `sub`.
define i32 @pr68381_undef_abs_false_sub(i1 %c0, i1 %c1, i32 %v1, i32 %v2) {
; CHECK-LABEL: @pr68381_undef_abs_false_sub(
; CHECK-NEXT:  start:
; CHECK-NEXT:    br i1 [[C0:%.*]], label [[BB0:%.*]], label [[BB1:%.*]]
; CHECK:       bb0:
; CHECK-NEXT:    [[V3:%.*]] = add i32 [[V1:%.*]], [[V2:%.*]]
; CHECK-NEXT:    [[LIM:%.*]] = icmp sle i32 [[V3]], -1
; CHECK-NEXT:    call void @llvm.assume(i1 [[LIM]])
; CHECK-NEXT:    br label [[BB1]]
; CHECK:       bb1:
; CHECK-NEXT:    [[X:%.*]] = phi i32 [ [[V3]], [[BB0]] ], [ undef, [[START:%.*]] ]
; CHECK-NEXT:    br i1 [[C1:%.*]], label [[BB0]], label [[BB2:%.*]]
; CHECK:       bb2:
; CHECK-NEXT:    [[Z:%.*]] = call i32 @llvm.abs.i32(i32 [[X]], i1 false)
; CHECK-NEXT:    ret i32 [[Z]]
;
start:
  br i1 %c0, label %bb0, label %bb1

bb0:
  %v3 = add i32 %v1, %v2
  %lim = icmp sle i32 %v3, -1
  call void @llvm.assume(i1 %lim)
  br label %bb1

bb1:
  %x = phi i32 [ %v3, %bb0 ], [ undef, %start ]
  br i1 %c1, label %bb0, label %bb2

bb2:
  %z = call i32 @llvm.abs.i32(i32 %x, i1 false)
  ret i32 %z
}

; We can delete `abs`.
define i32 @pr68381_undef_abs_true(i1 %c0, i1 %c1, i8 %v1) {
; CHECK-LABEL: @pr68381_undef_abs_true(
; CHECK-NEXT:  start:
; CHECK-NEXT:    br i1 [[C0:%.*]], label [[BB0:%.*]], label [[BB1:%.*]]
; CHECK:       bb0:
; CHECK-NEXT:    [[V1_I32:%.*]] = zext i8 [[V1:%.*]] to i32
; CHECK-NEXT:    br label [[BB1]]
; CHECK:       bb1:
; CHECK-NEXT:    [[X:%.*]] = phi i32 [ [[V1_I32]], [[BB0]] ], [ undef, [[START:%.*]] ]
; CHECK-NEXT:    br i1 [[C1:%.*]], label [[BB0]], label [[BB2:%.*]]
; CHECK:       bb2:
; CHECK-NEXT:    ret i32 [[X]]
;
start:
  br i1 %c0, label %bb0, label %bb1

bb0:
  %v1_i32 = zext i8 %v1 to i32
  br label %bb1

bb1:
  %x = phi i32 [ %v1_i32, %bb0 ], [ undef, %start ]
  br i1 %c1, label %bb0, label %bb2

bb2:
  %z = call i32 @llvm.abs.i32(i32 %x, i1 true)
  ret i32 %z
}