llvm/llvm/test/Transforms/SCCP/freeze.ll

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

@g = global i64 0
declare void @use(i1)

define i1 @freeze_undef_i1() {
; CHECK-LABEL: @freeze_undef_i1(
; CHECK-NEXT:    [[FR:%.*]] = freeze i1 undef
; CHECK-NEXT:    ret i1 [[FR]]
;
  %fr = freeze i1 undef
  ret i1 %fr
}

define ptr @freeze_undef_ptr() {
; CHECK-LABEL: @freeze_undef_ptr(
; CHECK-NEXT:    [[FR:%.*]] = freeze ptr undef
; CHECK-NEXT:    ret ptr [[FR]]
;
  %fr = freeze ptr undef
  ret ptr %fr
}

define float @freeze_undef_float() {
; CHECK-LABEL: @freeze_undef_float(
; CHECK-NEXT:    [[FR:%.*]] = freeze float undef
; CHECK-NEXT:    ret float [[FR]]
;
  %fr = freeze float undef
  ret float %fr
}

define <2 x i32> @freeze_undef_vector() {
; CHECK-LABEL: @freeze_undef_vector(
; CHECK-NEXT:    [[FR:%.*]] = freeze <2 x i32> undef
; CHECK-NEXT:    ret <2 x i32> [[FR]]
;
  %fr = freeze <2 x i32> undef
  ret <2 x i32> %fr
}

define i1 @freeze_const_i1() {
; CHECK-LABEL: @freeze_const_i1(
; CHECK-NEXT:    ret i1 true
;
  %fr = freeze i1 1
  ret i1 %fr
}

define ptr @freeze_const_ptr() {
; CHECK-LABEL: @freeze_const_ptr(
; CHECK-NEXT:    ret ptr inttoptr (i32 256 to ptr)
;
  %fr = freeze ptr inttoptr (i32 256 to ptr)
  ret ptr %fr
}

define float @freeze_const_float() {
; CHECK-LABEL: @freeze_const_float(
; CHECK-NEXT:    ret float 2.500000e-01
;
  %fr = freeze float 2.500000e-01
  ret float %fr
}

define <2 x i32> @freeze_const_vector() {
; CHECK-LABEL: @freeze_const_vector(
; CHECK-NEXT:    ret <2 x i32> <i32 1, i32 2>
;
  %fr = freeze <2 x i32> <i32 1, i32 2>
  ret <2 x i32> %fr
}

; make sure we don't constant-propagate values that could potentially be poison
define i64 @maybe_poison() {
; CHECK-LABEL: @maybe_poison(
; CHECK-NEXT:    [[FR:%.*]] = freeze i64 add nuw (i64 ptrtoint (ptr @g to i64), i64 123)
; CHECK-NEXT:    ret i64 [[FR]]
;
  %fr = freeze i64 add nuw (i64 ptrtoint (ptr @g to i64), i64 123)
  ret i64 %fr
}

define {i64, i64} @freeze_struct({i64, i64} %s) {
; CHECK-LABEL: @freeze_struct(
; CHECK-NEXT:    [[FR:%.*]] = freeze { i64, i64 } [[S:%.*]]
; CHECK-NEXT:    ret { i64, i64 } [[FR]]
;
  %fr = freeze {i64, i64} %s
  ret {i64, i64} %fr
}

define i1 @propagate_range_from_and_through_freeze(i32 %x, i32 %y) {
; CHECK-LABEL: @propagate_range_from_and_through_freeze(
; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], 3
; CHECK-NEXT:    [[AND_FR:%.*]] = freeze i32 [[AND]]
; CHECK-NEXT:    [[F_1:%.*]] = icmp eq i32 [[AND_FR]], 100
; CHECK-NEXT:    call void @use(i1 [[F_1]])
; CHECK-NEXT:    [[T_1:%.*]] = icmp ule i32 [[AND_FR]], 3
; CHECK-NEXT:    call void @use(i1 [[T_1]])
; CHECK-NEXT:    [[F_2:%.*]] = icmp ugt i32 [[AND_FR]], 3
; CHECK-NEXT:    call void @use(i1 [[F_2]])
; CHECK-NEXT:    [[C_1:%.*]] = icmp eq i32 [[AND_FR]], [[Y:%.*]]
; CHECK-NEXT:    call void @use(i1 [[C_1]])
; CHECK-NEXT:    [[R_1:%.*]] = xor i1 [[T_1]], [[F_1]]
; CHECK-NEXT:    [[R_2:%.*]] = xor i1 [[R_1]], [[F_2]]
; CHECK-NEXT:    [[R_3:%.*]] = xor i1 [[R_2]], [[C_1]]
; CHECK-NEXT:    ret i1 [[R_3]]
;
  %and = and i32 %x, 3
  %and.fr = freeze i32 %and
  %f.1 = icmp eq i32 %and.fr, 100
  call void @use(i1 %f.1)
  %t.1 = icmp ule i32 %and.fr, 3
  call void @use(i1 %t.1)
  %f.2 = icmp ugt i32 %and.fr, 3
  call void @use(i1 %f.2)
  %c.1 = icmp eq i32 %and.fr, %y
  call void @use(i1 %c.1)
  %r.1 = xor i1 %t.1, %f.1
  %r.2 = xor i1 %r.1, %f.2
  %r.3 = xor i1 %r.2, %c.1
  ret i1 %r.3
}

define i1 @range_from_phi_with_undef(i1 %c.1, i1 %c.2) {
; CHECK-LABEL: @range_from_phi_with_undef(
; CHECK-NEXT:    br i1 [[C_1:%.*]], label [[TRUE_1:%.*]], label [[FALSE:%.*]]
; CHECK:       true.1:
; CHECK-NEXT:    br i1 [[C_2:%.*]], label [[TRUE_2:%.*]], label [[EXIT:%.*]]
; CHECK:       true.2:
; CHECK-NEXT:    br label [[EXIT]]
; CHECK:       false:
; CHECK-NEXT:    br label [[EXIT]]
; CHECK:       exit:
; CHECK-NEXT:    [[P:%.*]] = phi i32 [ 10, [[TRUE_1]] ], [ 20, [[TRUE_2]] ], [ undef, [[FALSE]] ]
; CHECK-NEXT:    [[P_FR:%.*]] = freeze i32 [[P]]
; CHECK-NEXT:    [[T_1:%.*]] = icmp ule i32 [[P_FR]], 20
; CHECK-NEXT:    [[T_2:%.*]] = icmp uge i32 [[P_FR]], 10
; CHECK-NEXT:    [[RES:%.*]] = xor i1 [[T_1]], [[T_2]]
; CHECK-NEXT:    ret i1 [[RES]]
;
  br i1 %c.1, label %true.1, label %false

true.1:
  br i1 %c.2, label %true.2, label %exit

true.2:
  br label %exit

false:
  br label %exit

exit:
  %p = phi i32 [ 10, %true.1 ], [ 20, %true.2], [ undef, %false ]
  %p.fr = freeze i32 %p
  %t.1 = icmp ule i32 %p.fr, 20
  %t.2 = icmp uge i32 %p.fr, 10
  %res = xor i1 %t.1, %t.2
  ret i1 %res
}

define i32 @propagate_info_from_predicate_through_freeze(i32 %x) {
; CHECK-LABEL: @propagate_info_from_predicate_through_freeze(
; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 10
; CHECK-NEXT:    [[X_FR:%.*]] = freeze i32 [[X]]
; CHECK-NEXT:    br i1 [[CMP]], label [[THEN:%.*]], label [[ELSE:%.*]]
; CHECK:       then:
; CHECK-NEXT:    [[ADD_1:%.*]] = add i32 [[X_FR]], 10
; CHECK-NEXT:    [[ADD_2:%.*]] = add i32 [[X_FR]], 1
; CHECK-NEXT:    ret i32 [[ADD_2]]
; CHECK:       else:
; CHECK-NEXT:    [[ADD_3:%.*]] = add i32 [[X_FR]], 1
; CHECK-NEXT:    ret i32 [[ADD_3]]
;
  %cmp = icmp eq i32 %x, 10
  %x.fr = freeze i32 %x
  br i1 %cmp, label %then, label %else

then:
  %add.1 = add i32 %x.fr, %x
  %add.2 = add i32 %x.fr, 1
  ret i32 %add.2

else:
  %add.3 = add i32 %x.fr, 1
  ret i32 %add.3
}